---
trigger: model_decision
description: "RefRef referral tracking: landing script, signup call at account creation, server-only API key. Use when you add or change signup, referral, or invite code."
---

# RefRef referral tracking

This app uses RefRef (https://refref.ai) for its referral program. Follow these rules when you add or change referral code.

## Configuration

- Server-only secrets: `REFREF_API_KEY` (a Workspace API key), `REFREF_PROJECT_ID`, and `REFREF_PROGRAM_ID`.
- `REFREF_API_URL` defaults to `https://api.refref.ai`, and `REFREF_ASSETS_URL` to `https://assets.refref.ai`. Read both from configuration, so that a Sandbox or local environment can change them.
- Never put `REFREF_API_KEY` in browser code, in a public variable (`NEXT_PUBLIC_*`, `VITE_*`), in a prompt, in a log, or in a commit.
- Every RefRef call is a backend `POST` with a JSON body that contains `projectId`, and the header `X-Api-Key`. The current schemas are at `GET $REFREF_API_URL/openapi`.

## 1. Capture the referral click (browser)

Add the landing script to every page where a referral link can land:

```html
<script src="$REFREF_ASSETS_URL/attribution.v1.js" data-api-url="$REFREF_API_URL" defer></script>
```

- The script stores the browser's referral handle in the first-party cookie `refref_handle`. Never create, change, or delete this cookie, and never make it `HttpOnly`.
- Before a signup form submits, wait for capture with a time limit:
  `await Promise.race([window.RefRefAttribution?.capture(), new Promise((resolve) => setTimeout(resolve, 3000))]);`
- Do not add a capture endpoint to this app. Do not keep referral state in `localStorage`.

## 2. Send the signup (backend, once, at account creation)

In the backend code that creates the account, send:

```json
POST $REFREF_API_URL/v1/track/events
{
  "projectId": "$REFREF_PROJECT_ID",
  "type": "signup",
  "participant": { "kind": "individual", "externalId": "<the new user's ID>" },
  "identify": { "handle": "<value of the refref_handle cookie>" }
}
```

- Leave out `identify` when the request has no `refref_handle` cookie. Never invent a handle.
- `externalId` is the app's stable user ID, never an email address. For company accounts, use `{ "kind": "group", "externalId": "<account ID>" }` and add the creator as `"actor": { "kind": "individual", "externalId": "<user ID>" }`.
- Sign-in, session refresh, email verification, account linking, and joining a team never send a signup.
- If the account is confirmed later (an email link or code), keep the handle with the new account, for example in its user metadata, and send the signup at confirmation with `"occurredAt"` set to the account's creation time.
- A RefRef failure must never fail the signup. Log it and retry later with the same body. A repeated signup returns the first result.

## 3. Show the sharing link (optional)

- From the backend, for the signed-in user only: enroll with `POST /v1/enrollments` and get the code with `POST /v1/referral-codes`. Both take `{ projectId, programId, participant }`. The link is `https://r.refref.ai/<code>`.
- Show three states: not enrolled, ready (the link and a Copy button), and failed (with a retry). Never show a placeholder link, a made-up count, or made-up earnings.

## 4. Purchases

- Prefer a billing integration (Stripe, Paddle, Polar, Dodo Payments, or RevenueCat) connected in the RefRef Console.
- Otherwise send `"type": "purchase"` only from verified billing webhooks on the backend, never from the browser.

## RefRef MCP (configuration only)

- If the `refref` MCP server is connected, use it to read Workspaces, Projects, and Programs, and to prepare configuration proposals. A person approves each proposal in the RefRef Console.
- MCP never sends signups or purchases. Runtime tracking is application code.

## Tests to write

- A signup with a `refref_handle` cookie sends one signup with `identify.handle`.
- A signup without the cookie sends a signup without `identify`.
- A sign-in sends no signup.
- A RefRef failure does not fail the signup.
- No browser response or bundle contains the API key.

## Do not

- Match referrals or people by email.
- Call RefRef from the browser with a key, or expose the key to the browser.
- Report a Reward as paid. An earned Reward is an accounting result; delivery is a separate step.

Docs: https://refref.ai/docs/platform/installation/attribution-script and https://refref.ai/docs/platform/installation/auth
