Skip to content

Payments

Agents need positive available prepaid balance—the settled balance minus active reservations—before starting rated work such as ingest, clips, DVR recording, VOD processing, or model-backed execution. Account reads, billing, developer credentials, stream configuration, cleanup, and payment recovery remain available at zero balance. Two funding methods are available: x402-compatible confirmed top-ups and crypto deposits (on-chain transfer).

x402 enables gasless USDC payments using EIP-3009 transferWithAuthorization. The agent signs a transfer authorization off-chain. FrameWorks uses the official v2 wire format and, by default, its embedded facilitator verifies, relays, and confirms the transfer. A hosted facilitator is optional and used only when operators explicitly select one.

Payment requirements do not impose a blanket customer-profile gate. A payment of at most €100 may use the customer-anonymous simplified-document path. A payment over €100 or any submitted VAT-number claim requires a complete billing profile (legal name, billing email, and postal address) before payment instructions are exposed.

  1. An authenticated agent calls a rated tool (for example create_clip or create_vod_upload) with insufficient balance.
  2. HTTP returns 402 plus PAYMENT-REQUIRED. MCP returns JSON-RPC error -32002 whose data carries accepts, x402Version, and headers["PAYMENT-REQUIRED"], or a preflight INSUFFICIENT_BALANCE blocker with x402_accepts. Only get_payment_options returns the base64 document as payment_required.
  3. Agent signs an EIP-3009 authorization for the required amount.
  4. Agent echoes the selected v2 accepted requirement to GraphQL submitX402Payment or MCP submit_payment using PAYMENT-SIGNATURE containing the base64-encoded signed payload.
  5. Purser atomically claims the tenant-bound quote, uses the configured embedded or optional hosted facilitator, and waits for a receipt included by the chain’s consensus-labelled finalized head.
  6. Settlement state and prepaid credit commit atomically.
  7. The agent retries the rated operation without the payment header. A fresh canonical balance and suspension check runs before work is released. Direct x402 mutation execution is rejected before settlement until the owning service has durable idempotency.

Browser integrations authenticate first, make the rated request, receive the 402 response, sign its tenant-bound authorization, submit the top-up through the payment-recovery mutation, and retry the rated operation after confirmation. Wallet signup, billing, top-up, and API/MCP discovery remain reachable at zero balance.

Call get_payment_options while authenticated to get the tenant-bound payment address, exact amount, and supported networks:

{
"x402_version": 2,
"payment_required": "<base64 official v2 PaymentRequired>",
"options": [
{
"network": "eip155:8453",
"asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"asset_symbol": "USDC",
"pay_to": "0x...",
"amount": "5000000",
"quote_id": "<server-quote-id>",
"extra": { "frameworks": { "quoteId": "<server-quote-id>" } }
}
]
}

The standard PAYMENT-SIGNATURE header contains a base64-encoded v2 JSON payload:

{
"x402Version": 2,
"accepted": {
"scheme": "exact",
"network": "eip155:8453",
"asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"amount": "5000000",
"payTo": "0x<payTo-from-payment-options>",
"maxTimeoutSeconds": 60,
"extra": { "frameworks": { "quoteId": "<server-quote-id>" } }
},
"payload": {
"signature": "0x...",
"authorization": {
"from": "0x<your-wallet>",
"to": "0x<payTo-from-payment-options>",
"value": "5000000",
"validAfter": "0",
"validBefore": "1735689600",
"nonce": "0x..."
}
}
}

Use the exact server document; the amount is dynamic and covers the current deficit plus a prepaid buffer. Successful HTTP settlement returns PAYMENT-RESPONSE; MCP returns the same value as payment_response. PAYMENT-SIGNATURE is canonical; X-PAYMENT is read as a fallback; only v2 quote-bound payloads are accepted. Zero-value authorizations do not authenticate a caller—use the wallet challenge login flow.

If submission may have reached the chain but confirmation is not yet known, HTTP returns 503 SETTLEMENT_PENDING with transaction, network, and retry_same_payment: true; MCP returns the same machine state. Retry the exact same signed payment. FrameWorks does not emit PAYMENT-RESPONSE until canonical confirmation and credit; SETTLEMENT_PENDING is a FrameWorks error, not an official x402 settlement response.

Terminal failures keep the facilitator’s stable error_code across HTTP and MCP—for example, AUTHORIZATION_USED—so an agent can distinguish a consumed authorization from a transient transport failure. Do not create a second payment while the result is SETTLEMENT_PENDING.

For side effects, call submit_payment first and then send the normal mutation without PAYMENT-SIGNATURE. Normal operation-specific idempotency still applies. The platform refuses direct paid execution rather than relying only on Gateway response capture after an owner-service commit.

With the default embedded facilitator, returned options are enabled chains that pass live RPC, contract, gas-wallet, and custody readiness. With an optional hosted provider, that set is additionally intersected with its live v2 exact support. Networks use CAIP-2 identifiers; Base is eip155:8453.

