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

# API conventions

> Base URLs, versioning, formats, and idempotency: the rules that hold across every endpoint.

## Base URL & environments

```
Production   https://api.flightlinehq.com/v1
```

There is no separate sandbox host. **Sandbox (test mode) is selected by your
API key**. A sandbox key returns instant, canned results and runs no real
analysis. See [Sandbox](/sandbox).

## Versioning & deprecation

The API is versioned in the path (`/v1`). Within a version we only
make **backward-compatible** changes:

* **Additive, non-breaking** (safe, may ship anytime): new endpoints, new
  optional request fields, new fields in responses, new `status`/`severity`
  enum values, new error codes.
* **Breaking** (new version + advance notice): removing or renaming a field,
  changing a field's type, or removing an endpoint.

Build your integration to **ignore unknown response fields** and tolerate new
enum values, so additive changes never break you. Breaking changes ship under
a new version path with deprecation notice; we won't remove `v1` out from
under you.

## Formats

* **Timestamps**: ISO 8601, UTC (`2026-05-30T18:09:12Z`).
* **Identifiers**: `review_id` is a UUID. Use your own `reference_id` (any
  string) to correlate to your system of record.
* **Content types**: JSON request/response (`application/json`), except
  `POST /reviews`, which also accepts `multipart/form-data` for file uploads.

## Idempotency

There are two distinct mechanisms; they solve different problems.

**`Idempotency-Key` header (safe retries).** Send
`Idempotency-Key: <your-unique-key>` on `POST /reviews` to make the request
safely retryable. If a retry with the same key reaches us (for example after a
network timeout where you never saw the response), we return the ORIGINAL
review with HTTP `200 OK` instead of creating a duplicate; the expensive
review pipeline runs exactly once. Choose a fresh, unique key per logical
create request (a UUID works well); the key may be up to 255 characters. Keys
are scoped to your organization, so they never collide with another org's
keys. A first create returns `201 Created`; a replayed retry returns
`200 OK`, which is how you tell the two apart.

**`reference_id` field (deduplication).** Set `reference_id` to your own
external identifier for the loan package. Creating a second review with a
`reference_id` that already exists returns `409 Conflict`; this rejects the
duplicate rather than replaying it. Use `reference_id` to correlate a review
to your system of record and to guarantee one review per loan package; use the
`Idempotency-Key` header to retry a single create call without fear of
double-submitting.

## Documents

`POST /reviews` accepts full case packages and individual documents.

Accepted package formats: `.zip`, `.tar`, `.tar.gz`, `.tgz`.

Accepted document formats, either uploaded individually or inside a package:
PDF, PNG, JPG/JPEG, TIFF/TIF, WEBP, GIF, BMP.

Not accepted: RAR/7z archives, nested archives, executables, scripts, Office
files, spreadsheets, email containers, password-protected archives, corrupt
archives, empty files, and unsupported MIME types. There are per-file and
per-review size/count limits; oversize or unsupported files return `4xx` with
a clear message.

## Pagination

List endpoints are cursor-paginated. `GET /reviews` returns the organization's
reviews newest first, controlled by two query parameters:

| Parameter | Default | Notes                                                                           |
| --------- | ------- | ------------------------------------------------------------------------------- |
| `limit`   | `20`    | Maximum results per page; 1 to 100.                                             |
| `cursor`  | (none)  | Opaque token from a previous response's `next_cursor`. Omit for the first page. |

Each response is a page object:

```json theme={null}
{
  "data": [ /* reviews, newest first */ ],
  "next_cursor": "MjAyNi0wNS0zMFQxNzowMDowMCswMDowMHw5YjJjMWYzYQ=="
}
```

When `next_cursor` is non-null, pass it back as the `cursor` query parameter to
fetch the next page; when it is `null`, you have reached the last page. Treat
the cursor as an opaque token: pass it back verbatim, do not parse or construct
it. A malformed `cursor` returns `422` with the `invalid_request` code.
