# Authentication

API keys, scopes, live and test mode, and how AI agents connect over MCP without one.

The REST API checks who's calling with an API key. Zapier, n8n, your own code and your scripts all
use one.

- You make keys in the dashboard. They belong to your organization.
- Each key carries a list of what it's allowed to do. Each item on that list is a **scope**.
- AI agents don't use a key. They connect over MCP by signing in ([below](#how-ai-agents-connect)).

API and MCP access come with every plan, the free trial included.

## Creating a key

1. In the dashboard, open **Settings**, then **API keys**.
2. Name the key after what will hold it, like "Production server" or "Zapier".
3. Read the short summary beside **Create key**. It says what the key can and can't do.
4. By default a key can do everything. To narrow it, choose **Limit this key** and pick scopes. The summary follows your choice.
5. Press **Create key**, then copy the key.

You see the key exactly once, with the same summary beside it. We only store a scrambled
fingerprint of it (a hash), so we can't show it again.

Keys look like `rail_live_…` or `rail_test_…`.

<Callout type="warn">
**A test key is a live key with a different prefix.** It reads and writes the same data as a live one: the same partners, commissions and payouts. Every response carries `X-Rail-Livemode: false`. That header labels the answer. It doesn't wall off any data.

So a `rail_test_` key used from staging creates real partners and real commissions in your real program. Want a place to experiment where nothing counts? Make a second organization and create a key there.
</Callout>

Send the key in the `Authorization` header, after the word `Bearer` (a bearer token):

```bash
curl https://api.affiliaterail.com/v1/programs \
  -H "Authorization: Bearer rail_live_..."
```

## Scopes

A key holds one or more scopes. Pick the smallest set that does the job. You can always create
another key.

| Scope | Allows |
| --- | --- |
| `read` | Read every object in the organization |
| `write` | Create, update and delete every object (includes every narrower write scope), and mint partner sign-in links |
| `partners:write` | Partners, groups, tags, applications, links and coupons |
| `commissions:write` | Clicks, customers, sales, refunds, commissions and commission rules |
| `payouts:write` | Payout batches and marking payouts paid |
| `webhooks:write` | Webhook endpoints |
| `mcp:read` | Read-only access for a connected model (MCP) |
| `mcp:write` | Every write tool a connected model has: program settings, branding, commission rules, groups, partner links, coupons and clearing sample data, plus the review queues and partner invites. Read-only over REST |

Any write scope includes `read`, and `read` means everything in your organisation. So a key with only `partners:write` can still read sales, commissions and payouts. Pick `read` on its own for a key that should only look.

Ask for more than a key holds and you get a 403. It names the scope the request needed and the
scopes the key holds, so you know the fix.

One action sits on no narrow scope: `POST /v1/partners/{id}/sso`. It makes a link that signs a
partner into their portal. That's a live session, not a record, so only a key holding `write` can
make one. A leaked `partners:write` key can't open a partner's portal.

## Revocation

Revoke a key under **Settings**, **API keys**. It stops working on its next request, so everything
that sends it is cut off at once.

If a key leaks, revoke it first. Then create its replacement.

## How AI agents connect

An AI agent doesn't need a key.

1. Add `https://mcp.affiliaterail.com/mcp` to Claude, ChatGPT, Claude Code, Cursor, VS Code or Codex.
2. AffiliateRail opens in your browser. Sign in the way you always do.
3. Press **Allow**.

The agent gets a short-lived token. It lasts an hour and renews on its own. You never see a key,
so you can't leave one in a chat.

Each connection is listed under **Settings**, **API keys**, **Connected agents**. Press
**Disconnect** next to one and it stops on its next request. Removing the connector inside your
agent ends it too.

[Connect your assistant or editor](/mcp/setup) walks through each client. [MCP security](/mcp/security)
explains how it works.

## Webhook signing

A webhook is a message we send to your server when something happens. Each one is signed, so your
server can prove it came from us.

- The signing secret is a `whsec_…` value, one per endpoint.
- It's separate from your API keys.
- You see it once, when you create the endpoint.

See [Webhooks](/api/webhooks).
