x402 Gateway
Pay-per-call HTTP 402 gateway that fronts write mutations on the Labs API with per-request stablecoin settlement on Base.
Overview
The x402 gateway wraps a small set of Labs API write mutations with the HTTP 402 Payment Required protocol. Callers β typically autonomous AI agents or external services that don't hold a long-lived service token β settle a USDC payment on Base per request, and the gateway forwards the underlying GraphQL mutation to AppSync.
Each successful request costs the configured mutation price in USDC, which is debited directly from the payer wallet via EIP-3009 transferWithAuthorization (or Permit2) and settled through the Coinbase facilitator.
When to use x402
Use the gateway when:
An agent needs write access without provisioning a per-agent service token. The gateway mints a short-lived, scoped service token on the fly after payment is verified.
You want pay-per-call economics. Each mutation has its own price; no subscription or prepaid balance.
You're building third-party tooling that pays for users. The payer wallet is recorded as the mutation author.
Use the standard Labs API with a service token when you have long-lived credentials for a known lab.
Endpoints
The gateway exposes one HTTP endpoint per allow-listed mutation. All endpoints accept POST with a JSON body containing a GraphQL mutation.
POST /x402/labs/{mutation}/x402/labs/initiateCreateOrUpdateFile
initiateCreateOrUpdateFile
Start a file upload; returns a presigned URL
/x402/labs/finishCreateOrUpdateFile
finishCreateOrUpdateFile
Finalise a file upload with metadata
/x402/labs/createAnnouncement
createAnnouncement
Publish a lab announcement
/x402/labs/createLab
createLab
Create a lab (data room) for an onchain lab (OCL)
/x402/labs/generateDataEncryptionKey
generateDataEncryptionKey
Generate a data encryption key (DEK) for encrypted uploads
/x402/labs/decryptDataKey
decryptDataKey
Decrypt a file's data key for an authorized caller
The path mutation must match the top-level GraphQL mutation field in the request body, otherwise the gateway returns 400. The allow-list above is the single source of truth in lambda/x402-gateway-lambda/mutations.ts (X402_WRITE_MUTATIONS).
Payment Flow
The gateway implements the standard x402 three-phase flow: verify β serve β settle.
402 challenge β The gateway returns an x402-standard payment-requirements response describing network, asset, price, and payTo address.
Sign β The client signs an EIP-3009
transferWithAuthorization(or Permit2) for the quoted amount toX402_PAY_TO_ADDRESSon the configured network.Retry with payment β The signed authorization is submitted as a base64 JSON header under any of
Payment-Signature,X-Payment, orPayment.Verify β The gateway calls the Coinbase facilitator's
/verifyendpoint. On failure it returns402with the original requirements.Serve β The gateway mints a scoped, short-lived JWT service token (
allowedMutations: [mutation],authMethod: "x402",ttl = X402_TOKEN_TTL_SECONDS, default300s) with the payer wallet asadminAddress, then forwards the GraphQL mutation to AppSync using that token.Settle β After a
2xxupstream response, the gateway calls the facilitator's/settleendpoint to broadcast the transfer. Settlement headers are merged into the final response.
Payer address resolution
The mutation is executed as if the payer wallet called it. The payer address is resolved from the verified payment payload, in this order:
payload.authorization.from(EIP-3009)payload.permit2Authorization.from(Permit2)payerAddressfield on the JSON request body (fallback only β used when upstream wrappers strip the verified payload)
If none resolves to a valid address the gateway returns 400. Source: lambda/x402-gateway-lambda/index.ts (extractPayerAddress).
Request Format
The 200 body is the mutation's GraphQL response verbatim, so read it exactly as on the Labs API: the mutation succeeded when error is null; otherwise branch on error.code β see Error Handling. Note that settlement is triggered by the upstream 2xx, not by mutation success β a 200 whose body carries a non-null error (e.g. VALIDATION_FAILED, UNAUTHORIZED) is still settled, so you pay for a mutation that failed in-band; only an upstream 4xx/5xx skips settlement. Validate inputs (ids, categories/tags, role) before paying.
Constraints enforced by the gateway (validateMutationQuery):
Exactly one GraphQL operation.
Operation kind
mutation.Exactly one top-level selection.
Top-level field name must equal the path
{mutation}.
Pricing & Configuration
Pricing is environment-driven and resolved per-mutation. The gateway evaluates the following env vars in order and uses the first non-empty value:
Values are interpreted as USDC amounts (e.g. "2.50" = $2.50). Prices are environment-configured β the authoritative price for a given mutation is the one quoted in the 402 payment-requirements response, so clients should always read it from the challenge rather than hardcoding amounts.
X402_NETWORK
base (prod) / base-sepolia (non-prod)
CAIP-2 network (base β eip155:8453)
X402_PAY_TO_ADDRESS
β
Wallet that receives settlement
X402_FACILITATOR_URL
https://api.cdp.coinbase.com/platform/v2/x402
Facilitator base URL
X402_PRICE_* / X402_PRICE_DEFAULT
environment-configured
Per-mutation price in USDC (quoted in the 402 challenge)
X402_TOKEN_TTL_SECONDS
300
Lifetime of the minted service token
Facilitator authentication uses Coinbase CDP API keys (CDP_API_KEY_ID_SECRET_ARN / CDP_API_KEY_SECRET_SECRET_ARN in Secrets Manager, or CDP_API_KEY_ID / CDP_API_KEY_SECRET in local mode) to sign the /verify, /settle, and /supported requests.
Response Semantics
200
Payment verified, upstream AppSync returned 2xx. Body is the AppSync response verbatim; settlement headers are merged in.
402
Payment required or payment verification failed. Body includes facilitator hints in headers.
400
Path mutation mismatch, missing query, invalid GraphQL, or unresolvable payer address.
4xx/5xx
Upstream AppSync error β settlement is skipped and the upstream response is returned as-is.
Idempotency
Each minted service token has a unique jti claim, so requests are not idempotent by default β replaying the same signed payment may be rejected by the facilitator's replay protection, and the downstream AppSync call may succeed twice if you retry after a settlement failure. Agents should treat settlement failures as "payment not charged yet" and re-sign.
Agent Usage Pattern
An autonomous agent typically wraps each gateway call in a helper:
See the Developers / AI Agents guide for end-to-end agent integration patterns, and the Labs API reference for the full GraphQL signatures of each gated mutation.
Related
Labs API β full mutation signatures and variable types
Developers / AI Agents β agent integration guide
Last updated