External clients can create and fund an API-only Ambient account without an email, browser login, wallet login, or the Ambient UI. The Ambient API key is the account credential. A wallet is used only to authorize the x402 payment.
See the restart-safe TypeScript x402 subscription example for a working client.
The integration has six steps:
- Register with
POST /billing/x402/register-and-subscribe. - Securely save the one-time-displayed API key before paying.
- Send the opaque
payment_urlwith an x402 v2 client and select a live Solana or Base offer. - Save the payment receipt and both Ambient grant headers, then call
POST /billing/x402/subscription-complete. - Use the API key for inference and key management.
- Use the same API key to create future renewal intents.
The billing API origin is https://api.ambient.xyz. After provisioning,
configure OpenAI-compatible clients with:
Base URL: https://api.ambient.xyz/v1
Authorization: Bearer <api_key>Supported inference endpoints include POST /responses,
POST /chat/completions, and GET /models relative to that base URL.
Credentials and addresses#
- Ambient API key: bearer credential for the API-only Ambient account; it never authorizes a blockchain transfer.
- Wallet private key or signer: authorizes the x402 payment and stays inside the client's secure wallet boundary. Never send it to Ambient or Jumpgate.
- Payer address: public wallet address recorded in the settlement receipt; it is payment metadata, not an Ambient login.
- USDC asset: the Base token contract or Solana mint identifying the accepted currency.
- Payment recipient (
payTo): public Base or Solana address receiving USDC. Validate it against the trusted allowlist below. - Ambient grant and signature: short-lived opaque credentials proving a settled order to the completion endpoint; they are not API keys.
If you need one-off inference without creating an account or API key, use the separate account-free x402 client flow.
Plans, duration, and expiry#
Supported plan_id values are:
starterbasicpowerpro
See Ambient pricing for current monthly prices
and plan allowances. The signed order and live 402 determine the exact amount
for a purchase.
months is an integer from 1 through 12 and defaults to 1. A bulk
purchase is charged at the monthly price multiplied by months; there is no
bulk discount. Each month is provisioned as a consecutive monthly period so its
allowance resets independently.
Renewals must use the plan at the account's farthest paid-through boundary. Ambient rejects a different plan before creating a payment order. When an order is created, all nonexpired current and future periods, unexpired pending orders, and the requested purchase may not exceed 12 months in total. A valid grant settled earlier can exceptionally take the account past that cap if it completes later; Ambient honors paid value instead of discarding the settlement.
Registration and renewal payment URLs expire after 24 hours. That is not the payment authorization lifetime: create the authorization immediately before transmission and obey the shorter live rail-specific validity window. Base challenges currently use a 300-second authorization window; Solana blockhash validity is shorter and dynamic. A grant created by a successful settlement expires after seven days. An expired pending order becomes eligible for cleanup eight days after its payment URL expired; cleanup is asynchronous, so do not use retention as a payment or completion deadline.
Client safety#
Persist the registration response and API key before paying. Serialize concurrent payment attempts and maintain at most one live or possibly transmitted authorization for an order. An expired authorization may be replaced only when durable state proves it was never marked attempted; never replace one after transmission was attempted or became ambiguous.
Persist the raw response status and headers, including any receipt and grant,
as soon as fetch resolves; read and store the body afterward as diagnostic
data. Jumpgate is stateless, and Ambient does not expose a public
settlement-status or grant-recovery endpoint.
For compile-tested TypeScript reference code with injected signer, durable storage, and locking boundaries, see Restart-safe TypeScript x402 subscription example.
Lifecycle#
Register#
Registration is public and does not use an Ambient credential:
POST https://api.ambient.xyz/billing/x402/register-and-subscribe Content-Type: application/json { "plan_id": "basic", "months": 3 }A successful request returns
201 CreatedandCache-Control: no-store:{ "api_key": "<50-character Ambient API key>", "order_id": "7592578c-37b3-441e-a97c-7d262ebc0a72", "plan_id": "basic", "months": 3, "payment_url": "https://jumpgate.ambient.xyz/paid/subscription/v2/basic/3/7592578c-37b3-441e-a97c-7d262ebc0a72?intent=<opaque>", "expires_at": "<RFC 3339 timestamp about 24 hours after registration>", "completion_url": "/billing/x402/subscription-complete" }Registration creates a pending order containing the bootstrap key prefix and hash. It does not create the API-only team, activate the key, or add subscription periods until a valid paid grant completes atomically.
Registration is not idempotent: every successful call creates a distinct order and bootstrap key. A
429 Too Many Requestsresponse includesRetry-After. Only create a replacement order before any payment authorization has been created for the previous order; unexpired pending renewal orders also reserve months against the 12-month cap.When x402 sales are paused, registration and renewal intent creation return
403 Forbidden. Completion remains available so a valid saved grant for a payment already made can still provision idempotently; a sales pause is not a reason to abandon that grant.Do not parse, reconstruct, shorten, or change
payment_url. The signed intent binds the order, plan, duration, amount, and expiry.Obtain and validate the live offer#
Send an empty unsigned
POSTto the opaquepayment_urlwith redirects disabled. A valid challenge returns402 Payment Requiredwith a base64-encoded x402 v2 object inPayment-Required.Ambient supports these USDC rails when they appear in the live response:
Network CAIP-2 identifier Canonical USDC asset Accepted recipient Solana mainnet solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpEPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1vAYYo37bgztqAgP6wp2S9SiYWcijr8gz2o14c8RGWojJZBase mainnet eip155:84530x833589fcd6edb6e08f4c7c32d4f71b54bda029130x6992c688c56BE442EfE1E1cE7D5c95212ED7d59BThe live
acceptsarray is authoritative for currently available rails and amounts, but it is not by itself a trusted recipient allowlist. A client must fail closed unless the selected offer satisfies all of these conditions:x402Versionis2.schemeisexact.network,asset, andpayTomatch one allowed rail above. For Base, normalize both addresses to lowercase before comparison because a live challenge may use checksum casing. Compare Solana identifiers exactly because they are case-sensitive.amountis a canonical positive base-10 integer string. Parse it withBigIntor an equivalent checked integer type, require every offered rail to have the same value, and enforce the client's configured or user-approved maximum.- The resource identifies the intended Jumpgate payment URL.
Do not accept an arbitrary
payTofrom the live challenge. Configure or publish the trusted recipients above with the client, and update that allowlist before paying a rotated recipient. The challenge itself is not signed and does not let the client select Jumpgate's configured facilitator.Choose one offered rail supported by the wallet. Do not create a payment payload merely to inspect the offer.
Authorize and pay#
Use the linked TypeScript reference for the exact package pins and injected Base or Solana signer boundary. Do not use an automatic paid-fetch wrapper for a subscription
payment_url.npm install --save-exact @x402/[email protected] @x402/[email protected] @x402/[email protected] [email protected] @solana/[email protected]For each order:
- Create or reuse one current authorization under the per-order lock. Replace an expired one only when durable state proves it was never attempted.
- Persist its exact encoded
Payment-Signaturebefore transmission when the client supports a pre-send hook. - Send an empty
POSTto the exact savedpayment_url, with redirects disabled, the savedPayment-Signature, and a timeout of at least 125 seconds. - As soon as
fetchresolves, persist the raw status and all headers, including anyPayment-Responseand Ambient grants. Only then read and store the body as best-effort diagnostic data. Capture headers on non-2xxresponses too.
Subscription settlement happens before Jumpgate creates the grant and attempts Ambient's callback. The longer timeout covers facilitator discovery, settlement, confirmation, and the bounded synchronous callback attempts; a shorter client timeout can turn a successful on-chain payment into an ambiguous client result.
A successful Jumpgate response is
200 OKwith this JSON shape:{ "order_id": "7592578c-37b3-441e-a97c-7d262ebc0a72", "plan_id": "basic", "months": 3, "amount_micro_usdc": 60000000 }The numeric amount is illustrative; the validated live offer is authoritative. Save these response headers:
Payment-Response X-Ambient-X402-Grant X-Ambient-X402-Grant-SignatureX-Payment-Responsemay be accepted as a legacy fallback whenPayment-Responseis absent. New integrations should use the standardPayment-Responseheader.Header names are case-insensitive. The selected network, payer, and transaction are in the payment response and the signed grant, not the JSON response body. Before treating the payment as successful, require:
- HTTP status
200. - A decoded settlement receipt with
success=true. - A nonempty payer and transaction.
- A network matching the selected offer.
- A payer matching the expected signer address; normalize Base addresses to lowercase and compare Solana addresses exactly.
- If the receipt includes
amount, an amount matching the selected offer. Receipt amount is optional, so absence alone is not an error. - Both Ambient grant headers.
The unsigned JSON response body is diagnostic only and is not proof of settlement or provisioning. Treat the grant headers as opaque credentials. The signed grant binds the order, plan, months, amount, selected network, canonical asset, configured recipient, payer, transaction, issue time, and expiry. Base identifiers are normalized to lowercase; Solana identifiers remain case-sensitive.
Jumpgate starts Ambient's completion callback independently of the downstream connection and normally waits for it, retrying only transient failures. Callback rejection or exhaustion still returns the valid grant and
200; explicit client completion remains required. A downstream timeout or disconnect does not cancel that tracked callback or itself prove payment failure.An unsigned request or a header rejected before authorization acceptance returns
402 Payment Requiredwith aPayment-Requiredchallenge. A missing, expired, or path-mismatched Ambient intent returns400 Bad Requestbefore payment handling. Once the saved authorization may have been transmitted, do not infer from a status code or intermediary-generated error page that settlement did not occur.Treat every non-success after the authorization may have been transmitted as terminal for automatic payment handling. The outcome is unknown and funds may be at risk if any of these occur:
- A timeout, disconnect, or other transport loss.
- A challenge-free non-success without a structured
facilitator_rejectedorsettlement_unavailableclassification. - A
200with an invalid or unsuccessful receipt. - A missing grant header, empty payer or transaction, network mismatch, or a present receipt amount that mismatches the selected offer.
Jumpgate uses
409 Conflict,X-Ambient-X402-Error-Code: AMBIGUOUS_X402_SETTLEMENT, and the shared error code as a compatibility envelope for all structured post-authorization failures. Every variant stops automatic retries, but onlypayment_status=unknownorpayment_status=facilitator_reported_successindicates funds may be at risk.When Jumpgate cannot confirm settlement, its JSON body includes bounded context that is safe to persist or display:
{ "code": "AMBIGUOUS_X402_SETTLEMENT", "error": "Payment settlement outcome is ambiguous; do not create another payment authorization.", "order_id": "7592578c-37b3-441e-a97c-7d262ebc0a72", "phase": "settlement", "reason": "settlement_unconfirmed", "payment_status": "unknown", "next_action": "do_not_create_new_authorization" }When the facilitator reports a recognized pre-broadcast validation rejection without a settlement identifier, Jumpgate keeps the same challenge-free compatibility response but distinguishes it from an unknown outcome:
{ "code": "AMBIGUOUS_X402_SETTLEMENT", "error": "Payment settlement failed; do not create another payment authorization automatically.", "order_id": "7592578c-37b3-441e-a97c-7d262ebc0a72", "phase": "settlement", "reason": "facilitator_rejected", "facilitator_reason": "insufficient_funds", "payment_status": "facilitator_reported_failure", "next_action": "do_not_create_new_authorization" }facilitator_reasonis optional and limited toinsufficient_funds,authorization_not_yet_valid,authorization_expired,invalid_authorization,payment_mismatch,transaction_rejected,unsupported, orinvalid_response. It reports the facilitator's bounded classification, not independent proof of the on-chain outcome. A missing, unrecognized, or conflicting reason, or a failure carrying a transaction or legacy signature, is classified assettlement_unconfirmedwithpayment_status=unknown.If Jumpgate proves that a local failure happened before it submitted the authorization to the facilitator, the same
409instead usesreason=settlement_unavailableandpayment_status=not_submitted. This does not trigger Ambient's payment-risk pager, but the client must still preserve the saved authorization and stop automatic payment handling.For other failures,
phaseissettlement,receipt_validation, orpost_settlement. Receipt-validation reasons are limited tomissing_receipt,missing_network,missing_payer,missing_transaction, andunsupported_network; post-settlement processing usespost_settlement_failure.payment_status=facilitator_reported_successmeans the facilitator reported success but does not replace the requirement to validate and persistPayment-Response. Jumpgate does not put raw facilitator errors, payer or transaction identifiers, payment credentials, or grants in this JSON body.Ambient's operational pager is narrower than the client's safety rule. It fires only when Jumpgate cannot determine the settlement outcome, cannot turn a reported success into a valid grant, or the Ambient callback is rejected or exhausts its retries. A downstream client timeout or disconnect does not page by itself or cancel an already-started callback; if that callback succeeds, the account is provisioned even when the client did not receive the response.
Treat
next_action=do_not_create_new_authorizationas authoritative. An intermediary-generated response such as a Cloudflare524cannot contain these Jumpgate fields, so the broader challenge-free safety rule still applies.Do not follow
Retry-After, invoke generic HTTP retries, resend the paid request, or create a replacement authorization after any post-transmission non-success. A genuine pre-payment retry remains safe only when the response is a normal402carrying a validPayment-Requiredchallenge and the client has not transmitted an authorization.Complete provisioning#
Resolve the relative
completion_urlagainsthttps://api.ambient.xyz, not the/v1inference base. The endpoint is public: the signed grant is its authorization, so do not send the bootstrap API key.POST https://api.ambient.xyz/billing/x402/subscription-complete Content-Type: application/json { "grantToken": "<X-Ambient-X402-Grant value>", "signature": "<X-Ambient-X402-Grant-Signature value>" }A successful completion returns:
{ "team_id": "344740c2-fcb4-470f-8c88-721765743b67", "plan_id": "basic", "months": 3, "current_period_end": "<RFC 3339 paid-through timestamp>", "already_completed": true }Completion is idempotent for the same order and payment. Always call it after receiving a grant, even if Jumpgate's callback may already have provisioned the account.
already_completedis normallytruewhen that callback succeeded andfalsewhen the client performed the first successful provisioning. Repeating the same order and payment never adds more months.A still-valid seven-day grant can complete after the original 24-hour payment URL expires. Complete promptly instead of relying on the retention window. Treat a completion
409 Conflictas a terminal reconciliation case; do not try another payment.Use the account#
Example activation and usage check:
GET https://api.ambient.xyz/billing/usage-summary Authorization: Bearer <api_key>After provisioning, the response is authenticated and reports the expected active subscription. Before provisioning, the bootstrap key returns
401 Unauthorized.Example model listing:
GET https://api.ambient.xyz/v1/models Authorization: Bearer <api_key>Example Chat Completions request:
POST https://api.ambient.xyz/v1/chat/completions Authorization: Bearer <api_key> Content-Type: application/json { "model": "<model from /v1/models>", "messages": [{"role": "user", "content": "Hello"}] }The same API key can use the Responses API and manage additional Ambient API keys through these routes:
GET https://api.ambient.xyz/keysPOST https://api.ambient.xyz/keysPATCH https://api.ambient.xyz/keys/{prefix}DELETE https://api.ambient.xyz/keys/{prefix}
These routes use
Authorization: Bearer <api_key>and resolve againsthttps://api.ambient.xyz, not the/v1inference base.Renew#
Create a renewal intent with any API key belonging to the account:
POST https://api.ambient.xyz/billing/x402/subscription-intent Authorization: Bearer <api_key> Content-Type: application/json { "planId": "basic", "months": 2 }planIdis the canonical example field; the API also accepts the compatibility spellingplan_id.The response contains another opaque payment URL:
{ "order_id": "bb26e7f0-ef27-4dde-a6b7-35ad2e13f0fe", "plan_id": "basic", "months": 2, "network": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp", "payment_url": "https://jumpgate.ambient.xyz/paid/subscription/v2/basic/2/bb26e7f0-ef27-4dde-a6b7-35ad2e13f0fe?intent=<opaque>" }networkis a legacy Solana compatibility hint, not a complete list of available rails. Select a rail from the live402response. Pay and complete the renewal through the same payment, grant-persistence, and completion steps as registration. The bootstrap-key activation probe used for initial registration does not apply to renewals. The new periods begin at the account's farthest paid-through boundary.Renewal intent creation is not idempotent. An active Stripe subscription or another non-x402 subscription cannot be extended through this endpoint; Ambient returns
409 Conflict.
Ambiguous results#
If both saved grant headers are available, submit them to the idempotent completion endpoint.
For initial registration, GET /billing/usage-summary with the saved
bootstrap key can confirm whether the callback activated the account. A
successful authenticated response reporting the expected active plan confirms
activation; 401 Unauthorized means the key remains inactive. This check
cannot prove a renewal completed because the account was already active before
renewal.
If no grant is available and activation cannot be confirmed, do not automatically resend the payment, generate another authorization, or create a replacement order. Stop and contact [email protected] for reconciliation.
For support, provide only:
- Order ID.
- Payment rail/network.
- Payer address.
- Transaction ID or EVM authorization nonce.
Current limitations#
- Renewal is manual; there is no unattended auto-renewal.
- API-only accounts cannot log into the Ambient web UI. Losing every API key means losing account access; there is no email, wallet-signature, or browser recovery flow.
- Jumpgate is stateless and exposes no public settlement-status or grant-recovery endpoint.
- The callback is best effort. Deterministic client completion remains required.
- There is no cancellation or modification endpoint for a pending order.
- Two independently authorized transactions can still pay the same order. Ambient detects the second receipt but cannot prevent the second on-chain transfer; support reconciliation may be required.
- Settlement can succeed immediately before a Jumpgate crash loses both the paid response and callback, requiring manual reconciliation or refund.
- A late valid settlement can exceptionally take the account above the normal 12-month prepaid cap because Ambient honors paid value.
Related pages#
- Pay per request with x402: the account-free, quote-then-pay flow for a single inference request
- Restart-safe TypeScript x402 subscription example: compile-tested client with injected signer, durable storage, and locking
- Models and readiness: what the network is serving right now