Skip to main content
The AgentaOS REST API lets you create payment links, checkouts, and invoices, read subscriptions, customers, and transactions, and receive webhooks, from any language. It is the same API the TypeScript SDK and the agenta CLI call underneath.
Building in TypeScript or Node.js? Use @agentaos/pay instead of raw HTTP. It wraps every endpoint on this page with typed methods, camelCases responses for you, retries on 5xx, and signs/verifies webhooks. This section documents the wire format the SDK talks to, useful if you’re integrating from another language or debugging a raw request.

Base URL

Every path in this reference is relative to this base. POST /gateway/payment-links means POST https://api.agentaos.ai/api/v1/gateway/payment-links.

Authentication

Send your secret key in the x-api-key header on every request.
string
required
Your secret key, from app.agentaos.ai → Settings → Developers → API Keys.
A missing or invalid key returns 401 Unauthorized. There’s no separate bearer-token flow for API keys, only the CLI’s browser login session uses Authorization: Bearer internally; server-to-server integrations always use x-api-key.

Environments (test vs live)

A key’s prefix is both its identity and its environment. There’s no separate “mode” parameter to set. Test and live data never mix: a request authenticated with a test key can only see payment links, checkouts, invoices, customers, and transactions created under a test key, and the same is true for live. See Test mode and live mode for how to get a key of each kind.

Pagination

Every list endpoint (GET /gateway/payment-links, /sessions, /subscriptions, /customers, /invoices, /all-transactions) takes the same two query parameters and returns the same envelope.
number
default:"20"
Items per page. Capped server-side at 100 (invoices cap at 5000 for CSV-style bulk export via limit).
number
default:"0"
Number of items to skip, for the next page.
Pagination envelope
array
The page of results. Shape depends on the resource.
number
Total matching rows across every page, not just this one.
boolean
true if offset + items.length < total. Computed server-side, don’t derive it yourself.
hasMore is camelCase on the wire, not has_more. It’s a computed envelope field, not a database column, see Naming convention below for why that matters.

Naming convention

Most response fields mirror the underlying data and are snake_case. A handful of computed fields ride along already camelCase, and two resources are fully camelCase. In practice, three kinds of fields appear on responses:
Anything stored on the record comes back exactly as named in the database: created_at, amount_override, billing_interval, buyer_email, tax_rate_id, and so on. This is the majority of fields on Payment Links, Checkouts, and Invoices.
A small number of fields are built by the server at response time rather than read from a column, and those are camelCase as written, with no snake_case equivalent:
  • checkoutUrl on Checkouts and Payment Links
  • money (an object: currency, grossMinor, feeMinor, vatMinor, netMinor) on Transactions
  • earnings (an object: currency, grossMinor, agentaosFeeMinor, vatMinor, netMinor) on a single retrieved Invoice, same shape as money except the fee field is named agentaosFeeMinor instead of feeMinor
Two resources are hand-built end to end and never expose a snake_case column name: Subscriptions (GET /gateway/subscriptions, POST /gateway/subscriptions/:id/cancel) and Customers (GET /gateway/customers). Every field on these two is camelCase.
If any of this sounds like a footgun for a hand-rolled HTTP client, it is exactly why the TypeScript SDK exists. It recursively camelCases every response, so checkoutUrl and buyer_email both come back as checkoutUrl/buyerEmail on the SDK object regardless of which convention the wire used underneath. If you’re not on Node.js, treat the tables on each page in this reference as the literal JSON keys, they’re taken directly from what the server sends.

Money model

A plain amount field, on a create body, a Payment Link, a Checkout’s amount_override, or an Invoice’s amount/fiat_amount/tax_amount, is in currency units. 49.99 means €49.99, never cents.
The decimal rule above applies to plainly-named amount fields only. Any field whose name ends in Minor is an integer count of the smallest currency unit instead: unitAmountMinor on a Subscription (1999 means €19.99), plus every field inside the money breakdown on a Transaction and the earnings breakdown on a retrieved Invoice (grossMinor, feeMinor/agentaosFeeMinor, vatMinor, netMinor). The Minor suffix is the signal, it’s there so these are never confused with a plain decimal amount.
The amount inside a webhook payload’s data object is a string, e.g. "49.99", since JSON numbers silently drop trailing zeros and this value has to round-trip exactly for accounting.

Errors

A non-2xx response is always JSON, and every response carries an x-request-id header (echoed as requestId in the body):
400
number
Same as the HTTP status code.
string
Short category, e.g. Bad Request.
string | string[]
Human-readable. A validation failure returns an array, one entry per problem.
array
On a 400 validation error, one { field, message } per invalid field.
string
ISO 8601, when the error was generated.
string
Correlation ID, also returned as the x-request-id header.
On a 400, errors gives you per-field detail ([{ field, message }]) and message carries the same problems as human-readable text. The SDK surfaces these as ValidationError.errors and AgentaOSError.requestId. See Error codes.

Rate limits

60 requests per 60 seconds per client IP, by default, across every endpoint in this reference. A small number of unlisted, higher-risk endpoints (outbound sends, public checkout start) have a tighter dedicated limit; none of the endpoints documented in this section do. A 429 doesn’t currently include a guaranteed Retry-After header. Back off and retry (the SDK does this automatically, waiting 1 second by default before its single built-in retry on 429).

Idempotency

POST /gateway/sessions accepts an Idempotency-Key header (or an idempotencyKey field in the body). Retry the same call with the same key and you get back the exact same checkout, including its already-issued invoice, instead of creating a second one. The SDK generates a random key automatically on every POST if you don’t supply one.

Next steps

Payment Links

Create, list, update, and cancel reusable payment links.

Checkouts

Create a one-time checkout session, standalone or from a link.

Webhooks

Events, payload shapes, and signature verification.

TypeScript SDK

Skip the wire format entirely and use typed methods.