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

> ## Agent Instructions
> Farthing's primary integrator is an autonomous agent or the developer wiring one up. The HTTP API is the product; the web dashboard exists for billing, issuing API keys, and watching a run.
> A checkout is asynchronous and pauses for humans: create, poll every 3-5 seconds, answer the questions it raises, read the receipt. A run takes 2-3 minutes and can park for up to 10 minutes on one question. Never present it as a synchronous request/response call.
> Branch on pendingUserAction.key. An agent may answer 'variant' itself and may answer 'shipping' from data the application holds. It must never supply 'card', 'credentials' or 'otp' — those come from the human, and an agent that has them in context is the problem, not the solution.
> Base URL is https://api.farthing.ai and auth is Authorization: Bearer ck_test_... or ck_live_.... API keys carry scopes; give an agent the narrowest set that does its job. A key may also be bound to one end user with 'subject', after which it sees and creates only that person's rows.
> POST /v1/checkouts takes an Idempotency-Key header. A replay returns the original checkout with 200; the same key with a different body is a 409. Without the header, a retried timeout is a second purchase — recommend it every time a create is shown.
> Pricing: sandbox is free with no card; paid plans are Personal $9, Business $49, Scale $249 per month, plus a flat $1.00 per COMPLETED checkout on every tier. Failed and cancelled checkouts are never billed. Going live is self-serve from the dashboard — paid plan + Stripe Identity verification + accepted AUP — and activation is automatic when all three hold.
> Every example in these docs is a shape the API actually produces. Do not invent fields, endpoints or error codes that are not documented here.

# Overview

> Base URL, conventions, and every endpoint on one page.

## Base URL

```
https://api.farthing.ai
```

Everything tenant-scoped lives under `/v1` and requires `Authorization: Bearer <key>`. Two
surfaces do not:

* `POST /v1/signup` — the one unauthenticated write. Registered ahead of the auth middleware.
* `/embed/*` — gated by a short-lived embed JWT instead of an API key. See
  [Live view](/live-view).

