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

# Introduction

> Authentication, response envelopes, timestamps, and public-route conventions.

## Base URL

The codebase exposes these public routes, but it does not hardcode a single global hostname. Use the Offload API host for your environment:

```text theme={null}
https://<your-offload-api-host>
```

In SST deployments, the API host is emitted as `api.url`.

## Authentication

Every public client route uses:

```http theme={null}
x-api-key: your-api-key
```

Auth behavior:

* missing key -> `401 UNAUTHORIZED`
* invalid key -> `401 UNAUTHORIZED`
* inactive key -> `403 FORBIDDEN`

## Response Envelopes

Application-level success:

```json theme={null}
{
  "ok": true,
  "data": {}
}
```

Application-level error:

```json theme={null}
{
  "ok": false,
  "error": {
    "code": "INVALID_REQUEST",
    "message": "Human readable message"
  }
}
```

Platform-generated throttling or uncaught upstream errors may not use this envelope.

## Timestamps

The public API currently uses:

* Unix timestamps in milliseconds for most case and webhook timestamps
* ISO 8601 strings for attachment `expiresAt`

## Public Routes

| Method | Path                                     | Purpose                               |
| ------ | ---------------------------------------- | ------------------------------------- |
| `POST` | `/cases`                                 | Create and queue a new case           |
| `GET`  | `/cases/{id}`                            | Read the current public case state    |
| `GET`  | `/cases/{id}/attachments/{attachmentId}` | Mint a fresh file download URL        |
| `POST` | `/cases/{id}/input`                      | Provide human input for a paused case |

## Route Conventions

* `POST /cases` is asynchronous. It stores the case and queues internal processing.
* `GET /cases/{id}?includeTranscript=true` fetches and formats the live email thread.
* `POST /cases/{id}/input` returns `202` when the input was queued, not when the workflow has finished reprocessing it.
* `GET /cases/{id}` returns `inputRequest` when the case has an active or recently resolved input request stored on it.

## Status Model

| Status         | Meaning                                                       |
| -------------- | ------------------------------------------------------------- |
| `CREATED`      | Accepted and queued                                           |
| `RUNNING`      | Initial outreach, follow-up, or reply handling is in progress |
| `INPUT_NEEDED` | Waiting for your application to answer a question             |
| `COMPLETED`    | Goal achieved, with `result` available                        |
| `FAILED`       | Workflow stopped without success                              |

## Webhooks

If `clientWebhookUrl` is set on case creation, Offload sends:

* `case.completed`
* `case.failed`
* `case.input_needed`

See [Webhook Events](/api-reference/webhook-events) for the exact payloads and [Webhooks](/guides/webhooks) for delivery caveats.

## OpenAPI

The machine-readable spec lives at [openapi.json](/api-reference/openapi.json).
