Submit analytics events
Submit 1 to 100 analytics events in one request. The API handles each batch as a single unit and never partially accepts a batch. A 202 Accepted response means every event passed validation and received a durable queue acknowledgement; accepted therefore matches the number of submitted events. A 422 Unprocessable Entity response means the entire batch was rejected before publication. Its message identifies the invalid value using an events[index].field path so you can correct and resubmit the batch.
version tells downstream systems which event structure they are receiving. For example, version 1 uses verse_number, while version 2 uses verse_key. Keep the same version when adding optional properties; increase it for incompatible structure changes.
Delivery is at least once. If the API returns 503 Service Unavailable, retry the batch with the same event IDs. A failed request may have published some events before the failure, and stable event IDs allow downstream processing to identify duplicates.
Do not include client_id, app_id, or environment identity in the request body. The API associates events with the authenticated client ID. When an event belongs to a signed-in Quran Foundation user, set user_id to the QF user ID associated with that user's Quran Foundation OAuth identity. Omit it for guests or unknown users, and do not send an application-local user ID. See the request schema for property and identifier limits.
Request Body required
A batch containing between 1 and 100 analytics events.
- Array [
- ]
events object[] required
Possible values: >= 1, <= 100
Events to accept as one batch. Send between 1 and 100 events.
Possible values: <= 128 characters
An optional identifier that links this event to a specific user action or interaction.
Possible values: <= 128 characters
An application-generated identifier for a person who is not signed in. Omit or send null
when the event is not associated with an anonymous visitor.
Possible values: non-empty and <= 128 characters
A stable identifier generated by the caller for this event.
Reuse the same value when retrying an event. Together with the authenticated client ID, this identifies duplicates during downstream processing.
Possible values: non-empty and <= 128 characters
A namespaced event name containing letters, numbers, ., _, :, or -.
When the event happened, as an RFC 3339 timestamp.
The timestamp cannot be more than 5 minutes in the future or more than 366 days old.
Event-specific JSON data.
The object may contain at most 50 keys across all nesting levels, may be nested up to 6 levels, may contain strings up to 4,096 characters, and must serialize to at most 16 KiB. Do not include credentials, access tokens, or other secrets.
Possible values: <= 128 characters
An application-generated identifier that groups events from one usage session. Omit or send
null when no session is available.
Possible values: non-empty and <= 128 characters
Optional Quran Foundation user ID for the signed-in person associated with this event.
Include this field only when your application has identified the person through Quran
Foundation OAuth, and use the QF user ID associated with that identity. Omit it or send
null for guests or unknown users. Do not send an application-local user ID.
Possible values: >= 1
Tells downstream systems which structure this event uses. This is not the Analytics API
version or your application version. Start at 1. For example, version 1 uses
verse_number, while version 2 uses verse_key. Keep the same version when adding an
optional property; increase it when renaming, removing, or changing the type of a property.
- 202
- 400
- 401
- 403
- 422
- 429
- 500
- 503
The complete batch was validated and durably accepted for asynchronous processing.
Schema
Number of events accepted from the request. Because batches are never partially accepted,
this always matches the number of submitted events in a 202 Accepted response.
Server-generated identifier shared by all events in this request.
{
"accepted": 1,
"batch_id": "d77a3c27-8365-4c57-a3ae-cf8ab8cb62c2"
}
Three events accepted
{
"accepted": 3,
"batch_id": "b47ee72b-20ed-4da8-bf45-b292ff25c973"
}
One event accepted
{
"accepted": 1,
"batch_id": "d77a3c27-8365-4c57-a3ae-cf8ab8cb62c2"
}
The API Gateway rejected a malformed request, such as one missing required authentication headers.
Schema
Human-readable explanation of why the Gateway rejected the request.
Always false for an error response.
Stable machine-readable error category.
{
"message": "The server understood the request, but refuses to authorize it",
"success": false,
"type": "forbidden"
}
{
"message": "The request is missing required headers or is invalid",
"success": false,
"type": "invalid_request"
}
The access token is missing, expired, or invalid.
Schema
Human-readable explanation of why the Gateway rejected the request.
Always false for an error response.
Stable machine-readable error category.
{
"message": "The server understood the request, but refuses to authorize it",
"success": false,
"type": "forbidden"
}
{
"message": "The request requires authentication",
"success": false,
"type": "unauthorized"
}
The authenticated OAuth client is not allowed to submit analytics events. Request the analytics.events.write scope for this client.
Schema
Human-readable explanation of why the Gateway rejected the request.
Always false for an error response.
Stable machine-readable error category.
{
"message": "The server understood the request, but refuses to authorize it",
"success": false,
"type": "forbidden"
}
{
"message": "The access token does not include analytics.events.write",
"success": false,
"type": "insufficient_scope"
}
The entire batch was rejected before publication because it failed validation. The message identifies an invalid event field using an events[index].field path. Correct the reported field and resubmit the complete batch.
Schema
Human-readable explanation of why the request failed.
Whether the caller may retry the same request without changing it.
Always false for an error response.
{
"message": "validation failed: events must contain between 1 and 100 items",
"retryable": false,
"success": false
}
{
"message": "validation failed: events[1].occurred_at is too far in the future",
"retryable": false,
"success": false
}
The OAuth client exceeded the API Gateway rate limit. Retry after the delay indicated by the Gateway response headers.
Schema
Human-readable explanation of why the Gateway rejected the request.
Always false for an error response.
Stable machine-readable error category.
{
"message": "The server understood the request, but refuses to authorize it",
"success": false,
"type": "forbidden"
}
{
"message": "Too many requests, please try again later",
"success": false,
"type": "rate_limit_exceeded"
}
The collector encountered an unexpected internal error. Contact Quran Foundation support if the problem persists.
Schema
Human-readable explanation of why the request failed.
Whether the caller may retry the same request without changing it.
Always false for an error response.
{
"message": "validation failed: events must contain between 1 and 100 items",
"retryable": false,
"success": false
}
{
"message": "internal error",
"retryable": false,
"success": false
}
The durable event queue is temporarily unavailable. Retry the request with the same event IDs; duplicates are possible and are identified downstream by client ID and event ID.
Schema
Human-readable explanation of why the request failed.
Whether the caller may retry the same request without changing it.
Always false for an error response.
{
"message": "validation failed: events must contain between 1 and 100 items",
"retryable": false,
"success": false
}
{
"message": "event ingestion temporarily unavailable",
"retryable": true,
"success": false
}