Skip to content
API referenceAttribution

API reference · App API

Attribution

Ask whether a code or click your app caught can be attributed, before the user signs up, and get the attribution key that carries the referral from then on.

Ask whether a referral can be attributed

POST/v1/attributions

Ask as soon as your app has caught something: the link it was opened with (url), your deep-link SDK’s referring params as they are (params), the Play install referrer, or a typed code. It works before sign-up, so you can show “Invited by …” on the sign-up screen.

A yes carries an attributionKey. Keep it, and once you know the user is new, confirm with user.registered carrying the key and the new appUserId: that binds the key and attributes the user. A user who is not new never gets the key sent; it expires unused, or you can decline it.

Send an installId and asking again from the same install answers with the same key. Without one, every yes is a new key, unless appUserId names a user who already has one for this code.

AuthSigned request with an app key, fg_live_… or fg_test_…

Request body

codestring≤ 100 chars

fg_ref, the code in a /a/<code> link, or a code the user typed into your own referral field that you want checked against Flow Affiliate. Case and surrounding spaces do not matter.

clickIdstringuuid

fg_click from the link, Branch params or the Play install referrer. Used when there is no code, or the code is not one of yours.

urlstring≤ 2000 chars

The link the app was opened with, as it arrived. fg_ref and fg_click are read from it, and the code of a Flow Affiliate link (/a/<code> on its tracking host). Your app’s own referral links are ignored.

paramsobject

The referring params your deep-link SDK hands you (Branch, AppsFlyer, Adjust), forwarded as they are. Only Flow Affiliate’s own data is read: fg_ref and fg_click from its own keys, and from any value that is a link carrying them or a Flow Affiliate link, such as ~referring_link. Keys of your own referral scheme, such as code, are never read. Branch’s +match_guaranteed sets confidence. Nothing else in it is kept.

installIdstring≤ 200 chars

Your own random id for this install. Asking again with the same id answers with the key it already has, instead of making a new one.

sourcestringdefault other

How the code reached the app. Worked out from what you send when left out: branch for Branch params, link for a link or click id, code_entry for a code alone. app_clip for a click handed over by your App Clip, install_match for a click that POST /v1/installs/match matched the install to (always recorded with confidence: probable). Any other value is recorded as other, never refused.

One of link branch play_referrer code_entry app_clip install_match other

platformstring

The platform the app runs on. Any other value is ignored.

One of ios android

confidencestring

How sure your link provider is of the match, e.g. deterministic for Branch +match_guaranteed. Recorded, never decides anything.

One of deterministic probable

appUserIdstring≤ 200 chars

Only when the user already has an account: the key is then bound to them at once. Before sign-up, leave it out.

Returns · 200 · one of

Option 1

attributablebooleanrequired
attributionKeystringrequired

Keep it with the install or the sign-up form. Send it on user.registered if you decide the user is new.

statusstringrequired

pending: waiting for user.registered. registered: a registration arrived for the key’s user. declined: you closed it. expired: the window closed before the key was registered.

One of pending registered declined expired

partnerobjectrequired
Child attributes
displayNamestringrequired

Who referred the user, as they are shown.

programobjectrequired
Child attributes
idstringrequireduuid
namestringrequired
inviteeBonusobjectrequirednullable

The welcome gift the link carries for the invited user. Null when it carries none.

Child attributes
amountintegerrequired

Minor units.

currencystringrequired
qualifyingEventsarray of stringsrequired

Event types the user must complete; the bonus follows the first.

withinDaysintegerrequirednullable
expiresAtstringrequireddate-time

The user must register before this to get it.

expiresAtstringrequireddate-time

A key not registered by then is no longer accepted: the program’s attribution window.

Option 2

attributablebooleanrequired
reasonstringrequired
  • no_affiliate: nothing you sent names a code or a click, e.g. the params of an install that came from no link.
  • unknown_code: no code like this belongs to your app.
  • unknown_click: no code was sent, and the click id is not a click on one of your links.
  • code_inactive: the code was switched off or has expired, or its referrer can no longer be paid.
  • program_closed: the program the code belongs to is not running.
  • already_attributed: the appUserId you sent is already attributed.

One of no_affiliate unknown_code unknown_click code_inactive program_closed already_attributed

