Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions content/docs/api-reference/errors.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: Errors & Troubleshooting
description: All API error codes, their causes, and how to fix common integration problems.
kind: reference
last_updated: 2026-10-16
last_updated: 2026-10-17
---

> **Beta** — The Affitor SDKs and CLI are in active development. The documented happy-path works; edge cases may change. Report issues on GitHub.
Expand Down Expand Up @@ -193,7 +193,7 @@ The JSON body also gains a `warnings` array. No existing field is removed or ren

This body is the [typed envelope](#the-typed-envelope): no `data` key, and an `error.code` to branch on.

**Fix:** In your Affitor dashboard, go to **Settings** → **API keys** and regenerate the key, then update `AFFITOR_API_KEY` on your server with the new value. See [Rotate your API key](/docs/brand/settings#step-3-regenerate-the-key) for the full walkthrough.
**Fix:** In your Affitor dashboard, open the program menu and choose **Program settings**. Under **Developers** → **API keys**, regenerate the key, then update `AFFITOR_API_KEY` on your server with the new value. See [Rotate your API key](/docs/brand/settings#step-3-regenerate-the-key) for the full walkthrough.

---

Expand Down Expand Up @@ -437,7 +437,7 @@ An expired session is not an error on `/auth/poll`: it answers `200` with `"data
|----------|--------|---------------|---------|-----|
| both | `401` | `Missing or malformed Authorization header. Expected: Bearer <api_token>` | The `Authorization` header is missing or does not start with `Bearer ` | Send `Authorization: Bearer YOUR_PROGRAM_API_KEY` |
| both | `401` | `Missing API token` | The token is empty after `Bearer ` | Check for an empty env variable |
| both | `401` | `Invalid API key. To get a working key for the program you already have, ask a workspace owner of that program to open Affitor → Settings → API Key and click Regenerate, then replace the key you are sending with the new one.` | The key matches no program | Do as the message says. Running `affitor init` does not help: it creates a second program |
| both | `401` | `Invalid API key. To get a working key for the program you already have, ask a workspace owner of that program to open Affitor → Settings → API Key and click Regenerate, then replace the key you are sending with the new one.` | The key matches no program | Do as the message says: the key is under program menu → **Program settings**, then **Developers** → **API keys**. Running `affitor init` does not help: it creates a second program |
| both | `401` | [`api_key_rotation_required`](#api_key_rotation_required) | The key is retired | Create a new key |
| `GET /status` | `500` | `Failed to get status (request_id: <id>)` | Status lookup failed on our side | Retry with backoff |
| `POST /test-event` | `400` | `Invalid event_type: <value>. Valid: click, lead, sale` | Single-event mode got a missing or unknown `event_type` | Send `click`, `lead` or `sale`, or `{"type": "chain"}` for the full chain |
Expand Down
4 changes: 2 additions & 2 deletions content/docs/api-reference/integrations/fastify.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: "Fastify"
description: "Server-side Affitor integration with @affitor/sdk/server — track signups and sales from your Fastify backend, including a raw-body Stripe webhook."
kind: guide
last_updated: 2026-10-16
last_updated: 2026-10-17
---

This guide wires Affitor into a Fastify app. Because Fastify is a pure server runtime, the click is captured by a frontend script tag, then the `affitor_click_id` is forwarded to your server so all tracking calls — lead and sale — happen server-side with `@affitor/sdk/server`. The sale is tracked from your Stripe webhook handler, which needs the **raw request body** for signature verification.
Expand All @@ -15,7 +15,7 @@ The `@affitor/sdk` package is **Beta**. The documented happy-path works; report

## Prerequisites

- Your **program ID** (**Settings** → **Program settings** → **Business**)
- Your **program ID** (program menu → **Program settings** → **Business**)
- A **program API key** for server-side calls (dashboard → API keys)
- `@affitor/sdk` and `stripe` installed in your backend

Expand Down
4 changes: 2 additions & 2 deletions content/docs/api-reference/integrations/nextjs-clerk.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: "Next.js + Clerk"
description: "Add Affitor tracking to a Next.js (App Router) app that uses Clerk for authentication."
kind: guide
last_updated: 2026-10-16
last_updated: 2026-10-17
---

This guide covers the auth-specific parts of an Affitor integration when your Next.js app uses Clerk. Steps 1 (capture the click) and 3 (track the sale) are identical to the [base Next.js guide](/docs/api-reference/integrations/nextjs) — this guide focuses on **Step 2: tracking the signup** with Clerk's identity model.
Expand All @@ -15,7 +15,7 @@ The `@affitor/sdk` package is **Beta**. The documented happy-path works; report

## Prerequisites

- Your **program ID** (**Settings** → **Program settings** → **Business**)
- Your **program ID** (program menu → **Program settings** → **Business**)
- A **program API key** for server-side calls (leads and sales)
- A Next.js App Router app with **Clerk** configured

Expand Down
4 changes: 2 additions & 2 deletions content/docs/api-reference/integrations/nextjs-nextauth.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: "Next.js + NextAuth"
description: "Add Affitor lead tracking to a Next.js app using NextAuth (Auth.js) — handle the click-id cookie gap correctly."
kind: guide
last_updated: 2026-10-16
last_updated: 2026-10-17
---

This guide covers the signup step when your Next.js app uses **NextAuth (Auth.js)** for authentication. Steps 1 (capture click) and 3 (track sale) are identical to the [base Next.js guide](/docs/api-reference/integrations/nextjs) — this page focuses on what is different: wiring the lead call to NextAuth's auth lifecycle without losing the click attribution.
Expand All @@ -15,7 +15,7 @@ The `@affitor/sdk` package is **Beta**. The documented happy-path works; report

## Prerequisites

- Your **program ID** (**Settings** → **Program settings** → **Business**)
- Your **program ID** (program menu → **Program settings** → **Business**)
- A **program API key** for server-side calls
- A Next.js App Router app with NextAuth (Auth.js) configured

Expand Down
4 changes: 2 additions & 2 deletions content/docs/api-reference/integrations/nextjs-supabase.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: "Next.js + Supabase Auth"
description: "Add Affitor tracking to a Next.js app that uses Supabase Auth — clicks, signups, and sales."
kind: guide
last_updated: 2026-10-16
last_updated: 2026-10-17
---

This guide covers the Supabase-specific signup step. Steps 1 (capture the click) and 3 (track the sale) are identical to the [base Next.js guide](/docs/api-reference/integrations/nextjs) — refer there for full detail.
Expand All @@ -15,7 +15,7 @@ The `@affitor/sdk` package is **Beta**. The documented happy-path works; report

## Prerequisites

- Your **program ID** (**Settings** → **Program settings** → **Business**)
- Your **program ID** (program menu → **Program settings** → **Business**)
- A **program API key** for server-side calls (leads and sales)
- A Next.js app with **Supabase Auth** configured

Expand Down
4 changes: 2 additions & 2 deletions content/docs/api-reference/integrations/nextjs.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: "Next.js"
description: "Add Affitor tracking to a Next.js (App Router) app — clicks, signups, and sales."
kind: guide
last_updated: 2026-10-16
last_updated: 2026-10-17
---

This guide wires Affitor into a Next.js App Router app with the three moves every integration needs: **capture the click**, **track the signup**, **track the sale**.
Expand All @@ -15,7 +15,7 @@ The `@affitor/sdk` package is **Beta**. The documented happy-path works; report

## Prerequisites

- Your **program ID** (**Settings** → **Program settings** → **Business**)
- Your **program ID** (program menu → **Program settings** → **Business**)
- A **program API key** for server-side calls (leads and sales)
- A Next.js app on the **App Router**

Expand Down
4 changes: 2 additions & 2 deletions content/docs/api-reference/integrations/node-express.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: "Node / Express"
description: "Server-side Affitor integration with @affitor/sdk/server — track signups and sales from your Express backend."
kind: guide
last_updated: 2026-10-16
last_updated: 2026-10-17
---

This guide wires Affitor into a Node.js / Express app. Because Express is a pure server runtime, the click is captured by a frontend script tag, then the `affitor_click_id` is forwarded to your server so all tracking calls — lead and sale — happen server-side with `@affitor/sdk/server`.
Expand All @@ -15,7 +15,7 @@ The `@affitor/sdk` package is **Beta**. The documented happy-path works; report

## Prerequisites

- Your **program ID** (**Settings** → **Program settings** → **Business**)
- Your **program ID** (program menu → **Program settings** → **Business**)
- A **program API key** for server-side calls (dashboard → API keys)
- `@affitor/sdk` installed in your backend

Expand Down
4 changes: 2 additions & 2 deletions content/docs/api-reference/integrations/polar.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: "Polar"
description: "Canonical recipe for attributing Polar payments to Affitor partners — one-time, subscriptions, renewals, and refunds. No Stripe account needed."
kind: guide
last_updated: 2026-10-16
last_updated: 2026-10-17
---

This guide is the **canonical reference for the Polar sale path**. Polar is a merchant of record, so there is no Stripe account to connect — instead, your app hosts a small webhook route that reports every paid order to Affitor.
Expand All @@ -15,7 +15,7 @@ The `@affitor/sdk` package is **Beta**. The documented happy-path works; report

## Prerequisites

- Your **program ID** and a **program API key** (run `npx affitor init`, or **Settings** → **Program settings** → **Business** for the ID and **Developers** → **API keys** for the key)
- Your **program ID** and a **program API key** (run `npx affitor init`, or, in the program menu, **Program settings** → **Business** for the ID and **Developers** → **API keys** for the key)
- A Polar organization with checkout working in your app
- Access to your Polar organization's webhook settings. Sandbox is a separate environment with its own tokens and its own webhook endpoints (`sandbox-api.polar.sh`).

Expand Down
8 changes: 4 additions & 4 deletions content/docs/api-reference/integrations/stripe.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: "Stripe"
description: "Canonical recipe for attributing Stripe payments to Affitor partners — one-time and recurring."
kind: guide
last_updated: 2026-10-16
last_updated: 2026-10-17
---

This guide is the **canonical reference for the Stripe sale path**. Other framework guides (Next.js, Express, etc.) link here for Step 3. If you need click capture or signup tracking first, start with the [Next.js guide](/docs/api-reference/integrations/nextjs) or the framework guide for your stack.
Expand All @@ -15,10 +15,10 @@ The `@affitor/sdk` package is **Beta**. The documented happy-path works; report

## Prerequisites

- Your **program ID** (**Settings** → **Program settings** → **Business**)
- A **program API key** (dashboard → program settings → API keys)
- Your **program ID** (program menu → **Program settings** → **Business**)
- A **program API key** (program menu → **Program settings**, then **Developers** → **API keys**)
- Stripe Checkout or Stripe Billing already working in your app
- Affitor receiving your Stripe webhooks (dashboard → program settings → Stripe connect)
- Affitor receiving your Stripe webhooks (program menu → **Program settings** → **Payments**, **Connect Stripe**)

## 1. Capture clicks and track signups

Expand Down
14 changes: 7 additions & 7 deletions content/docs/api-reference/mcp.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: Affitor MCP server
description: Connect Claude, ChatGPT, Cursor, VS Code, Perplexity, Claude Code, Codex and other AI apps to your Affitor program or partner account at https://mcp.affitor.com/mcp. Sign in with your Affitor account; access is read-only.
kind: reference
last_updated: 2026-10-16
last_updated: 2026-10-17
---

The Affitor MCP server lets an AI app read your Affitor data: a brand's program, partners, applications, commissions and billing, or a partner's programs, links, earnings, commissions and payouts. It is a hosted [Model Context Protocol](https://modelcontextprotocol.io) server. You sign in with your Affitor account, no API key needed, and the connection is read-only: it cannot change data or move money.
Expand Down Expand Up @@ -38,7 +38,7 @@ https://mcp.affitor.com/mcp

## Connect your AI app

In the Affitor dashboard, **Connect an AI tool** shows the server URL and steps for Claude, Cursor, Claude Code and Codex. Brands find it in **All settings** › **Developers** › **AI agents**, and on the program's **Tracking** step under **Your agent** › **Connect your AI**. Partners find it in **Settings** › **Integrations**.
In the Affitor dashboard, **Connect an AI tool** shows the server URL and steps for Claude, Cursor, Claude Code and Codex. Brands find it in the program menu under **Program settings**, then **Developers** › **AI agents**, and on the program's **Tracking** step under **Your agent** › **Connect your AI**. Partners find it in the **⋯** menu next to their name, at the bottom of the left menu, under **Integrations**.

<CodeGroup items={[
{
Expand Down Expand Up @@ -175,8 +175,8 @@ To give an app a second program, connect again and pick that program. Each conne
"Your AI app lists the Affitor tools: `get_program` for a brand connection, `list_my_programs` for a partner connection",
]}
dashboard={[
"Brands: the connection appears under **All settings** › **Developers** › **AI agents**, with **Added** and **Last used**",
"Partners: the connection appears under **Settings** › **Integrations**",
"Brands: the connection appears on **Developers** › **AI agents** (program menu › **Program settings**), with **Added** and **Last used**",
"Partners: the connection appears on **Integrations**, in the **⋯** menu next to your name",
]}
ifNotWorking={[
"**This request has expired**: start the connection again from your AI app",
Expand Down Expand Up @@ -210,7 +210,7 @@ Every tool is read-only, and the server declares it so on each tool: `readOnlyHi
| `list_my_links` | Your referral links, newest first, with lifetime clicks, leads and sales. | `partner_program_id`, `status` (`active`, `inactive`), `limit`, `cursor` |
| `get_my_earnings` | Your earnings per program and in total for the window: earned, ready, arriving, paid and pending. | `from`, `to` |
| `list_my_commissions` | Your commissions across your programs, newest sale first. | `status`, `from`, `to`, `partner_program_id`, `limit`, `cursor` |
| `list_my_payouts` | Your payout requests, newest first: amount, status, method type and dates. Bank and PayPal details are never included. | `limit`, `cursor` |
| `list_my_payouts` | Your payout requests, newest first: amount, status, method type and dates. Payout account details, such as bank or Wise details, are never included. | `limit`, `cursor` |

### How results look

Expand Down Expand Up @@ -264,8 +264,8 @@ The server cannot approve an application, change a commission, create a link or

### Remove access

- **Brands:** **All settings** › **Developers** › **AI agents** lists the program's connections under **Connections** with **Client**, **Connected by**, **Added**, **Last used** and **Access**. Click **Remove** on your own connection. A program owner can remove any member's connection to that program.
- **Partners:** **Settings** › **Integrations**, then **Remove**.
- **Brands:** program menu › **Program settings**, then **Developers** › **AI agents**, lists the program's connections under **Connections** with **Client**, **Connected by**, **Added**, **Last used** and **Access**. Click **Remove** on your own connection. A program owner can remove any member's connection to that program.
- **Partners:** the **⋯** menu next to your name › **Integrations**, then **Remove**.

Removal is immediate: the app's tokens are deleted and its next request gets `401`.

Expand Down
6 changes: 3 additions & 3 deletions content/docs/brand/api-keys.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: API key reference
description: Which credential each Affitor call needs, where the program API key lives, how to replace it, and how mandatory rotation is signalled.
kind: reference
last_updated: 2026-10-15
last_updated: 2026-10-17
---

Affitor has one self-serve credential: the **program API key**. It authenticates server-side tracking calls for a single program, you manage it yourself from the dashboard, and it is the key the integration guides, the SDKs, the CLI's tracking setup, and the agent skill all refer to. CLI commands that create or list programs are different: they act as your account, so they authenticate with your CLI login rather than with this key.
Expand Down Expand Up @@ -46,7 +46,7 @@ Keys issued before the short prefix was introduced do not start with `aff_`. Aut

## Where to find it

1. In the program menu (your program's name at the top of the left menu), choose **All settings**.
1. In the program menu (your program's name at the top of the left menu), choose **Program settings**.
2. Under **Developers**, select **API keys**.

A program is given a key the moment it is created, but creating a program does not hand that value back to you. To get a key you can put in an environment variable, a workspace owner selects **Generate** — or **Regenerate**, if one was generated before — on the **API keys** page. The full value appears in the response to that action, and only there. Copy it then and store it server-side:
Expand Down Expand Up @@ -136,7 +136,7 @@ Send a test-mode call with the key in hand: it goes through the same authenticat
"Read the status before the body: a 200 with no warnings array means this key is not flagged for mandatory rotation. A flagged key that is past its deadline returns 401 and carries no warnings array either, so warnings alone never proves a key is unflagged",
]}
dashboard={[
"Settings → API keys shows a masked value whose visible characters match the key your server sends",
"The **API keys** page (program menu → **Program settings**, then **Developers** → **API keys**) shows a masked value whose visible characters match the key your server sends",
]}
ifNotWorking={[
"On a 401, read error.code first. api_key_rotation_required means the key passed its rotation deadline — regenerate it, because re-copying the same key will not bring it back. Any other 401 means the header is malformed or the key matches no program: check the Authorization: Bearer prefix and your environment variable for trailing whitespace",
Expand Down
Loading
Loading