Referrals endpoints claim an install for a referral link, list and read credited referrals, resend their webhook events, and delete a referral.
Referrals endpoints record which invitation link brought an install, and give you the report behind the dashboard's Referrals view. Read Referrals for the full path from link to reward. The MCP server has the same operations as claim_referral, list_referrals, get_referral, resend_referral_webhook and delete_referral.
Authentication and Permissions
Reading needs an API key with the referrals:read scope. Claiming, resending and deleting need referrals:write, which includes referrals:read. Resending also needs a key whose creator is an owner or admin.
POST /v1/referrals/claims is the one referral route an SDK key can call. It needs the attribution:write scope an SDK key carries, and it is limited to 60 requests a minute per key per client IP address. Every other referral route refuses an SDK key with 403 SDK_KEY_ROUTE_FORBIDDEN.
Claim a Referral
POST/referrals/claims
Claim a referral
Credits an installer's install to the referral link that brought it. Send it from your backend with an API key that has the referrals:write scope, or from the SDK with an SDK key that has attribution:write. The first valid claim for an app and installer id is recorded as claimed. A later claim for the same installer is ignored and points at the first through duplicate_of. A claim made after the credit window closed is recorded as flagged with the outside_window flag. An exact match (a token, an install referrer, a device id or a link open) replaces an earlier estimate for the same installer: the referral keeps its id, moves to the exact link, and a referral.updated webhook event follows. An estimate is accepted only for an iPhone install when the app has handoff off and probabilistic matching on. A link_open match counts only when the app credits existing users. An install from an ordinary link, or a tap before the link became a referral link, gives none. Every outcome is a 200 with a status of claimed, flagged, ignored or none; none records nothing. Send the same Idempotency-Key to repeat a call safely.
Parameters
Name
Type
In
Description
Idempotency-Key
string
header
A unique string of 1 to 255 printable ASCII characters for this create. Sending the same request again with the same key returns the first response, with the header `Idempotent-Replayed: true`, and creates nothing new. A key is remembered for 24 hours for your organization, this API key and this endpoint. The same key with a different body is refused with `422 IDEMPOTENCY_KEY_REUSED`. The same key while the first request still runs is refused with `409 IDEMPOTENCY_IN_PROGRESS`. A `5xx` or `429` response is not remembered, so a retry runs again. A replay of a response larger than 64 KB answers `409 IDEMPOTENCY_RESULT_TOO_LARGE`: read the resource with the get call.
Request Body
Field
Type
Description
installer_id*
string
Your own id for the person who installed. It is stored exactly as written. The first valid claim for an app and installer id wins.
app_id
string
The app. Optional for an SDK key tied to one app. Otherwise send app_id, app_bundle_id or app_package_name when the organization has more than one app.
app_bundle_id
string
The iOS bundle id, an alternative to app_id.
app_package_name
string
The Android package name, an alternative to app_id.
platform
"ios" | "android"
The platform of the install.
install_id
string
The install record from POST /attribution/match, when the install was matched by the SDK.
recovery_token
string
The referral token the invitation carried. A token alone is enough. An expired one is refused with RECOVERY_TOKEN_EXPIRED, a malformed one or one of another app with RECOVERY_TOKEN_INVALID. A genuine one issued in the last few minutes whose invitation has not arrived yet is answered 503 RECOVERY_TOKEN_PENDING with Retry-After: retry the same claim. When install_id is also sent, a refused or pending token falls back to the install.
link_id
string
An explicit referral link. A link that is not a referral link is refused with 409 LINK_NOT_REFERRAL and nothing is recorded.
Responses
200The result of the claim
Field
Type
Description
status*
"claimed" | "flagged" | "ignored" | "none"
claimed and flagged are recorded. ignored is a later claim for an installer that already holds a credit. none means no referral link brought this install, and nothing is recorded.
referral_id*
string | null
Null for none. For ignored, the id of the duplicate that was recorded.
link*
oneOf
match*
oneOf
flags*
"outside_window"[]
duplicate_of*
string | null
For ignored, the referral that holds the credit.
updated*
boolean
True when this call replaced an earlier estimate with an exact match.
replay_state*
string | null
replayed when the token or device was already used by an earlier install.
400VALIDATION_ERROR for a body that does not fit, RECOVERY_TOKEN_INVALID for a malformed token or one of another app, or RECOVERY_TOKEN_EXPIRED for a token past its expiry or whose invitation is gone. A genuine token issued moments ago whose invitation has not arrived yet is a 503 RECOVERY_TOKEN_PENDING instead.
Field
Type
Description
error*
object
401Unauthorized. The key is missing or invalid.
Field
Type
Description
error*
object
403Forbidden. An API key needs the referrals:write scope and an SDK key needs attribution:write. KEY_APP_MISMATCH when an SDK key tied to one app names another app.
Field
Type
Description
error*
object
409LINK_NOT_REFERRAL when link_id is an ordinary link, or IDEMPOTENCY_IN_PROGRESS when a call with the same Idempotency-Key still runs.
Field
Type
Description
error*
object
422IDEMPOTENCY_KEY_REUSED. The same Idempotency-Key was sent with a different body.
Field
Type
Description
error*
object
429Rate limit exceeded
Field
Type
Description
error*
object
503Service temporarily unavailable, or RECOVERY_TOKEN_PENDING for a genuine token issued moments ago whose invitation has not arrived yet. Retry after the delay in the Retry-After header
Field
Type
Description
error*
object
Send installer_id, your own id for the new user, with one piece of evidence: an install_id from the SDK's attribution result, a recovery_token, or a link_id. The first valid claim for an app and installer id wins. Every outcome is a 200 with a status of claimed, flagged, ignored or none, and none records nothing. Send an Idempotency-Key to repeat a call safely.
An exact claim from an installer that holds an estimate upgrades the referral and returns updated: true. A link_id for a link that is not a referral link answers 409 LINK_NOT_REFERRAL. A 503 RECOVERY_TOKEN_PENDING carries a Retry-After header: send the same claim again after that many seconds.
Lists the organization's referrals, newest claim first. Each one is a credit that an invitation link earned for an install. Needs an API key with the referrals:read scope. SDK keys are refused with 403 SDK_KEY_ROUTE_FORBIDDEN. Page with pagination.next_cursor and send the same filters with it. A parameter this endpoint does not accept, or one repeated, is a 400 VALIDATION_ERROR. With format=csv the response is one CSV file of at most 10,000 rows (newest first) and a cursor is refused; X-Result-Truncated says whether the list was cut. The status filter uses the report status: duplicate and flagged are a referral's own state, and every other referral shows failed, retrying, delivered or claimed from its latest webhook delivery.
Parameters
Name
Type
In
Description
installer_id
string
query
Only referrals for this installer id, matched exactly as it was written.
Omit to read every app. A UUID reads one app. The literal "none" reads only referrals with no app.
from
string
query
Start of the window on claimed_at, inclusive, as an ISO instant with an offset.
to
string
query
End of the window on claimed_at, exclusive, as an ISO instant with an offset.
cursor
string
query
The pagination.next_cursor of the previous page. Not allowed with format=csv.
limit
integer
query
Referrals per page.
format
"json" | "csv"
query
csv downloads one file with the columns referral_id, status, installer_id, app_id, link_id, link_url, platform, match_method, match_exact, confidence, flags, claimed_via, tapped_at, installed_at, claimed_at and duplicate_of.
Responses
200One page of referrals, or the CSV file when format=csv
Field
Type
Description
data*
object[]
pagination*
object
400VALIDATION_ERROR for an unknown, repeated or malformed parameter, or CURSOR_INVALID when the cursor does not fit this list.
Field
Type
Description
error*
object
401Unauthorized. The key is missing or invalid.
Field
Type
Description
error*
object
403Forbidden. The key needs the referrals:read scope, and an SDK key is refused with SDK_KEY_ROUTE_FORBIDDEN.
Field
Type
Description
error*
object
429Rate limit exceeded
Field
Type
Description
error*
object
503Service temporarily unavailable. Retry after the delay in the Retry-After header
Field
Type
Description
error*
object
Referrals come newest claim first. status is claimed, delivered, retrying, failed, flagged or duplicate: flagged and duplicate are the referral's own state, and the rest follow its latest webhook delivery. match.exact and evidence_class say how sure the match is. Page with pagination.next_cursor and send the same filters with it. format=csv returns one file of up to 10,000 rows and refuses a cursor.
Get a Referral
GET/referrals/{id}
Get a referral
Returns one referral with its claims, its webhook events with the payloads sent, and every delivery attempt. When an exact claim replaced an estimate, both claims and both events are listed. Needs an API key with the referrals:read scope. SDK keys are refused with 403 SDK_KEY_ROUTE_FORBIDDEN.
Parameters
Name
Type
In
Description
id*
string
path
The referral id: ref_ followed by 32 hex characters, as the API returns it. A plain UUID is also accepted.
Responses
200The referral400INVALID_ID when the id in the path is not a referral id.
Field
Type
Description
error*
object
401Unauthorized. The key is missing or invalid.
Field
Type
Description
error*
object
403Forbidden. The key needs the referrals:read scope.
Field
Type
Description
error*
object
404The referral does not exist in this organization
Field
Type
Description
error*
object
429Rate limit exceeded
Field
Type
Description
error*
object
503Service temporarily unavailable. Retry after the delay in the Retry-After header
Field
Type
Description
error*
object
The response adds the referral's claims, its webhook events with the payloads we sent, and every delivery attempt.
Resend a Referral's Events
POST/referrals/{id}/resend
Resend a referral's webhook events
Sends the newest webhook event of each endpoint again, with the same event id and payload, so a receiver can drop a repeat by id. Add endpoint_id to resend to one endpoint only. An event still being delivered, or finished more than 7 days ago, is listed in skipped. When nothing could be sent, the first refusal is returned: 409 CONFLICT for an event in flight or a referral with no events, 410 GONE for an event past the resend window. Needs the referrals:write scope, and the key's creator must be an owner or admin. Takes no body.
Parameters
Name
Type
In
Description
id*
string
path
The referral id: ref_ followed by 32 hex characters, as the API returns it. A plain UUID is also accepted.
endpoint_id
string
query
Resend only to this webhook endpoint.
Responses
202The events that were queued again and the ones that were skipped
Field
Type
Description
resent*
object[]
skipped*
object[]
400INVALID_ID when the id in the path is not a referral id, or VALIDATION_ERROR when endpoint_id is not a UUID.
Field
Type
Description
error*
object
401Unauthorized. The key is missing or invalid.
Field
Type
Description
error*
object
403Forbidden. The key needs the referrals:write scope, and its creator must be an owner or admin.
Field
Type
Description
error*
object
404The referral does not exist in this organization
Field
Type
Description
error*
object
409CONFLICT. Every event is still being delivered, or the referral has no webhook events.
Field
Type
Description
error*
object
410GONE. Every event finished more than 7 days ago.
Field
Type
Description
error*
object
429Rate limit exceeded
Field
Type
Description
error*
object
503Service temporarily unavailable. Retry after the delay in the Retry-After header
Field
Type
Description
error*
object
Each endpoint receives its newest event again with the same event id, so a receiver can drop the repeat. Add endpoint_id to resend to one endpoint. An event still in flight, or finished more than 7 days ago, comes back in skipped.
Delete a Referral
DELETE/referrals/{id}
Delete a referral
Erases the referral with its claims, webhook events and delivery attempts. This cannot be undone. Ignored duplicates of the referral (the referrals that point to it as their duplicate_of) are erased with it. Needs an API key with the referrals:write scope.
Parameters
Name
Type
In
Description
id*
string
path
The referral id: ref_ followed by 32 hex characters, as the API returns it. A plain UUID is also accepted.
Responses
204The referral is erased400INVALID_ID when the id in the path is not a referral id.
Field
Type
Description
error*
object
401Unauthorized. The key is missing or invalid.
Field
Type
Description
error*
object
403Forbidden. The key needs the referrals:write scope.
Field
Type
Description
error*
object
404The referral does not exist in this organization
Field
Type
Description
error*
object
429Rate limit exceeded
Field
Type
Description
error*
object
503Service temporarily unavailable. Retry after the delay in the Retry-After header
Field
Type
Description
error*
object
Deleting erases the referral with its claims, webhook events and delivery attempts. It cannot be undone.