Skip to content

The 402 flow

The full HTTP-level x402 exchange for PDF As You Go — the 402 body, the X-PAYMENT header, settlement, and the X-PAYMENT-RESPONSE receipt.

This page documents the payment exchange at the HTTP level: the 402 challenge, the X-PAYMENT header you send back, and the X-PAYMENT-RESPONSE receipt you get on success. For the conceptual overview see x402 payments.

Send the operation request with no payment header:

Terminal window
curl -i -X POST https://api.pdfasyougo.com/v1/merge \
-H "Content-Type: application/json" \
-d '{"files":["https://example.com/a.pdf","https://example.com/b.pdf"]}'

The server responds with 402 and a JSON body whose accepts array lists acceptable ways to pay:

HTTP/1.1 402 Payment Required
Content-Type: application/json
{
"x402Version": 1,
"error": "X-PAYMENT header is required",
"accepts": [
{
"scheme": "exact",
"network": "base",
"maxAmountRequired": "50000",
"resource": "https://api.pdfasyougo.com/v1/merge",
"description": "Merge PDF documents",
"mimeType": "application/json",
"payTo": "0xA0b8…receiver",
"maxTimeoutSeconds": 60,
"asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"extra": { "name": "USDC", "version": "2" }
}
]
}
Field Meaning
x402Version Protocol version.
error Why the request was rejected (here, payment is missing).
accepts[].scheme exact — a fixed price.
accepts[].network Settlement network. base by default.
accepts[].maxAmountRequired Price in token base units. 50000 = $0.05 USDC (6 decimals).
accepts[].asset Token contract (USDC on Base shown).
accepts[].payTo Receiving address.
accepts[].resource The URL being paid for.
accepts[].maxTimeoutSeconds How long this quote stays valid.
accepts[].extra Scheme data — USDC’s EIP-712 name/version for signing.

Pick an entry from accepts your wallet can satisfy (during preview there is one: USDC on Base).

Construct a payment payload for the chosen requirement, sign it with your wallet, base64-encode it, and resend the identical request with the X-PAYMENT header.

The decoded payload has this shape (a gasless EIP-3009 transferWithAuthorization for USDC):

{
"x402Version": 1,
"scheme": "exact",
"network": "base",
"payload": {
"signature": "0x…",
"authorization": {
"from": "0xYourWallet…",
"to": "0xA0b8…receiver",
"value": "50000",
"validAfter": "0",
"validBefore": "1750000060",
"nonce": "0x…"
}
}
}
Terminal window
curl -i -X POST https://api.pdfasyougo.com/v1/merge \
-H "Content-Type: application/json" \
-H "X-PAYMENT: $(echo -n "$PAYMENT_JSON" | base64)" \
-d '{"files":["https://example.com/a.pdf","https://example.com/b.pdf"]}'

The server hands the payload to a facilitator, which verifies the signature and settles the USDC transfer onchain (typically sub-2-second). On settled payment, the operation runs.

HTTP/1.1 200 OK
Content-Type: application/json
X-PAYMENT-RESPONSE: <base64-encoded settlement receipt>
{
"output": {
"url": "https://files.pdfasyougo.com/o/3f9a…?token=…",
"expires_at": "2026-06-29T12:00:00Z",
"pages": 24,
"bytes": 184320
},
"operation": "merge",
"cost": "0.05 USDC"
}

The decoded X-PAYMENT-RESPONSE confirms settlement and includes the onchain transaction reference:

{
"success": true,
"transaction": "0x…",
"network": "base",
"payer": "0xYourWallet…"
}

Download the output from output.url before it expires (preview default: 60 minutes).

import { wrapFetchWithPayment } from 'x402-fetch';
import { privateKeyToAccount } from 'viem/accounts';
const account = privateKeyToAccount(process.env.X402_WALLET_PRIVATE_KEY as `0x${string}`);
const fetchWithPay = wrapFetchWithPayment(fetch, account);
// One call — the 402, signing, and retry are handled internally.
const res = await fetchWithPay('https://api.pdfasyougo.com/v1/merge', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ files: ['https://example.com/a.pdf', 'https://example.com/b.pdf'] }),
});
console.log((await res.json()).output.url);