Send first-party events
Use the SpendDaddy API when your backend sends subscription and attribution events directly instead of using RevenueCat.
Before you start
Choose SpendDaddy API while adding your app, then copy the generated API key into a server-side secret store.
Never embed this key in a mobile app or other downloadable client. Anyone with the key can send events for the connected app.
All requests use:
Authorization: Bearer <spenddaddy_api_key>
Content-Type: application/json
The base URL is https://api.spenddaddy.app.
Identify an install
Call POST https://api.spenddaddy.app/identify when your backend first sees an app user. Send the same stable user ID you will use for later events.
curl https://api.spenddaddy.app/identify \
--request POST \
--header "Authorization: Bearer $SPENDDADDY_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"appUserId": "user_123",
"installedAt": "2026-07-17T12:34:56Z",
"asaToken": "optional_apple_ads_attribution_token"
}'
| Field | Required | Description |
|---|---|---|
appUserId | Yes | Stable identifier for this app user. |
installedAt | No | Install time in ISO 8601 format. Defaults to the time SpendDaddy first sees the user. |
asaToken | No | Apple Ads attribution token obtained by your app and forwarded to your backend. |
Example response:
{
"status": "identified",
"created": true,
"attribution": "fetched"
}
created is true when SpendDaddy created the app user. attribution is fetched, failed, or not_requested depending on whether an Apple Ads token was supplied and resolved.
Send an event
Call POST https://api.spenddaddy.app/event for trials, purchases, renewals, refunds, and cancellations.
curl https://api.spenddaddy.app/event \
--request POST \
--header "Authorization: Bearer $SPENDDADDY_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"appUserId": "user_123",
"eventType": "initial_purchase",
"occurredAt": "2026-07-17T12:40:00Z",
"eventId": "evt_01",
"transactionId": "txn_01",
"productId": "monthly_pro",
"amount": 9.99,
"currency": "USD",
"store": "app_store",
"country": "US"
}'
Event fields
| Field | Required | Description |
|---|---|---|
appUserId | Yes | The same stable user ID used with /identify. |
eventType | Yes | One of the supported event types below. |
occurredAt | Yes | Event time in ISO 8601 format. |
eventId | Recommended | Unique event identifier used to safely update a previously received event. |
transactionId | Recommended for purchases | Store transaction identifier. |
renewalNumber | No | Renewal sequence number when available. |
productId | No | Subscription or product identifier. |
amount | Required for revenue events | Positive revenue amount. Send refunds as a positive amount; SpendDaddy applies the negative sign. |
currency | Recommended for revenue events | Three-letter currency code. Defaults to USD when omitted. |
store | No | Store that processed the event, such as app_store. |
country | No | Two-letter country code when available. |
Supported event types
| Event type | Requires amount |
|---|---|
trial_started | No |
trial_converted | Yes |
initial_purchase | Yes |
non_renewing_purchase | Yes |
renewal | Yes |
refund | Yes |
cancellation | No |
Example response:
{
"status": "ingested",
"created": false
}
Here, created indicates whether SpendDaddy created the app user while processing the event. It does not indicate whether the event was new.
Retries and duplicate events
Provide a stable eventId or transactionId whenever possible. If a request times out, retry it with the same identifiers and payload so SpendDaddy can recognize the existing event.
Errors
| Status | Meaning | What to do |
|---|---|---|
400 | Unsupported event type, missing revenue amount, or invalid amount. | Correct the request body and retry. |
401 | Missing, invalid, disabled, or rotated API key. | Confirm the bearer token or rotate the key in SpendDaddy Settings. |
422 | A required field is missing or has an invalid format. | Compare the request with the field tables above. |
Rotate the API key
Open the app in SpendDaddy, go to Settings > First-party attribution API, and choose Rotate API key.
Rotation invalidates the previous key immediately. Update the server-side secret used by every event sender before sending more requests.