Errors

400validation_error

The request does not match the schema. details says which fields failed and why.

401missing_signature

One of x-fg-key, x-fg-timestamp and x-fg-signature is missing.

401invalid_timestamp

x-fg-timestamp is not Unix time in seconds.

401stale_timestamp

x-fg-timestamp is more than 300 seconds from the server clock. Sign each attempt again, and keep your clock in sync.

401invalid_key

The key id is unknown or revoked, or the app is archived.

401invalid_signature

The signature does not match. Sign the exact bytes you send.

429too_many_attempts

Too many requests with this key in the last minute. Wait Retry-After seconds.

Request
BODY='{"params":{"+clicked_branch_link":true,"+match_guaranteed":false,"fg_ref":"k7qxa2mp","fg_click":"1d4f9c5e-7a8b-4c2d-9e1f-0a1b2c3d4e5f","~referring_link":"https://example.app.link/AbC123"},"installId":"5b1d0c9e-2f4a-4b8c-9d7e-6f5a4b3c2d1e","platform":"ios"}'
TS=$(date +%s)
SIG=$(printf '%s.%s' "$TS" "$BODY" | openssl dgst -sha256 -hmac "$FG_SECRET" | sed 's/^.*= //')

curl -X POST "https://api.flowgroup.se/v1/attributions" \
  -H "content-type: application/json" \
  -H "x-fg-key: $FG_KEY_ID" \
  -H "x-fg-timestamp: $TS" \
  -H "x-fg-signature: $SIG" \
  --data-raw "$BODY"
200 OK
{
  "attributable": true,
  "attributionKey": "fga_k7qxa2mpw4ht9bvc3rnd8ezj",
  "status": "pending",
  "partner": {
    "displayName": "Anna Berg"
  },
  "program": {
    "id": "0c9e6f3a-1b2d-4c5e-8f7a-9b0c1d2e3f4a",
    "name": "Invite friends"
  },
  "inviteeBonus": null,
  "expiresAt": "2026-12-09T09:30:00Z"
}

Get an attribution key

GET/v1/attributions/{key}

What became of a key: who it belongs to, whether it was registered or declined, and the conversion it made.

AuthSigned request with an app key, fg_live_… or fg_test_…

Path parameters

keystringrequired≤ 100 chars

The attributionKey, fga_….

Returns · 200

attributionKeystringrequired
statusstringrequired

pending: waiting for user.registered. registered: a registration arrived for the key’s user. declined: you closed it. expired: the window closed before the key was registered.

One of pending registered declined expired

partnerobjectrequired
Child attributes
displayNamestringrequired

Who referred the user, as they are shown.

programobjectrequired
Child attributes
idstringrequireduuid
namestringrequired
appUserIdstringrequirednullable

The user the key is bound to; null until it is registered.

createdAtstringrequireddate-time
expiresAtstringrequireddate-time
declineReasonstringrequirednullable

Why you declined it; null unless status is declined.

One of existing_user duplicate suspected_fraud other

conversionobjectrequirednullable

The conversion this key made, once the registration has been processed. Null when there is none, or the user was attributed to another referral.

Child attributes
statusstringrequired

One of qualification_pending qualified rejected reversed

Errors

400validation_error

The request does not match the schema. details says which fields failed and why.

401missing_signature

One of x-fg-key, x-fg-timestamp and x-fg-signature is missing.

401invalid_timestamp

x-fg-timestamp is not Unix time in seconds.

401stale_timestamp

x-fg-timestamp is more than 300 seconds from the server clock. Sign each attempt again, and keep your clock in sync.

401invalid_key

The key id is unknown or revoked, or the app is archived.

401invalid_signature

The signature does not match. Sign the exact bytes you send.

404not_found

No key like this belongs to your app in this environment.

429too_many_attempts

Too many requests with this key in the last minute. Wait Retry-After seconds.

Request
TS=$(date +%s)
SIG=$(printf '%s.' "$TS" | openssl dgst -sha256 -hmac "$FG_SECRET" | sed 's/^.*= //')

curl "https://api.flowgroup.se/v1/attributions/key" \
  -H "x-fg-key: $FG_KEY_ID" \
  -H "x-fg-timestamp: $TS" \
  -H "x-fg-signature: $SIG"
