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

# Billing state and the activation checklist

> Where the workspace is on the road to live: plan, verification, AUP, subscription, the limits in force, and `remaining` — exactly what still stands between this workspace and activation.



## OpenAPI

````yaml /openapi.json get /v1/billing
openapi: 3.1.0
info:
  title: Farthing API
  version: 1.0.0
  summary: >-
    Agentic checkout. Give it a product URL and a plain-English request; it
    drives a real browser to a completed purchase and asks a human only when it
    must.
  description: >-
    The HTTP API is the product. Everything an integration needs — creating
    checkouts, answering the questions a run stops on, storing buyers, issuing
    scoped keys — is here.


    A checkout is asynchronous and pauses for humans. `POST /v1/checkouts`
    returns in milliseconds with a `queued` object; the run itself takes minutes
    and may park on a `pendingUserAction` for up to ten. Poll `GET
    /v1/checkouts/{id}` (unmetered) or register a webhook endpoint.


    Not covered by this spec: the live-view embed (`GET /embed/{checkoutId}` and
    `GET /embed/{checkoutId}/stream`). Those are consumed by a browser,
    authenticate with a short-lived JWT minted at `POST
    /v1/checkouts/{id}/embed-token` rather than with an API key, and return HTML
    and `text/event-stream`.


    Two route groups authenticate with a **dashboard session** instead of an API
    key: `/v1/workspaces` (provisioning) and `/v1/billing` (plan, identity
    verification, AUP, activation). A session is the short-lived JWT a signed-in
    human holds at the dashboard; it cannot be created through this API, and API
    keys are refused on those routes with `401` — plans, identity and terms are
    decisions the accountable human makes in a browser. Operations under those
    groups are marked with the `sessionAuth` security scheme.
  contact:
    name: Farthing
    url: https://docs.farthing.ai
servers:
  - url: https://api.farthing.ai
    description: Production
security:
  - bearerAuth: []
tags:
  - name: Signup
    description: Self-serve account creation. The only unauthenticated write on the API.
  - name: Checkouts
    description: Create a run, poll it, cancel it, and answer what it asks.
  - name: Buyer profiles
    description: >-
      Reusable identity and shipping details, referenced by id when creating a
      checkout.
  - name: Buyer sessions
    description: >-
      Stored merchant logins captured by a `credentials` action. Read-only
      metadata and revocation.
  - name: Webhooks
    description: >-
      Endpoints that receive `checkout.status_changed` with an HMAC-SHA256
      signature.
  - name: API keys
    description: >-
      Self-serve key issuance and revocation. Keys carry scopes; a key can never
      mint one broader than itself.
  - name: Usage
    description: Completed checkouts by day, and gross merchandise volume by currency.
  - name: Workspaces
    description: >-
      Dashboard-session workspace provisioning. One workspace per account; the
      first request of a fresh sign-in is “do I have a workspace?” and the
      second is “make me one”.
  - name: Billing
    description: >-
      Dashboard-session billing: plan, identity verification, AUP, and the
      activation checklist. Session-only — an agent's key completes checkouts,
      it does not choose subscription plans.
  - name: Health
    description: Liveness.
