# Response codes

> Reference of the HTTP codes used across the whole Rapid API.

Página: https://doc.rapidchargeback.com/en/referencia/codigos-de-resposta/

Reference of the HTTP codes used across the whole Rapid API.

## Success codes

| Code | Meaning |
|---|---|
| 200 | Success with body |
| 201 | Resource created |
| 204 | Success without body (e.g. `DELETE`) |

## Client error codes

| Code | Meaning |
|---|---|
| 400 | Body is not valid JSON (`INVALID_JSON`) |
| 401 | Missing or invalid credentials |
| 403 | Company blocked |
| 404 | Resource not found |
| 409 | Conflict (duplicate, immutable resource) |
| 413 | Body above the maximum size (`PAYLOAD_TOO_LARGE`) |
| 422 | Validation error |
| 429 | Too many requests (rate limit) |

## Server error codes

| Code | Meaning |
|---|---|
| 500 | Internal error (`INTERNAL_ERROR`), retry recommended |

---

## Error body format

Every error response has this structure:

```json
{
  "error": {
    "code": "SEMANTIC_CODE",
    "message": "Human-readable description of the error"
  }
}
```

The `message` is in English and is meant for whoever reads the log: its wording can change. To decide what to do in your code, use the `code`. The endpoints kept from the previous system respond as they did before.

## Most common semantic codes

| Code | HTTP | Use |
|---|---|---|
| `INVALID_JSON` | 400 | The body is not valid JSON |
| `UNAUTHORIZED` | 401 | Missing or invalid credentials |
| `COMPANY_BLOCKED` | 403 | Company blocked |
| `VALIDATION_ERROR` | 422 | One or more invalid fields |
| `NOT_FOUND` | 404 | The address does not exist in the API (typo in the path, extra trailing slash) |
| `TRANSACTION_NOT_FOUND` | 404 | Transaction does not exist |
| `TRANSACTION_DUPLICATE` | 409 | `external_source` + `external_id` already registered |
| `TRANSACTION_IMMUTABLE` | 409 | Transaction already used, cannot be modified |
| `MERCHANT_NOT_FOUND` | 404 | Merchant does not exist |
| `ALERT_NOT_FOUND` | 404 | Alert does not exist |
| `ALERT_INVALID_STATUS` | 422 | Invalid status, or transition not allowed (deadline, expiration or status already final) |
| `PAYLOAD_TOO_LARGE` | 413 | Body above the limit: 1 MB per request, 5 MB in [batch upload](https://doc.rapidchargeback.com/en/canais/transactions/envio-em-lote/) |
| `RATE_LIMIT_EXCEEDED` | 429 | Request limit exceeded (see below) |
| `INTERNAL_ERROR` | 500 | Unexpected server error |

## Rate limit

All routes share a limit of **100 requests per minute per IP**, including those that answer `401` for invalid credentials. The exception is [sending an event from the browser](https://doc.rapidchargeback.com/en/canais/capture/enviar-evento-navegador/), which has its own cap of 120 per minute and does not count toward the 100.

When you go over it, the API returns:

```
HTTP/1.1 429 Too Many Requests
Retry-After: 15
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 15
```

```json
{
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "Rate limit exceeded, retry in 15 seconds"
  }
}
```

**Use `Retry-After`.** It says, in seconds, how long until the window resets, and the message repeats the same number. Waiting exactly that long is better than guessing: blind exponential backoff can retry too early (and get another `429`) or wait longer than needed.

The `X-RateLimit-*` headers come in **every** response, not only in the `429`, so you can get ahead of it: when `X-RateLimit-Remaining` gets close to zero, hold the sending instead of waiting for the error. For volume, prefer [batch upload](https://doc.rapidchargeback.com/en/canais/transactions/envio-em-lote/), which sends up to 1000 transactions in one request and uses one unit of the limit.

## Retrying 5xx errors

`5xx` errors are usually transient. Retry with increasing intervals between attempts. Never retry `4xx`: they mean an error on your side and will fail again.
