Get started
Quickstart
Get your first attributed registration in about five minutes: a sandbox key, one click on a tracking link, an ask and a signed event. Nothing here creates real money.
You need a terminal with curl and openssl, or Node 18 or later. Everything below runs in the sandbox: the events you send are processed exactly like production traffic, but nothing they create is ever settled, paid or shown to partners.
Keys are issued per app, one pair per environment. In the Flow Affiliate dashboard, open Programs, pick your app's program and go to Tracking → Keys. Choose Create key, with Sandbox as the environment.
You get a key id that starts with
fg_test_and a secret. The secret is shown once: store it in your secret manager before you close the dialog. If it is lost, revoke the key and create a new one.export FG_KEY_ID=fg_test_... # the key id export FG_SECRET=... # the secret, shown onceTake any active tracking link of a program on your app, the kind a partner shares:
https://go.affiliate.yflow.io/a/<code>. Open it the way a visitor would, and look at where it sends you:curl -s -o /dev/null -w '%{redirect_url}\n' https://go.affiliate.yflow.io/a/k7qxa2mp # https://your-site.example/?fg_click=6f0e2c1a-8d3b-4f5e-9a7c-1b2d3e4f5a6b&fg_ref=k7qxa2mpThe redirect carries two parameters:
fg_click, the id of the click that was just recorded, andfg_ref, the partner's code. In a real integration your app catches this link (or your deep-link SDK's params) when it opens and hands it to your backend.export FG_URL='https://your-site.example/?fg_click=6f0e2c1a-8d3b-4f5e-9a7c-1b2d3e4f5a6b&fg_ref=k7qxa2mp'Your backend asks whether what the app caught can be attributed. Requests are signed:
x-fg-signatureis the hex HMAC-SHA256 of<timestamp>.<raw body>under your secret, and the timestamp must be within 300 seconds of our clock. This helper signs a body and sends it:fg() { # fg POST /v1/attributions '<json>' local ts sig ts=$(date +%s) sig=$(printf '%s.%s' "$ts" "$3" | openssl dgst -sha256 -hmac "$FG_SECRET" | sed 's/^.*= //') curl -s -X "$1" "https://api.flowgroup.se$2" -H "content-type: application/json" \ -H "x-fg-key: $FG_KEY_ID" -H "x-fg-timestamp: $ts" -H "x-fg-signature: $sig" --data-raw "$3" }fg POST /v1/attributions "{\"url\":\"$FG_URL\",\"installId\":\"install-1\"}" # {"attributable":true,"attributionKey":"fga_k7qxa2mpw4ht9bvc3rnd8ezj","status":"pending", # "partner":{"displayName":"Anna Berg"},"program":{…},"inviteeBonus":null,"expiresAt":"…"} export FG_ATTRIBUTION_KEY=fga_k7qxa2mpw4ht9bvc3rnd8ezjimport { createFlowGrowth } from '@flow/growth-sdk'; const fg = createFlowGrowth({ baseUrl: 'https://api.flowgroup.se', keyId: process.env.FG_KEY_ID!, // fg_test_… secret: process.env.FG_SECRET!, }); // the link the app was opened with, as it arrived; Branch or AppsFlyer params go in `params` const ask = await fg.createAttribution({ url: openedWith, installId }); if (ask.ok && ask.data.attributable) console.log(ask.data.attributionKey, ask.data.partner.displayName); else console.log(ask.error ?? ask.data); // { attributable: false, reason: 'unknown_code' }, …The answer comes at once, before anyone has signed up: the partner's name to show ("Invited by Anna Berg") and an
attributionKeyto keep with the install. A no is an answer too, with areasonsuch asunknown_code.- Confirm
Confirm the registration
Once you know the user is new, send
user.registeredwith the key and your id for the user. This is the event that attributes them.fg POST /v1/events "$(printf '{"eventId":"registered:u_1042","type":"user.registered","occurredAt":"%s","appUserId":"u_1042","attributionKey":"%s"}' \ "$(date -u +%Y-%m-%dT%H:%M:%SZ)" "$FG_ATTRIBUTION_KEY")"const res = await fg.track({ type: 'user.registered', eventId: `registered:${user.id}`, // stable: a retry is recognised as a duplicate appUserId: user.id, attributionKey: ask.data.attributionKey, }); if (res.ok) console.log(res.data); // { eventId: 'registered:u_1042', status: 'accepted' } else console.error(res.error.code, res.error.message);A
202 Acceptedmeans the event is stored and queued for processing:{ "accepted": [{ "eventId": "registered:u_1042", "status": "accepted" }] }Send the same request again and the status is
duplicate: Flow Affiliate deduplicates on youreventId, so retrying is always safe. An event whose key can't be used comes backrejected, with areasonsuch askey_bound_to_other_user. Back in your program, Tracking → Events lists the last events Flow Affiliate received from the app, live, with what the engine did with each one:
- Processed: the registration was attributed. A sandbox conversion now exists for
u_1042, credited to the partner behind the link. - Ignored, with a reason: nothing was attributed.
no_touchmeans nothing the event carried matched a tracking link;outside_windowmeans the click or key is older than the program's attribution window.
Each step of the integration checklist beside the events ticks itself off from what actually arrived, not from a box you tick.
- Processed: the registration was attributed. A sandbox conversion now exists for
Next steps
You have an attributed user in the sandbox. To see money move, send the event one of the program's rules pays on with the same key (for example a purchase.completed with an amount), and a sandbox commission or reward appears.
- Integrating an app? Follow Attribution for apps: ask, confirm, then report what the user does.
- Read Concepts for how attribution windows, conversions, commissions and rewards fit together.
- See Events for every field, the standard event types, batching and reversals.
- Crediting users in your app? Set up the reward webhook.
- When the sandbox checklist is green, create an
fg_live_key and switch it in your production config.