For non-x402 prepaid top-ups, use the deposit flow:

  1. Call topup_balance with amount_cents (minimum 1) and asset: "ETH" or "USDC".
  2. The response is a locked-rate quote: a deposit address plus the exact token_amount to send (e.g. 0.01515 ETH), the price_usd it was locked at, its quote_source (chainlink for ETH; one_to_one for USDC), and a 24h expires_at.
  3. Send exactly the quoted amount on-chain.
  4. Call check_topup to follow the lifecycle: pending → confirming → completed.
  5. Once confirmed, the balance is credited at the locked rate (received_token × price_usd), so you get exactly what was quoted regardless of price drift inside the 24h TTL.

The address remains monitored after quote expiry. Late prepaid deposits use a fresh receipt-time price/FX rate. Late invoice payments and non-exact invoice amounts are retained in review_required for explicit allocation and do not silently mark the invoice paid.

Native ETH must be sent as a top-level transaction to the deposit address; internal contract transfers are not an accepted deposit method. USDC is read from contract Transfer logs. Both use restart-safe JSON-RPC cursors and separate deposit-event records. A network’s first cursor starts at the finalized head before any address is issued there, so no deposit can predate it; recreating a cursor for a network that already has issued addresses requires an explicit CRYPTO_SCAN_START_BLOCK_<NETWORK> anchor in production.

LPT is not supported as a top-up asset. Chainlink doesn’t publish an official LPT/USD aggregator, so topup_balance rejects asset: "LPT".

The one-cent crypto minimum is the prepaid ledger’s credit precision, not a claim that every transfer is economical after wallet or network fees. Browser fiat top-ups use a provider-aware minimum, currently 500 cents for Stripe and Mollie checkout in EUR, USD, and GBP. Checkout charges the tenant’s presentment currency, derived from the billing country, and credits the EUR balance at the ECB reference rate locked when the checkout is created.

Invoice collection is available to agents as well as the dashboard and GraphQL API. Read billing://invoices or billing://invoices/{invoice_id}, then call pay_invoice with that invoice ID and card, crypto_usdc, or crypto_eth. Purser derives the amount and currency from the locked invoice balance; an agent cannot choose an arbitrary charge amount. Repeating the same request resumes a still-active hosted session or quote, and a fully paid invoice is rejected.

Use billing://payments for paginated history and billing://payments/{payment_id} for one tenant-owned payment. A failed payment can be retried by calling pay_invoice again after its reservation is terminal; processing and confirmed payments are never blindly retried.

Use billing://documents to list retained monthly statements, full crypto invoices, simplified invoices, confirmed-payment receipts, and credit notes. Read the returned billing://documents/{kind}/{document_id} URI for the tenant-owned document, returned as an application/pdf blob, and its SHA-256 integrity metadata. Document reads stay available at zero prepaid balance.

For postpaid accounts, complete billing identity first and call start_postpaid_setup with an eligible tier and configured stripe or mollie provider. Hosted user action is mandatory. For Mollie, finish with complete_mollie_postpaid_setup; Purser fetches the mandate for the exact customer and requires it to be valid. A browser return alone never activates postpaid service—provider confirmation is authoritative.

The optional VAT number is customer-supplied identity data, not proof of validation or reverse-charge eligibility. Current postpaid records are billing statements, not rendered immutable tax invoices or credit notes.

Rated MCP tools validate positive available prepaid balance before executing. Safe read, control-plane, and payment-recovery tools remain usable at zero balance. Billing details are checked only for paid postpaid setup or for a crypto payment whose amount/tax treatment needs a full customer document. When requirements aren’t met, the response names what is missing.

Missing billing details (HTTP 402 body; get_payment_options returns the same required_fields with error_code):

{
"code": "BILLING_PROFILE_REQUIRED",
"message": "this payment requires a full customer tax invoice; add a legal name, billing email, and postal address before paying",
"topup_url": "/account/billing",
"required_fields": [
"billing_name",
"billing_email",
"billing_address.street",
"billing_address.city",
"billing_address.postal_code",
"billing_address.country"
]
}

Call update_billing_details with the listed fields, then request fresh payment options.

Insufficient balance:

{
"code": "INSUFFICIENT_BALANCE",
"message": "Available balance is 0 cents (0 settled, 0 reserved). Top up required to perform billable operations.",
"resolution": "Call topup_balance tool to add credits, OR pay via x402 (USDC on Base/Arbitrum)",
"tool": "topup_balance",
"x402_accepts": [
{
"network": "eip155:8453",
"asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"pay_to": "0x...",
"description": "Streaming, transcoding & storage credits via Base"
},
{
"network": "eip155:42161",
"asset": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
"pay_to": "0x...",
"description": "Streaming, transcoding & storage credits via Arbitrum One"
}
]
}

Prepaid usage deductions can move an account toward zero or negative balance. Monitor via the billing://balance resource:

FieldDescription
balance_centsSettled prepaid ledger balance
reserved_balance_centsAmount committed to active in-flight usage
available_balance_centsSpendable balance used by MCP preflight
drain_rate_cents_per_hourRecent rated spend rate, when available
estimated_hours_leftTime until the available balance is depleted
live_metricsCurrent operational usage context

At zero or below available balance, prepaid accounts are blocked from new rated work until the balance is topped up. The rest of the authenticated platform remains usable. If the settled balance drops below -€10, Purser suspends the tenant and asks Commodore/Foghorn to terminate active streams and sessions. Top up proactively.