> For the complete documentation index, see [llms.txt](https://docs.perceptis.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.perceptis.ai/perceptis-api-v1/errors-and-limits.md).

# Errors, rate limits, and billing

## Error response shape

Synchronous errors typically look like:

```json
{
  "error": {
    "code": "invalid_request",
    "message": "Human-readable detail"
  }
}
```

Branch on `error.code`, not on `message`. Messages are intended for debugging and may change.

## Common error codes

| Code                      | Meaning                                                                               |
| ------------------------- | ------------------------------------------------------------------------------------- |
| `invalid_request`         | The request is malformed, fails validation, or uses an unsupported field combination. |
| `not_found`               | The requested job or resource was not found for the current API key.                  |
| `ambiguous_template_name` | `template_name` matches more than one accessible template.                            |
| `idempotency_conflict`    | The same `Idempotency-Key` was reused with a different request body.                  |
| `rate_limit_exceeded`     | The integration is sending requests too quickly. Use `Retry-After` and back off.      |

Generation failures are returned by the status endpoint as `status: "failed"` with an `error` object.

## Rate limits

Perceptis applies limits to generation requests and status polling. If you receive `429`, read the `Retry-After` response header, wait at least that long, and retry with backoff.

Recommended polling behavior:

* Start with a 2 to 5 second interval.
* Increase the interval after repeated in-progress responses.
* Set a timeout in your integration.
* Do not poll more than once per second for the same job.

Repeated status polls for a completed job do not create additional generation charges.

## Billing and credits

API usage draws from your organization's Perceptis credit pool.

* Single-slide jobs are based on delivered variants.
* Deck jobs are based on delivered slides.
* Failed jobs do not consume credits.
* Polling status does not consume credits.

## Idempotency

Send an `Idempotency-Key` header on `POST /api/v1/generate` when retrying a request after a network error or timeout. Reuse the same key only with the same request body.

The idempotency key is not the job identifier. After the request is accepted, use the returned `job_id` to poll status and refresh download links.

If the same key is reused with a different body, the API returns `409` with `idempotency_conflict`.
