Design a discoverable paid HTTP resource with explicit price, network, schema, payment verification, idempotency, and safe fulfillment boundaries.
The result you're building
A testnet-verified paid API route that advertises a clear resource and price, returns a standards-compliant 402 challenge, verifies and settles payment before fulfillment, handles duplicate requests safely, and publishes accurate discovery metadata.
Use this guide when
- You have a real API result that autonomous software would pay to receive immediately and programmatically.
- You need usage-based or fixed-price payment without building accounts and subscription billing first.
- You can measure the cost and reliability of producing each response.
Do not use it as a substitute for
- Charging for an undifferentiated wrapper around free public data with no reliability, normalization, freshness, or decision value.
- Mainnet launch before negative payment tests, spend caps, idempotency, observability, and a kill switch work.
Before you change anything
- Collect the items below first. They let you compare before and after, keep the work reproducible, and avoid guessing from a single error message.
- One narrow resource path, method, input schema, output schema, examples, latency target, and freshness promise.
- Receiving wallet public address on a supported test network; private keys stay in a wallet or secret manager.
- Chosen facilitator, payment scheme, asset/network, price ceiling, and settlement behavior.
- Measured upstream cost per call and failure behavior.
- A separate low-balance buyer test wallet plus acceptance test matrix.
Understand the system before fixing it
x402 monetizes a resource, not an entire website
The paid boundary should wrap a response with specific machine value. Keep discovery, schema, health, samples, and human-readable explanation free so an agent can decide whether to buy.
Payment verification and business authorization are different
A valid payment proves the payment payload satisfies the advertised requirement. It does not prove the caller may access another person's data or trigger an unsafe operation.
Price must follow contribution margin
Gross payment minus facilitator/network cost, upstream/API cost, compute, refunds, and failed paid responses is the useful number. A popular endpoint can lose money if these are not bounded.
x402 v2 is an evolving protocol surface
Pin SDK versions, publish the supported network and scheme explicitly, test protocol edge cases, and recheck current official documentation before launch.
Evidence-to-decision map
| Evidence | Likely layer | First decisive check | What the result means |
|---|---|---|---|
| Unpaid request does not return 402 | Middleware/order | Call route without payment and inspect headers/body | Route is unprotected, middleware is mounted incorrectly, or framework adapter is wrong. |
| 402 returned but client cannot decode | Protocol/schema | Decode payment-required structure and version | Header/body/version/network identifiers do not match client expectations. |
| Payment verifies but fulfillment fails | Upstream/service | Correlate payment ID with resource job | Need preflight, refund/support policy, stable paid error, and contribution-cost tracking. |
| Paid retry duplicates work | Idempotency | Repeat same logical request/payment identifier | Fulfillment lacks atomic deduplication or uses a fresh business key. |
| Endpoint absent/misleading in discovery | Catalog | Fetch discovery entry and compare live route | Published method, price, network, schema, or examples are stale. |
Step-by-step procedure
Work in order. Record the output after each step. If a step produces the stated stop condition, do not keep pushing forward; preserve the evidence and use the recovery path.
Step 01 — Define the paid unit and free preview
Why: Agents will not pay for a vague promise and cannot price an unknown payload.
Do: Specify one resource, supported inputs, response schema, freshness, latency, exclusions, and a free sample or preview that reveals structure without giving away unlimited production output.
Read the result: If value cannot be stated in one sentence or tested objectively, the endpoint is not ready for a payment layer.
Next: Measure production cost and choose the smallest useful billable unit.
Step 02 — Choose scheme, network, asset, recipient, and price
Why: These fields are part of the authorization boundary, not decorative configuration.
Do: Select fixed exact, usage-capped upto, or the current supported scheme based on real billing semantics. Use a supported test network and stable receiving address. Calculate minimum viable price from costs and target margin.
Read the result: A buyer must be able to know the maximum before signing. Reject unsupported network/asset/scheme and amounts above route policy.
Next: Write the configuration as server-owned constants or validated deployment secrets.
Step 03 — Implement the unpaid challenge
Why: The 402 response is the machine-readable quote and purchase instructions.
Do: Mount the current official x402 server middleware/adapter on only the paid route. Return the supported protocol version, payment options, resource identity, and descriptive metadata.
curl -i https://example.com/api/v1/paid-resource
# Decode the returned payment requirements and compare every field to server policy.Read the result: An unpaid curl request should receive 402, not 401/403/500, and the challenge must decode to the intended recipient, amount, network, asset, and expiry.
Next: Create negative tests before enabling settlement.
Step 04 — Verify and settle before irreversible fulfillment
Why: A payment-looking header is untrusted input until the facilitator or configured verifier accepts it.
Do: Validate protocol version, scheme, network, asset, destination, amount/max, expiry, resource binding, and payment identifier. Settle according to the chosen flow before returning protected data or creating a side effect.
Read the result: Verification failure must return a stable payment error with no fulfillment. Settlement and fulfillment records must share one correlation/idempotency key.
Next: Keep authorization, quota, and data-access checks in addition to payment.
Step 05 — Make retries safe and observable
Why: Networks time out after either side may have committed, so both buyer and seller must reconcile ambiguous outcomes.
Do: Use a client-supplied or generated stable idempotency/payment identifier. Store the first terminal result atomically and return it for matching retries. Log sanitized payment status, fulfillment status, latency, and cost.
Read the result: Same key plus different payload must be rejected. Same key plus same payload must not charge or fulfill twice.
Next: Add alerting for settlement failure, paid-response errors, margin, and duplicates.
Step 06 — Publish and test discovery
Why: An agent cannot buy a service it cannot find, compare, or call correctly.
Do: Publish accurate Bazaar/discovery metadata, OpenAPI schema, examples, price/network/asset, freshness, error codes, and free health/preview routes. Validate the listing against the live endpoint.
curl -sS https://api.cdp.coinbase.com/platform/v2/x402/discovery/resources | jq .
curl -fsS https://example.com/openapi.json | jq .Read the result: Discovery conversion requires a working example buyer and deterministic schema, not merely a listing.
Next: Keep versioned route and metadata changes synchronized.
Step 07 — Pass testnet and mainnet gates
Why: The first real payment should not be the first time wrong network, expiry, duplication, and upstream failure are tested.
Do: Run unpaid, valid, wrong network, wrong asset, wrong recipient, over-price, expired, invalid signature, duplicate, timeout, upstream failure, and refund/support tests. Then use a low-balance mainnet buyer wallet for one capped call.
Read the result: Mainnet is allowed only when every safety gate is documented and the paid-route kill switch is tested.
Next: Monitor contribution margin and disable routes whose paid success or cost breaks policy.
Worked example
Evidence collected
- Testnet payment flow and discovery both work.
- Upstream provider charges per call and retries are not cached.
- Paid-response failure rate is 4%, and duplicate retries repeat upstream work.
- Gross receipts appear positive while contribution margin is negative.
Decision: The protocol integration works, but the product is commercially unsafe. Pricing, caching, and idempotency must be corrected before mainnet.
Actions taken
- Added a short freshness cache keyed by chain, mint, and data version.
- Made duplicate payment identifiers return the stored terminal result.
- Raised price to cover p95 cost plus failure allowance and target margin.
- Published observed-at time and cache age so the buyer understands freshness.
Why this example matters: Getting a 402 flow to work is only the integration milestone. The end result is a reliable unit of paid value with positive economics and bounded buyer risk.
Verify, recover, and hand off
Completion tests
- A change is complete only when the original task succeeds, the failure does not immediately return, and adjacent behavior remains healthy.
- Unpaid call returns a decodable x402 v2 402 challenge for the intended resource.
- Valid testnet payment returns the documented schema and receipt/response metadata.
- Wrong network, asset, destination, amount, expiry, signature, and payload binding are rejected before fulfillment.
- Identical retry cannot double-charge or duplicate fulfillment; conflicting reuse is rejected.
- Discovery/OpenAPI examples match the live version, price, network, and error behavior.
- Contribution margin, p95 latency, settlement failure, and paid-response error rate meet launch limits.
Rollback or safe recovery
- Activate the paid-route kill switch while leaving free health/schema information available.
- Return to testnet and previous route version when facilitator, SDK, or network behavior changes.
- Preserve payment/fulfillment correlation records for reconciliation and support; never solve an incident by deleting them.
If the expected result does not appear
| What happened | What it usually means | Next safe move |
|---|---|---|
| 402 body looks correct but SDK refuses | Protocol version or payment option encoding differs. | Decode the exact challenge and compare with the current SDK/spec example. |
| Buyer paid but got 5xx | Fulfillment failed after settlement. | Return stable correlation ID, reconcile settlement, apply support/refund policy, and fix preflight. |
| Duplicate paid results | Idempotency is outside the atomic fulfillment boundary. | Store request hash and terminal result before/reliably with side effect. |
| No agents purchase | Discovery, proof, value, freshness, trust, or price is weak. | Run a demonstration buyer, publish examples/metrics, and narrow the recurring job. |
Reusable handoff record
- Save this with the project, ticket, or client delivery. It turns the work into a repeatable result instead of a one-time guess.
- Versioned route, schemas, examples, free preview, and value statement.
- Server-owned payment policy: scheme, network, asset, recipient, price/max, expiry.
- Negative and positive test matrix with receipts and fulfillment IDs.
- Idempotency data model, kill switch, support/refund rule, and sanitized logs.
- Discovery entry plus cost, price, margin, latency, and paid-success scoreboard.
Agent delivery contract
Required inputs
| Field | Type | Requirement |
|---|---|---|
| resource | string | Stable route or resource identifier. |
| method | enum | Allowed HTTP method. |
| inputSchema | object | Strict JSON Schema with examples and size limits. |
| paymentPolicy | object | Scheme, network, asset, recipient, price/max, expiry, and facilitator. |
| economics | object | p50/p95 cost, target margin, cache policy, and paid failure allowance. |
Returned output
| Field | Type | Meaning |
|---|---|---|
| routeConfig | object | Framework-neutral paid route and server-owned policy. |
| challengeTests | test[] | Unpaid and invalid-payment cases plus expected errors. |
| fulfillmentTests | test[] | Valid, duplicate, conflicting-key, timeout, and upstream-failure behavior. |
| discovery | object | Catalog/OpenAPI metadata and free preview contract. |
| launchDecision | object | Pass/fail gates, risks, and mainnet blockers. |
Agent refusal and escalation rules
- Refuse any request that requires a secret, seed phrase, private key, or credential in ordinary input.
- Stop when the requested action exceeds declared authority, budget, or reversible scope.
- Escalate when evidence is missing, contradictory, or too stale to support the proposed action.
Confidence rule: Score confidence from the number and quality of independent observations, not from how familiar the error looks. Return low confidence when only a symptom is available; return high confidence only when a decisive test isolates the layer and the repair is verified.
Official reference starting points