# 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`.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.perceptis.ai/perceptis-api-v1/errors-and-limits.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
