> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sparkles.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Handle API errors

> Respond correctly to Sparkles API validation, authorization, conflict, limit, and server errors.

All partner API errors use the same JSON envelope:

```json theme={null}
{
	"error": {
		"code": "idempotency_conflict",
		"message": "This leadId is already attached to different claim details"
	}
}
```

## Error reference

| HTTP  | Code                          | Meaning                                                         | Action                                                      |
| ----- | ----------------------------- | --------------------------------------------------------------- | ----------------------------------------------------------- |
| `400` | `invalid_json`                | The request body is not valid UTF-8 JSON.                       | Correct the JSON before retrying.                           |
| `400` | `invalid_request`             | A field or event-feed query failed validation.                  | Send only the documented fields and constraints.            |
| `401` | `unauthorized`                | The bearer key is missing, malformed, revoked, or inactive.     | Replace it with an active key.                              |
| `404` | `not_found`                   | The claim is invalid or not visible to this access grant.       | Check the claim ID and authenticated grant.                 |
| `409` | `idempotency_conflict`        | The `leadId` already has different claim details.               | Use the original details or a new lead ID.                  |
| `409` | `credit_budget_exceeded`      | New claims would exceed the access grant's total credit budget. | Ask an administrator to increase the budget.                |
| `409` | `claim_limit_exceeded`        | The access grant has allocated 100,000 unique claims.           | Ask an administrator for a new or expanded grant.           |
| `413` | `request_too_large`           | The request body exceeds 16 KiB.                                | Reduce the body before retrying.                            |
| `415` | `unsupported_media_type`      | The request does not use `application/json`.                    | Set the correct `Content-Type`.                             |
| `422` | `credit_amount_exceeds_limit` | The whole-credit amount exceeds the per-claim limit.            | Lower the amount to the limit shown on the API access page. |
| `429` | `rate_limited`                | The API key exceeded 600 requests in one minute.                | Wait for `Retry-After`, then retry.                         |
| `500` | `internal_error`              | Sparkles could not complete the request.                        | Retry with exponential backoff.                             |

All successful and error responses include `Cache-Control: private, no-store`.

## Retry policy

Retry network failures and HTTP `500` responses with exponential backoff and jitter. For HTTP `429`, wait at least the number of seconds in `Retry-After`.

Do not automatically retry validation, authorization, conflict, size, or media-type errors without changing the request or access configuration.

Creating a credit claim is safe to retry because `leadId` is its idempotency key. A byte-for-byte identical JSON body is not required, but the normalized email, variant, and credit amount must match the original claim details.

## Example retry decision

```typescript theme={null}
export function shouldRetry(status: number) {
	return status === 429 || status >= 500;
}
```

Cap automated retries, record the final error code, and preserve the original `leadId` across every create-claim attempt.
