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

# Errors

> Every error code the pull/story API returns, and how to handle it.

## Error shape

Every error response uses the same shape:

```json theme={null}
{
  "error": {
    "code": "string",
    "message": "human-readable explanation",
    "request_id": "req_01hq..."
  }
}
```

Include the `request_id` when reporting an issue — it lets us find the exact failing request in our logs.

## HTTP status codes

| Status | Meaning                            |
| ------ | ---------------------------------- |
| `200`  | Success                            |
| `202`  | Accepted — generation in progress  |
| `400`  | Invalid request body or parameters |
| `401`  | Missing or invalid API key         |
| `402`  | Out of minutes for the month       |
| `404`  | Story or endpoint not found        |
| `429`  | Rate limit exceeded                |
| `500`  | Internal server error              |
| `503`  | Service temporarily unavailable    |

## Error codes

### Authentication

<ResponseField name="invalid_api_key" type="401">
  The API key is malformed, expired, or has been revoked.
</ResponseField>

<ResponseField name="missing_api_key" type="401">
  No `Authorization` header was sent, or the `Bearer` prefix is missing.
</ResponseField>

### Validation

<ResponseField name="invalid_request" type="400">
  The request body failed schema validation. Check the `details` array in the response for the specific field.
</ResponseField>

<ResponseField name="invalid_id" type="400">
  The story ID does not match `brief_<16-hex>`.
</ResponseField>

<ResponseField name="not_found" type="404">
  No story exists for the requested ID.
</ResponseField>

<ResponseField name="failed" type="story status">
  Generation reached a terminal failure. Polling returns `status: "failed"` with an `error` message; no minutes are charged.
</ResponseField>

<ResponseField name="corrupt_cache_entry" type="500">
  A cached story exists but could not be parsed. Retry later or report the `request_id`.
</ResponseField>

### Billing

<ResponseField name="insufficient_minutes" type="402">
  You've used your full monthly video allowance. Wait until your next billing cycle or [upgrade your plan](https://pullstory.com/dashboard).
</ResponseField>

### Rate limiting

<ResponseField name="rate_limit_exceeded" type="429">
  Too many requests. Back off for the number of seconds in the `Retry-After` header.
</ResponseField>

### Service failures

<ResponseField name="server_misconfigured" type="503">
  Redis or billing configuration is unavailable, so generation cannot safely proceed.
</ResponseField>

## Retry strategy

<AccordionGroup>
  <Accordion title="5xx errors: exponential backoff">
    Retry with `1s, 2s, 4s, 8s` delays. Give up after 4 attempts. Story creation is idempotent by brief content, so an identical JSON brief returns the same story ID.
  </Accordion>

  <Accordion title="429: respect Retry-After">
    Sleep for the exact number of seconds in the `Retry-After` header, then retry once.
  </Accordion>

  <Accordion title="4xx except 429: don't retry">
    Client errors won't fix themselves. Log the `request_id`, fix the request, and try again.
  </Accordion>
</AccordionGroup>

## Reporting bugs

Email the `request_id` from the error response to [moshikarim@proton.me](mailto:moshikarim@proton.me) or open an issue on [GitHub](https://github.com/EchoMosh).
