# Errors

> The Brand API uses conventional HTTP status codes. 2xx means success, 4xx means something in the request needs to change, and 5xx means retry later.

- Audience: API
- Page type: reference
- Updated: 2026-10-08
- Canonical URL: https://www.rendezvu.co/docs/api/errors

Every response tells you how it went in its status code. Codes in the `2xx` range mean success. Codes in the `4xx` range mean the request needs to change: a bad parameter, a missing scope, a resource that is not yours. Codes in the `5xx` range mean something went wrong on our side, and the same request may succeed if you retry it.

## Error format

An error body has `success: false` and a human-readable `message`. Messages are written for the developer reading the log; do not parse them, branch on the status code instead.

```json
{
  "success": false,
  "message": "This API key is missing the analytics:read scope"
}
```

## Status codes

| Status | Meaning | When |
| --- | --- | --- |
| `400` | Bad Request | A query parameter is unknown or invalid, or the key was sent in the URL or an x-api-key header. |
| `401` | Unauthorized | The key is missing, malformed, unknown, expired or revoked. The response carries WWW-Authenticate: Bearer. |
| `402` | Payment Required | Your plan doesn't include this data, or the subscription is inactive. |
| `403` | Forbidden | The key lacks the endpoint's scope, or the request came from an IP outside the key's allowlist. |
| `404` | Not Found | The resource does not exist, or it belongs to another brand. |
| `405` | Method Not Allowed | Any method other than GET or HEAD. The API is read-only. |
| `410` | Gone | A retired endpoint, such as the keyless public recommendations feeds. |
| `429` | Too Many Requests | The key or the IP address is over its per-minute limit. |
| `500` | Server Error | Something went wrong on our side. Retry with backoff. |
| `503` | Service Unavailable | Authentication, the plan check or the audit log is briefly unavailable. Retry with backoff. |

A resource that belongs to another brand is always `404`, never `403`, so the API never confirms that someone else's campaign or survey exists.

## Rate limit responses

A `429` has its own body, along with `Retry-After` and the `X-RateLimit-*` headers described in [Rate limits](/docs/api/rate-limits):

```json
{
  "error": "Rate limit exceeded",
  "message": "Rate limit exceeded for this API key (60 requests/minute).",
  "retryAfter": 23
}
```

## Handle errors

- **Retry** `429`, `500` and `503` with exponential backoff. For a `429`, wait at least `Retry-After` seconds first.
- **Do not retry** any other `4xx`. Fix the request, the key or its scopes.
- **Treat `402`** as a plan question for your Rendezvu admin, not a code problem.

```javascript
async function rendezvu(path, attempt = 0) {
  const res = await fetch(`https://api.rendezvu.co/api/brand/v1${path}`, {
    headers: { Authorization: `Bearer ${process.env.RENDEZVU_BRAND_API_KEY}` },
  });
  const retryable = res.status === 429 || res.status >= 500;
  if (retryable && attempt < 5) {
    const wait = Number(res.headers.get('retry-after')) || 2 ** attempt;
    await new Promise((resolve) => setTimeout(resolve, wait * 1000));
    return rendezvu(path, attempt + 1);
  }
  const body = await res.json();
  if (!res.ok) throw new Error(`Rendezvu ${res.status}: ${body.message}`);
  return body;
}
```

## Related

- [Authentication](https://www.rendezvu.co/docs/api/authentication.md): Authenticate every request with a secret API key in the Authorization header. Keys are read-only, scoped, tied to one brand, and always expire.
- [Rate limits](https://www.rendezvu.co/docs/api/rate-limits.md): Each API key can make 60 requests a minute, and each IP address 120. Every response carries headers that say how much of the limit is left.

---

Source: https://www.rendezvu.co/docs/api/errors (Rendezvu docs, Markdown view). Every page: https://www.rendezvu.co/llms.txt