200 OK
{
  "attributionKey": "fga_k7qxa2mpw4ht9bvc3rnd8ezj",
  "status": "registered",
  "partner": {
    "displayName": "Anna Berg"
  },
  "program": {
    "id": "0c9e6f3a-1b2d-4c5e-8f7a-9b0c1d2e3f4a",
    "name": "Invite friends"
  },
  "appUserId": "u_8F2K",
  "createdAt": "2026-11-09T09:28:00Z",
  "expiresAt": "2026-12-09T09:28:00Z",
  "declineReason": null,
  "conversion": {
    "status": "qualification_pending"
  }
}

Decline an attribution key

POST/v1/attributions/{key}/decline

Optional. When you have decided the user behind a key is not new, you can simply never send the key. Declining it says why: the key is closed at once, and the publisher sees your reason instead of a key that expired without a word.

A declined key is refused on every event (key_declined). Declining again changes nothing. A key already registered cannot be declined: undo what it earned with a reversal.

AuthSigned request with an app key, fg_live_… or fg_test_…

Path parameters

keystringrequired≤ 100 chars

The attributionKey, fga_….

Request body

reasonstringrequired

existing_user: they already had an account. duplicate: the same person or device signed up before. suspected_fraud: you will not accept this sign-up. other: anything else.

One of existing_user duplicate suspected_fraud other

notestring≤ 500 chars

For our records, never shown to the publisher. Nothing that identifies the person.

Returns · 200

attributionKeystringrequired
statusstringrequired

pending: waiting for user.registered. registered: a registration arrived for the key’s user. declined: you closed it. expired: the window closed before the key was registered.

One of pending registered declined expired

partnerobjectrequired
Child attributes
displayNamestringrequired

Who referred the user, as they are shown.

programobjectrequired
Child attributes
idstringrequireduuid
namestringrequired
appUserIdstringrequirednullable

The user the key is bound to; null until it is registered.

createdAtstringrequireddate-time
expiresAtstringrequireddate-time
declineReasonstringrequirednullable

Why you declined it; null unless status is declined.

One of existing_user duplicate suspected_fraud other

conversionobjectrequirednullable

The conversion this key made, once the registration has been processed. Null when there is none, or the user was attributed to another referral.

Child attributes
statusstringrequired

One of qualification_pending qualified rejected reversed

Errors

400validation_error

The request does not match the schema. details says which fields failed and why.

401missing_signature

One of x-fg-key, x-fg-timestamp and x-fg-signature is missing.

401invalid_timestamp

x-fg-timestamp is not Unix time in seconds.

401stale_timestamp

x-fg-timestamp is more than 300 seconds from the server clock. Sign each attempt again, and keep your clock in sync.

401invalid_key

The key id is unknown or revoked, or the app is archived.

401invalid_signature

The signature does not match. Sign the exact bytes you send.

404not_found

No key like this belongs to your app in this environment.

409key_registered

The key was already registered.

429too_many_attempts

Too many requests with this key in the last minute. Wait Retry-After seconds.

Request
BODY='{"reason":"existing_user"}'
TS=$(date +%s)
SIG=$(printf '%s.%s' "$TS" "$BODY" | openssl dgst -sha256 -hmac "$FG_SECRET" | sed 's/^.*= //')

curl -X POST "https://api.flowgroup.se/v1/attributions/key/decline" \
  -H "content-type: application/json" \
  -H "x-fg-key: $FG_KEY_ID" \
  -H "x-fg-timestamp: $TS" \
  -H "x-fg-signature: $SIG" \
  --data-raw "$BODY"
200 OK
{
  "attributionKey": "fga_k7qxa2mpw4ht9bvc3rnd8ezj",
  "status": "registered",
  "partner": {
    "displayName": "Anna Berg"
  },
  "program": {
    "id": "0c9e6f3a-1b2d-4c5e-8f7a-9b0c1d2e3f4a",
    "name": "Invite friends"
  },
  "appUserId": "u_8F2K",
  "createdAt": "2026-11-09T09:28:00Z",
  "expiresAt": "2026-12-09T09:28:00Z",
  "declineReason": null,
  "conversion": {
    "status": "qualification_pending"
  }
}