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. In the dashboard, open Developers → API keys in the sidebar and click Generate Test Key (in test mode) or Generate Live Key (in live mode).
A missing or invalid key returns 401 Unauthorized, with the message Missing or invalid authentication. Server-to-server calls always send the key in x-api-key; API keys have no bearer-token form. A key stops working when the person who created it is no longer an owner or admin of the business. The server then returns 401 with the code key_no_longer_valid:
401
Only the CLI’s browser login session sends Authorization: Bearer: the agenta CLI signs in through your browser and sends a session token as Authorization: Bearer <token>, not an API key. A request made with a session token runs in test mode unless it sends the header X-Environment: live. Use an API key for your own servers and scripts.

Acting for a business

A platform can call any endpoint as a business it manages. Send the business’s id in the AgentaOS-Account header, and the request runs as that business: the checkout, product or invoice is the business’s, not yours.
string
The id of a business you manage. Leave it out, or send your own id, to act as yourself.
Only a platform’s key, or a signed-in owner or admin of the platform, may send it, and only for a business that platform manages. Any other value (another platform’s business, an account nobody manages, an id that does not exist) returns the same 403:
403
A header that is present but empty returns 400 with the message AgentaOS-Account must name a business. The SDK sends this header for you with { business } and the CLI with --business <id>. See Acting for a business.

Test and live keys

The key’s prefix sets the mode of the request. There is no mode parameter. Test data and live data are separate. A test key reads and writes only records created with a test key, and a live key only records created with a live key. A record from the other mode returns 404, as if it did not exist. See Test mode and testing.

Request format

Send request bodies as JSON with Content-Type: application/json. Body fields are camelCase, for example successUrl, billingInterval and trialPeriodDays. The server rejects a field that the endpoint does not define with a 400, so check the spelling of every field. A body larger than 512 KB is rejected.

Pagination

The list endpoints GET /gateway/payment-links, /sessions, /subscriptions, /customers, /invoices and /all-transactions page with limit and offset and return the same envelope. There is no cursor.
number
default:"20"
Items per page. The server caps it at 100 on payment links, checkouts, subscriptions and customers, and at 1000 on invoices and transactions. A larger value returns the capped number of items without an error.
number
default:"0"
The number of items to skip. For the next page, add the number of items you received to the current offset.
Pagination envelope
array
The page of results. The shape depends on the resource.
number
The number of matching items across all pages.
boolean
true when offset plus the number of items on this page is less than total.
GET /gateway/businesses is not paged. It returns a plain array.

Naming convention

Most response fields are snake_case. A few computed fields are camelCase, and two resources are camelCase throughout. Responses have three kinds of fields:
A field stored on the record comes back in snake_case: 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.
The server computes these fields when it builds the response. They are camelCase and have no snake_case form:
  • 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 have no snake_case fields: Subscriptions (GET /gateway/subscriptions, POST /gateway/subscriptions/:id/cancel) and Customers (GET /gateway/customers). Every field on these two is camelCase.
The TypeScript SDK removes this mix: it camelCases every response, so checkoutUrl stays checkoutUrl and buyer_email becomes buyerEmail. Outside Node.js, read the tables on each page of this reference as the literal JSON keys the server sends.

Money model

AgentaOS writes money in three forms.
An amount you send is a decimal number in currency units: 49.99 means €49.99, never cents. The same holds for a plainly named amount in a response: a Payment Link’s amount, a Checkout’s amount_override, and an Invoice’s amount, fiat_amount and tax_amount.
A field whose name ends in Minor is an integer count of the smallest currency unit: 1999 means €19.99. Examples are unitAmountMinor on a Subscription, dueTodayMinor on a plan-change quote, amountMinor on a credit, and the fields of the money breakdown on a Transaction and the earnings breakdown on a retrieved Invoice.
In a webhook event’s data, amount is a string in currency units, e.g. "49.99", so the value keeps its trailing zeros. amount_minor on subscription and dispute events is an integer in minor units, like the Minor fields above. The SDK’s webhooks.verify() returns it as amountMinor.

Errors

An error response is JSON. Every response, success or error, has an x-request-id header, and an error body repeats it as requestId. Include it when you contact support.
400
number
The HTTP status code.
string | string[]
Human-readable text. A validation failure returns an array, one entry per problem.
string
ISO 8601 time of the error.
string
The same value as the x-request-id header.
string
A short category, such as Bad Request. Most errors have it; some, such as a 429, do not.
array
On a validation 400 only: one { field, message } per invalid field.
string
On some errors only: a stable, machine-readable code, such as key_no_longer_valid or account_on_hold. Branch on code when it is present, and on statusCode when it is not. Never branch on message, which can change.
The status codes and how to handle each are on Error codes.

Rate limits

The server counts requests per client IP address and per endpoint. The default limit is 60 requests per 60 seconds on each endpoint. These endpoints have a lower limit of 10 requests per 60 seconds:
  • POST /gateway/businesses
  • POST /gateway/businesses/:id/invitation
  • POST /gateway/businesses/:id/verification-link
Each response has the headers X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset (seconds until the count resets). Over the limit, the server returns 429 with a Retry-After header, in seconds:
429
Wait for the number of seconds in Retry-After, then send the request again. The SDK does this for you when Retry-After is 60 seconds or less. The count is per IP address and endpoint, so all the checkouts your server creates share one budget: 60 POST /gateway/sessions calls per minute, across all your buyers. Create a checkout when a buyer asks to pay, not on every page view.

Idempotency

Two endpoints read the Idempotency-Key header: No other endpoint reads the header. If a create request times out and you send it again, for example POST /gateway/payment-links, the server can create the record twice. Before you retry such a request, list the resource and check whether the first request succeeded. The SDK sends a new random Idempotency-Key on every POST call, and uses the same key when it retries that call after a 429, a 5xx or a network error. You cannot choose the key: RequestOptions has no idempotencyKey. The one exception is subscriptions.credit(), which requires you to pass idempotencyKey. On the two endpoints above, a retry is safe. On other endpoints, the retry can create a duplicate. The server does not answer a repeated key with 409: it returns the first result. A 409 Conflict means the request conflicts with the record’s current state, for example a checkout changed by another request, or a product at its purchase limit. The SDK throws every 409 as IdempotencyError, whatever the cause, so read its message.

Versioning

The API version is in the path: every endpoint is under /api/v1. The SDK (@agentaos/pay) and the CLI (agentaos) are published on npm with semantic version numbers. Pin the version you tested with, and read the changelog before you upgrade.

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.