For the complete documentation index, see llms.txt. This page is also available as Markdown.

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}
Path
Wraps mutation
Purpose

/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.

  1. 402 challenge β€” The gateway returns an x402-standard payment-requirements response describing network, asset, price, and payTo address.

  2. Sign β€” The client signs an EIP-3009 transferWithAuthorization (or Permit2) for the quoted amount to X402_PAY_TO_ADDRESS on the configured network.

  3. Retry with payment β€” The signed authorization is submitted as a base64 JSON header under any of Payment-Signature, X-Payment, or Payment.

  4. Verify β€” The gateway calls the Coinbase facilitator's /verify endpoint. On failure it returns 402 with the original requirements.

  5. Serve β€” The gateway mints a scoped, short-lived JWT service token (allowedMutations: [mutation], authMethod: "x402", ttl = X402_TOKEN_TTL_SECONDS, default 300s) with the payer wallet as adminAddress, then forwards the GraphQL mutation to AppSync using that token.

  6. Settle β€” After a 2xx upstream response, the gateway calls the facilitator's /settle endpoint 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:

  1. payload.authorization.from (EIP-3009)

  2. payload.permit2Authorization.from (Permit2)

  3. payerAddress field 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.

Variable
Default
Purpose

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

Status
Meaning

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.


Last updated