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
POST /gateway/payment-links means POST https://api.agentaos.ai/api/v1/gateway/payment-links.
Authentication
Send your secret key in thex-api-key header on every request.
string
required
Your secret key, from app.agentaos.ai → Settings → Developers → API Keys.
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 aresnake_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:
Persisted fields → snake_case
Persisted fields → snake_case
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.Computed convenience fields → camelCase, added on top
Computed convenience fields → camelCase, added on top
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:
checkoutUrlon Checkouts and Payment Linksmoney(an object:currency,grossMinor,feeMinor,vatMinor,netMinor) on Transactionsearnings(an object:currency,grossMinor,agentaosFeeMinor,vatMinor,netMinor) on a single retrieved Invoice, same shape asmoneyexcept the fee field is namedagentaosFeeMinorinstead offeeMinor
Fully camelCase resources
Fully camelCase resources
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.Money model
Decimal currency units (number)
Decimal currency units (number)
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.Integer minor units (number)
Integer minor units (number)
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.String, on webhooks
String, on webhooks
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 anx-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.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. A429 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.