paths:
  /v1/billing:
    get:
      tags:
        - Billing
      summary: Billing state and the activation checklist
      description: >-
        Where the workspace is on the road to live: plan, verification, AUP,
        subscription, the limits in force, and `remaining` — exactly what still
        stands between this workspace and activation.
      operationId: getBilling
      responses:
        '200':
          description: The billing state.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BillingState'
              examples:
                sandbox:
                  summary: Fresh workspace, nothing done yet
                  value:
                    plan: sandbox
                    live: false
                    verificationStatus: unverified
                    aupAcceptedAt: null
                    hasSubscription: false
                    limits:
                      concurrentCheckouts: null
                      maxCheckoutCostUsd: null
                    remaining:
                      - choose_plan
                      - verify_identity
                      - accept_aup
                live:
                  summary: Live on Personal
                  value:
                    plan: personal
                    live: true
                    verificationStatus: verified
                    aupAcceptedAt: '2026-08-01T10:22:41.055Z'
                    hasSubscription: true
                    limits:
                      concurrentCheckouts: 1
                      maxCheckoutCostUsd: '200'
                    remaining: []
        '401':
          $ref: '#/components/responses/SessionRequired'
        '403':
          description: >-
            A valid session with no workspace yet (`code: "no_workspace"`), or a
            suspended tenant.
          content:
            application/json:
              schema:
                anyOf:
                  - $ref: '#/components/schemas/CodedError'
                  - $ref: '#/components/schemas/Error'
              examples:
                noWorkspace:
                  value:
                    error: true
                    message: No workspace for this account
                    code: no_workspace
                suspended:
                  value:
                    error: true
                    message: Tenant suspended
      security:
        - sessionAuth: []
components:
  schemas:
    BillingState:
      type: object
      description: >-
        Where the workspace is on the road to live. `remaining` names what still
        stands between it and activation — the dashboard renders this as the
        checklist rather than deriving it client-side.
      required:
        - plan
        - live
        - verificationStatus
        - aupAcceptedAt
        - hasSubscription
        - limits
        - remaining
      properties:
        plan:
          type: string
          description: '`sandbox`, or a paid plan: `personal`, `business`, `scale`.'
        live:
          type: boolean
          description: Whether the workspace is activated (not sandbox-only).
        verificationStatus:
          type: string
          enum:
            - unverified
            - pending
            - verified
            - rejected
        aupAcceptedAt:
          type:
            - string
            - 'null'
          format: date-time
        hasSubscription:
          type: boolean
        limits:
          type: object
          required:
            - concurrentCheckouts
            - maxCheckoutCostUsd
          properties:
            concurrentCheckouts:
              type:
                - integer
                - 'null'
              description: >-
                `null` until activation applies the plan's number; the platform
                default (5) holds in the meantime.
            maxCheckoutCostUsd:
              type:
                - string
                - 'null'
              description: >-
                The per-checkout spend ceiling as a decimal string — `"200"` on
                Personal. `null` on plans without a ceiling.
        remaining:
          type: array
          items:
            type: string
            enum:
              - choose_plan
              - verify_identity
              - accept_aup
          description: Empty once the workspace is live.
    CodedError:
      type: object
      description: >-
        An error with a machine-readable `code`, used only by the session-only
        workspace routes so the dashboard can key its onboarding off it.
      required:
        - error
        - message
        - code
      properties:
        error:
          type: boolean
          const: true
        message:
          type: string
        code:
          type: string
          enum:
            - no_workspace
            - workspace_exists
    Error:
      type: object
      title: Error
      description: >-
        Every error is this object. There are no error codes: match on the HTTP
        status, treat `message` as text for a human.
      required:
        - error
        - message
      properties:
        error:
          type: boolean
          const: true
        message:
          type: string
  responses:
    SessionRequired:
      description: >-
        The credential was an API key (or missing, or an unverifiable session
        token). This surface is session-only — an agent's key must not be able
        to make billing and membership decisions.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          examples:
            apiKey:
              value:
                error: true
                message: This endpoint requires a dashboard session, not an API key
            badSession:
              value:
                error: true
                message: 'Invalid session token: "exp" claim timestamp check failed'
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: >-
        `Authorization: Bearer ck_test_…` or `ck_live_…`. There is no other auth
        scheme — no query-string keys, no request signing, no OAuth.
    sessionAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: >-
        A dashboard session — the short-lived JWT a signed-in human holds at the
        dashboard, sent on the same `Authorization: Bearer` header. Dispatched
        by shape: a session token is a JWT, an API key starts with `ck_`.
        Sessions cannot be created through this API, and operations that list
        only this scheme refuse API keys with `401`.

````