API reference

The Tab Authority REST surface, versioned under /api/v1. Agent endpoints authenticate with a tab-scoped key: Authorization: Bearer molt_sk_test_.... Errors are JSON: {error: "code", ...detail}. All amounts are integer minor units (cents).

GET /api/v1/health auth: none

Liveness and the mode gate result.

200 {ok, service, mode:"test"}

POST /api/v1/tabs auth: none

Start opening a tab. Returns the ceremony URL for the human owner; agents cannot self-authorize.

200 {ceremony_url, message}

GET /api/v1/tabs/:id auth: agent key

Tab status: budget, remaining, expiry, the root bounds and task declaration.

200 · 401 · 404

POST /api/v1/tabs/:id/mandates auth: agent key

Request a child mandate for one cart: merchant_origin, amount_minor, cart_hash, reason, optional mcc and items_summary. Policy decides (auto / notify / hold for tap / block), the narrowing engine enforces the invariant, budget and velocity are atomic.

201 active {mandate_id, parent_id, bounds, card (one-time)} · 202 held {mandate_id, message} · 403 blocked_by_policy · 409 tab_not_active/budget · 422 narrowing_violation · 429 velocity

GET /api/v1/mandates/:id auth: agent key

Mandate status; the polling target for held mandates. Card details are delivered exactly once, on the first read after approval.

200 {status, bounds, cart_hash, parent_id, card|null} · 404

DELETE /api/v1/mandates/:id auth: agent key

Shed an unworn shell: cancels an unused child mandate, the card dies, the reserved amount returns to the tab.

200 {ok, status:"revoked"} · 404 · 409 mandate_not_cancelable

POST /api/v1/mandates/:id/receipt auth: agent key

File the dual-signed receipt. The agent generates id and created_at, signs the canonical body; the TA verifies, enforces mandate constraints and idempotency, countersigns, and returns the complete SignedReceipt.

201 {ok, receipt: SignedReceipt} · 400 · 409 mandate_not_usable/duplicate_idempotency_key · 422 amount/merchant/currency/chain/signature

GET /api/v1/tabs/:id/receipts auth: agent key

All receipts for the tab, newest first.

200 {receipts: [...]}

Filing a receipt

POST /api/v1/mandates/:id/receipt
{
  "receipt": {
    "id": "<uuid, agent-generated>",
    "tab_id": "...", "mandate_id": "...",
    "rung": "L1", "rail": "card_stripe_test",
    "merchant": "https://store.example.com",
    "amount_minor": 3400, "currency": "EUR",
    "evidence": {"dom_sha256": "...", "screenshot_sha256": "..."},
    "idempotency_key": "<sha256(tab|merchant|cart_hash)>",
    "mandate_chain": ["<root id>", "<child id>"],
    "created_at": "<ISO 8601, within 10 minutes>"
  },
  "agent_signature": "<ed25519 over canonical JSON of receipt>",
  "agent_public_key": "<SPKI PEM>"
}

The response embeds ta_signature and ta_public_key; the document verifies offline with npx molt verify receipt.json, no network and no database needed.