Singular Event Delivery Reference
Event Endpoint V1 and V2 delivery behavior, request examples, and RevenueCat source mapping
Use this page when you need RevenueCat-specific details about Singular's Event Endpoint V1 and V2 delivery paths. For setup steps, see Singular.
Singular exposes two server-to-server Event API versions. RevenueCat picks the version for each event: V2 when the customer has a $singularDeviceId, V1 otherwise. Singular accounts created on or after July 15, 2026 only accept V2.
| Event API version | When RevenueCat uses it | Required identifiers |
|---|---|---|
| V2 | The customer has an SDID. The only version Singular accepts from accounts created on or after July 15, 2026. | $singularDeviceId customer attribute, sent as sdid. |
| V1 (legacy) | The customer has no SDID. Singular accepts it only from accounts created before July 15, 2026. | iOS uses $idfa and $idfv. Android uses $gpsAdId and/or $androidId. |
Example Event Endpoint V2 request
RevenueCat sends V2 events as an application/x-www-form-urlencoded POST. The example below is shown as JSON for readability.
{
"headers": {
"Content-Type": "application/x-www-form-urlencoded"
},
"body": {
"a": "<singular_sdk_key>",
"n": "<event_name>",
"sdid": "<singular_device_id>",
"p": "iOS",
"i": "<bundle_id_or_package_name>",
"amt": <usd_revenue>,
"cur": "USD",
"umilisec": <event_timestamp_ms>,
"purchase_product_id": "<product_id>",
"purchase_transaction_id": "<transaction_id>",
"partner": "revenuecat",
"att_authorization_status": <att_authorization_status>,
"e": "{\"rc_app_user_id\":\"<app_user_id>\",\"pn\":\"\",\"pq\":<quantity>,\"pp\":<usd_revenue>,\"pk\":\"<product_id>\"}"
}
}
V2 events require sdid. RevenueCat reads SDID from the $singularDeviceId customer attribute that your app sets with setSingularDeviceID(). RevenueCat doesn't derive SDID from collectDeviceIdentifiers().
Example Event Endpoint V1 request
RevenueCat sends V1 events as a GET request with query parameters. The example below is shown as JSON for readability.
{
"params": {
"a": "<singular_sdk_key>",
"n": "<event_name>",
"p": "iOS",
"i": "<bundle_id_or_package_name>",
"idfa": "<idfa>",
"idfv": "<idfv>",
"amt": <usd_revenue>,
"cur": "USD",
"umilisec": <event_timestamp_ms>,
"purchase_product_id": "<product_id>",
"purchase_transaction_id": "<transaction_id>",
"partner": "revenuecat",
"att_authorization_status": <att_authorization_status>,
"e": "{\"rc_app_user_id\":\"<app_user_id>\",\"pn\":\"\",\"pq\":<quantity>,\"pp\":<usd_revenue>,\"pk\":\"<product_id>\"}"
}
}
On Android, RevenueCat sends aifa and/or andi instead of idfa and idfv. RevenueCat omits identifier parameters that aren't available on the customer.
RevenueCat source to Singular request mapping
The table below covers fields shared by both versions unless noted.
| Singular request element | RevenueCat source and behavior |
|---|---|
| Endpoint | Sends POST requests to https://s2s.singular.net/api/v2/evt when the customer has an SDID, or GET requests to https://s2s.singular.net/api/v1/evt otherwise. |
a | Uses the production or sandbox Singular SDK key configured in RevenueCat, based on the event environment. |
n | Uses the event name configured in RevenueCat for the matching lifecycle event. |
sdid (V2 only) | Sends the $singularDeviceId customer attribute. Customers without an SDID are sent to V1 instead. |
idfa, idfv (V1 iOS) | Sends available iOS device identifiers collected through RevenueCat customer attributes. Both are required for standard iOS V1 delivery unless a project-specific exception applies. |
aifa, andi (V1 Android) | Sends Google's Advertising ID and/or Android ID from RevenueCat customer attributes. At least one Android identifier is required for V1 Android delivery. |
p | Sends iOS or Android based on the purchase platform. Amazon purchases report as Android. |
i | Sends the app bundle ID or package name for the purchase. |
amt, cur | Sends USD revenue according to the integration's Sales Reporting mode and sends USD as the currency. |
umilisec | Sends the RevenueCat event timestamp in milliseconds. When Report early renewals is enabled, early renewals can use the occurrence time instead of the due time. |
purchase_product_id, purchase_transaction_id | Sends RevenueCat product and transaction identifiers when available. |
ip or country | Sends the device IP when available; otherwise sends the subscriber's last-seen country for geo resolution. |
custom_user_id | Sends the RevenueCat app user ID when it isn't an anonymous RevenueCat ID. |
att_authorization_status | Sends the customer's ATT consent status on iOS events. |
data_sharing_options | Sends the customer's Limit Data Sharing consent as a URL-encoded JSON object ({"limit_data_sharing":true} or {"limit_data_sharing":false}) when the $limitDataSharing customer attribute is set. Omitted when the attribute is unset. |
e | Sends a JSON string of custom attributes, including RevenueCat context such as rc_app_user_id, product metadata for purchase events, and optional hashed user data when enabled for the project. Individual attribute keys and values longer than 500 characters are dropped. |
partner | Sends revenuecat. |
Provider responses
Singular's EVENT endpoint answers with a JSON body whose status says whether it accepted the event. A rejection can still come back as HTTP 200, and invalid api version: v1 comes back as HTTP 400, so inspect the body to determine the outcome:
{ "status": "ok" }
{ "status": "error", "reason": "<error_reason>" }
RevenueCat counts a request as delivered only when status is ok. A rejected request shows as failed in Customer History with Singular's reason. RevenueCat doesn't retry a rejection whose reason names a missing or invalid parameter, since Singular gives the same answer every time.
The table below lists reason values that commonly appear when RevenueCat sends Singular events. See Attribution troubleshooting for setup fixes when you see these in Customer History.
reason | Meaning in RevenueCat integrations |
|---|---|
invalid api version: v1 | The Singular account only accepts Event Endpoint V2, but the customer had no $singularDeviceId, so RevenueCat sent the event to V1. Make sure your app calls setSingularDeviceID(). |
missing argument: n | The configured event name for this lifecycle event is empty in RevenueCat. |
missing argument: a | The production or sandbox SDK key for the event environment is missing in RevenueCat. |
no device ID supplied | A V1 request was sent without the platform device identifiers Singular requires for that store. |
platform: iOS should have an idfv param | A V1 iOS request is missing $idfv, or RevenueCat omitted it from the payload. |
platform: Android should have an {identifier} param | A V1 Android request is missing $gpsAdId and/or $androidId, or RevenueCat omitted them from the payload. |
For the full Singular error catalog, see Singular's Server-to-Server API response codes and errors.