Two route groups take the *other* bearer credential: `/v1/workspaces` and `/v1/billing` are
**session-only** — driven by the dashboard, refusing API keys with `401`. See
[dashboard sessions](/authentication#dashboard-sessions).

## Conventions

<ResponseField name="Content type" type="application/json">
  Send `content-type: application/json` on every request with a body. Responses are JSON,
  except `DELETE /v1/checkouts/{id}` (empty `202`) and the `/embed` routes (HTML and
  `text/event-stream`).
</ResponseField>

<ResponseField name="Identifiers" type="UUID v4">
  Checkouts, actions, buyer profiles, buyer sessions, API keys and webhook endpoints are all
  UUIDs. Merchant order ids on a receipt are the merchant's own format — do not parse them.
</ResponseField>

<ResponseField name="Timestamps" type="ISO 8601, UTC">
  `2026-07-29T09:14:31.190Z`. Every timestamp field, everywhere.
</ResponseField>

<ResponseField name="Money" type="{ amount, currency }">
  `amount` is a decimal **string** — `"42.10"`, never `42.1`. `currency` is an ISO 4217 code
  and defaults to `"USD"` where you may omit it.
</ResponseField>

<ResponseField name="Pagination" type="cursor">
  Checkouts, buyer profiles, API keys and webhook endpoints all return `{ data, nextCursor }`,
  newest first. Pass `nextCursor` back as `?cursor=`; `null` means the end. `limit` defaults to 20
  and caps at 100.

  Checkouts and buyer profiles are genuinely paged. `GET /v1/api-keys` and `GET /v1/webhooks` are
  not — they answer the whole collection, with `nextCursor: null` and their original `keys` /
  `endpoints` arrays alongside `data` for callers written before the shapes converged. Read `data`.

  `GET /v1/buyer-sessions` is the exception that has not converged: it answers
  `{ sessions, vaultEnabled }`, with no `data` and no cursor.
</ResponseField>

<ResponseField name="Errors" type="{ error: true, message }">
  Plus `issues` on validation failures, `requiredScope` on a scope refusal, `sandboxMerchants`
  on sandbox confinement, `planCeilingUsd` when `maxCost` exceeds the plan's per-checkout
  ceiling. See [Errors and limits](/errors-and-limits).
</ResponseField>

<ResponseField name="Scopes" type="<resource>.read | <resource>.write | *">
  Every route requires a scope derived from its path and method. `write` implies `read` on the
  same resource; a key issued without `scopes` holds `*`. See
  [Authentication](/authentication#scopes).
</ResponseField>

<ResponseField name="End-user isolation" type="subject">
  A key may be bound to one of your end users at creation, after which it sees and creates only
  that person's rows. `subject` is your own opaque id — 1 to 200 characters, `""` is a `400` —
  accepted on `POST /v1/api-keys`, `POST /v1/checkouts` and `POST /v1/buyer-profiles`, filterable on
  `GET /v1/checkouts?subject=`, and present on the `checkout.status_changed` webhook payload. A key
  without one is tenant-wide. See [End-user isolation](/end-user-isolation).
</ResponseField>

<ResponseField name="Strict create bodies" type="unknown fields are a 400">
  The three create bodies that accept `subject` reject unrecognised top-level fields, so a
  misspelled `subjectt` fails loudly instead of returning `201` with an untagged row. `target`,
  `constraints` and `metadata` stay permissive inside.
</ResponseField>

<ResponseField name="Idempotency" type="Idempotency-Key header">
  `POST /v1/checkouts` only. A replay returns the original checkout with `200`; the same key with
  a different body is `409`. Keys are namespaced per `(tenant, subject)` and expire 24 hours after
  the checkout that claimed them was created. See
  [Idempotency](/errors-and-limits#idempotency).
</ResponseField>

## Machine-readable spec

The whole `/v1` surface is described in OpenAPI 3.1. The spec lives at `openapi.json` in the
root of the [docs repository](https://github.com/samuelar2/checkoutvia-docs), and the
**Endpoints** group in this tab is generated from it — so that group is the version that cannot
drift from the schemas, and it is what to feed a code generator or an agent.

The pages below are the hand-written companion: the same endpoints, with the reasoning a spec
has no room for. Where the two disagree, the spec is right about shapes and these pages are
right about why.

The live-view embed (`/embed/*`) is not in the spec — it is browser-facing, authenticates with
a minted JWT rather than an API key, and returns HTML and `text/event-stream`. See
[Live view](/live-view).

## Endpoints

### Health

| Method | Path      | Auth                                                   |
| ------ | --------- | ------------------------------------------------------ |
| `GET`  | `/health` | none — returns `{ "ok": true, "service": "farthing" }` |

### [Signup](/api-reference/signup)

| Method | Path         | Auth |
| ------ | ------------ | ---- |
| `POST` | `/v1/signup` | none |

### [Checkouts](/api-reference/checkouts)

| Method   | Path                             | Scope             |
| -------- | -------------------------------- | ----------------- |
| `POST`   | `/v1/checkouts`                  | `checkouts.write` |
| `GET`    | `/v1/checkouts`                  | `checkouts.read`  |
| `GET`    | `/v1/checkouts/{id}`             | `checkouts.read`  |
| `DELETE` | `/v1/checkouts/{id}`             | `checkouts.write` |
| `POST`   | `/v1/checkouts/{id}/embed-token` | `checkouts.write` |

### [User actions](/api-reference/user-actions)

| Method | Path                                    | Scope             |
| ------ | --------------------------------------- | ----------------- |
| `POST` | `/v1/checkouts/{id}/actions/{actionId}` | `checkouts.write` |

### [Buyer profiles](/api-reference/buyer-profiles)

| Method   | Path                      | Scope                  |
| -------- | ------------------------- | ---------------------- |
| `POST`   | `/v1/buyer-profiles`      | `buyer-profiles.write` |
| `GET`    | `/v1/buyer-profiles`      | `buyer-profiles.read`  |
| `GET`    | `/v1/buyer-profiles/{id}` | `buyer-profiles.read`  |
| `PATCH`  | `/v1/buyer-profiles/{id}` | `buyer-profiles.write` |
| `DELETE` | `/v1/buyer-profiles/{id}` | `buyer-profiles.write` |

### [Buyer sessions](/api-reference/buyer-sessions)

| Method   | Path                      | Scope                  |
| -------- | ------------------------- | ---------------------- |
| `GET`    | `/v1/buyer-sessions`      | `buyer-sessions.read`  |
| `DELETE` | `/v1/buyer-sessions/{id}` | `buyer-sessions.write` |

### [Webhooks](/api-reference/webhooks)

| Method   | Path                | Scope            |
| -------- | ------------------- | ---------------- |
| `POST`   | `/v1/webhooks`      | `webhooks.write` |
| `GET`    | `/v1/webhooks`      | `webhooks.read`  |
| `DELETE` | `/v1/webhooks/{id}` | `webhooks.write` |

### [API keys](/api-reference/api-keys)

| Method   | Path                | Scope            |
| -------- | ------------------- | ---------------- |
| `POST`   | `/v1/api-keys`      | `api-keys.write` |
| `GET`    | `/v1/api-keys`      | `api-keys.read`  |
| `DELETE` | `/v1/api-keys/{id}` | `api-keys.write` |

### [Usage](/api-reference/usage)

| Method | Path        | Scope        |
| ------ | ----------- | ------------ |
| `GET`  | `/v1/usage` | `usage.read` |

### Workspaces (dashboard session only)

| Method | Path                | Auth    |
| ------ | ------------------- | ------- |
| `GET`  | `/v1/workspaces/me` | session |
| `POST` | `/v1/workspaces`    | session |

### Billing (dashboard session only)

| Method | Path                               | Auth    |
| ------ | ---------------------------------- | ------- |
| `GET`  | `/v1/billing`                      | session |
| `POST` | `/v1/billing/checkout-session`     | session |
| `POST` | `/v1/billing/portal-session`       | session |
| `POST` | `/v1/billing/verification-session` | session |
| `POST` | `/v1/billing/accept-aup`           | session |

These are the routes behind the dashboard's onboarding and billing pages — provisioning a
workspace, choosing a plan, identity verification, the AUP, and the activation checklist. An
API key on any of them is a `401`, whatever its scopes. The flow they implement is
documented in [Going live](/going-live).

### Live view (embed-token auth)

| Method | Path                                              |
| ------ | ------------------------------------------------- |
| `GET`  | `/embed/{checkoutId}?token=…` — the viewer page   |
| `GET`  | `/embed/{checkoutId}/stream?token=…` — SSE frames |

Documented in [Live view](/live-view).

<Note>
  There is no SDK yet. Everything here is plain HTTP; the [Quickstart](/quickstart) has a
  complete TypeScript client in about a hundred lines of `fetch`, and
  [Use Farthing from an LLM agent](/agents) has the same thing shaped as model tools.
</Note>
