> AffiliateOS Help Center. Index of every article for AI tools: https://www.affiliateos.ai/help/llms.txt

# Errors and rate limits

Developer docs · For everyone · Updated 30 October 2026
Web version: https://www.affiliateos.ai/help/developers/errors-and-rate-limits

Our API answers an error with a standard HTTP status and a short JSON body that says what went wrong. Fix the request before you retry a 400, 401, 403 or 404. Retry a 429 or a 5xx after a wait that grows each time.

## The error body

Errors come back as JSON with `statusCode` and `message`, and most also carry `error`:

```json
{
  "statusCode": 401,
  "message": "Invalid or expired API key",
  "error": "Unauthorized"
}
```

When a 400 comes from a field check, `message` is a list with one line per problem. Log the whole body: the message is usually the fix.

## Status codes

| Status | What it means | What to do |
|---|---|---|
| 400 | A parameter or body field failed a check. On advertiser events, also any field the API doesn't know. | Read `message`, fix the request, then send it. Don't retry it unchanged. |
| 401 | No key, a mistyped key, a revoked or expired key, or a publisher account that isn't active. | See the key messages below. |
| 403 | The key is valid, but this account can't use the route. | Read `message`. Email us if it doesn't say why. |
| 404 | The route, or the item in it, doesn't exist for your account, such as an offer you can't run. | Check the path and the ID. |
| 429 | Too many requests from one address in a short time. | Wait, then retry with a growing wait. |
| 5xx | Something failed on our side. | Retry with a growing wait. If it keeps happening, email us the time and the request. |

On the offer calls, a query parameter we don't recognize is dropped without an error. If a filter seems to do nothing, check its spelling against the [Offer API reference](https://www.affiliateos.ai/help/developers#offer-api).

## Key messages, word for word

| Message | Status | Where | What to do |
|---|---|---|---|
| `Missing x-api-key header` | 401 | Network API | Send your key as `x-api-key: ak_...`. |
| `Invalid or expired API key` | 401 | Offer API, Network API | Check the key in **API Keys**: a revoked or removed key is no longer listed; an older publisher key past its date reads expired under **Status**; networks check whether **Expires** has passed. |
| `Partner account is not active` | 401 | Offer API | The publisher account is restricted ("partner" is an older name for a publisher account). Email us. |
| `Invalid API key` | 401 | Advertiser events | The key doesn't start with `ak_`, isn't an advertiser key or was revoked. Mint a new one on the campaign. |
| `Your account is currently restricted. Please contact support.` | 403 | Network API | Email us. |
| `Your account is pending approval. Please wait for activation.` | 403 | Network API | Your network account hasn't been activated yet. Email us if you expected it to be. |

Publisher keys made since 24 August 2026 never expire; older ones show their date under **Expires**. Network keys expire, 90 days after you generate them by default, and an expired key answers 401 on every call. To put the next key live before that date you need room for two keys: the key list shows **Used** against your limit, and at one, ask us to raise it first. Where keys come from: [hosts and keys](https://www.affiliateos.ai/help/developers#keys).

## Not errors: event statuses

An advertiser event that we accept but don't charge still gets a success response. The reason is in the `status` field of the body: `duplicate`, `missing_attribution`, `invalid_event`, `outside_window`, `campaign_paused`, `insufficient_balance` or `rejected`. Read `status` on every response, not only the HTTP code. What each one means: [advertiser events](https://www.affiliateos.ai/help/developers#advertiser-events).

## Rate limits

We limit how many requests one address or one account can make in a short time. We don't publish the numbers, and they can change. You'll see a limit as one of these:

- **429** with `Too many requests`, on sign-in, sign-up, invite links, password and secret changes, and the public top offers list.
- **400** with a message that starts `Rate limit exceeded`, on advertiser events and install matching.

When you hit one:

- Wait, then retry. Double the wait after each failed try, and stop after a few.
- Advertisers: send each event as it happens, not in a nightly batch. A retry with the same `eventId` comes back as `duplicate`, so retrying is safe.
- Publishers: the offer list changes as caps fill and offers end. Refresh it on a schedule, not on every tap.

> **Never retry in a tight loop.** A request retried at once, again and again, keeps you over the limit. Spread retries out and give up after a few, then log the error for a person to read.

## Postbacks we send you

These are the requests that go the other way, from us to your server.

- We send a GET and wait for your answer. Answer with any 2xx status, best of all 200.
- Publisher postbacks: if your server doesn't answer, or answers 5xx or 429, we try again a few times within seconds; any other 4xx is final. Network postbacks are sent once.
- The result is in **Flight Recorder**. Publishers see **Your postback delivery** (**Attempted**, **HTTP status**, **Error**), and **Copy request** copies the masked URL we called. Networks see **Network Delivery Response**, with the **Masked URL**.
- After the last try the delivery reads `failed`. Publishers: once your server is fixed, send us the action IDs: our team can send a failed credit from the Offer API or a link again, under the same `action_id`, so your dedupe still works.

How to answer and verify them: [postback reference](https://www.affiliateos.ai/help/developers#postbacks). When one doesn't arrive at all: [Postback not firing or never arrives](https://www.affiliateos.ai/help/troubleshooting/postback-never-arrives).
