Four steps
The flow
- Ask for the pack. POST to /api/v1/credits/buy/1 with no body and no key. The answer is HTTP 402.
- Read the offer. Decode the PAYMENT-REQUIRED header. It is base64 JSON in x402 version 2 form: the exact scheme, USDC on Base, the amount, the address to pay and a quote token.
- Pay. Sign a USDC transfer authorization for that amount to that address, and send the same POST again with the signed payment in a PAYMENT-SIGNATURE header.
- Receive a key. The answer is HTTP 201 with an API key and the credits it holds. Save the key and send it as a Bearer header on every capture.
Payment buys a key with credits. Each capture is then an ordinary API call with that key. There is no payment per call: a capture request without a key is refused.
Request and response
Step 1 and 2: get the offer and read it
curl -si -X POST https://pageverified.com/api/v1/credits/buy/1
The answer is 402 Payment Required. The x402 offer is in the PAYMENT-REQUIRED header as base64 JSON. Decoded and abridged, it looks like this (the real header also carries a description of the resource and an extensions block). The amount is in USDC's smallest unit, which has six decimal places, so 1,000,000 is $1.
{
"x402Version": 2,
"error": "Payment required",
"resource": {
"url": "https://pageverified.com/api/v1/credits/buy?pack=1",
"mimeType": "application/json"
},
"accepts": [
{
"scheme": "exact",
"network": "eip155:8453",
"amount": "1000000",
"asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"payTo": "<PageVerified's receiving address>",
"maxTimeoutSeconds": 300,
"extra": {
"name": "USD Coin",
"version": "2",
"pageverified_quote": "<quote token>"
}
}
]
}
eip155:8453 is Base mainnet and the asset is the USDC contract on Base. extra.name and extra.version are the signing-domain values for that contract. The quote token ties your payment to this purchase, so send it back unchanged.
Request and response
Step 3 and 4: pay and receive the key
Sign an EIP-3009 transferWithAuthorization for the offered amount to payTo. Set value to the amount exactly as offered, validAfter to now or earlier, and validBefore to more than 30 seconds ahead when the request arrives (a minute is safe) and no further ahead than the offer's maxTimeoutSeconds. Build the x402 payment payload:
{
"x402Version": 2,
"accepted": "<the entry from accepts, exactly as offered, including extra.pageverified_quote>",
"payload": {
"authorization": {
"from": "<payer address>",
"to": "<payTo>",
"value": "<amount>",
"validAfter": "<unix seconds>",
"validBefore": "<unix seconds>",
"nonce": "<32 random bytes as 0x hex>"
},
"signature": "<EIP-3009 signature>"
}
}
Base64-encode it and send the same request again with it in the PAYMENT-SIGNATURE header. An x402 version 2 client library does this step for you.
curl -si -X POST https://pageverified.com/api/v1/credits/buy/1 \
-H "PAYMENT-SIGNATURE: <base64 payment payload>"
Once the payment settles, the answer is 201 with a PAYMENT-RESPONSE header that carries the transaction hash, and this body:
{
"purchase_id": "<uuid>",
"api_key": "pv_cap_...",
"credits_added": 150,
"credits_remaining": 150
}
Then capture a page with the key:
curl -s -X POST https://pageverified.com/api/v1/capture \
-H "authorization: Bearer pv_cap_..." \
-H "content-type: application/json" \
-d '{"url":"https://example.com","format":"png"}'
The capture response is described on Screenshot API with hash and timestamp.
One-time, USD
Packs an agent can buy
Scroll the table horizontally to see all fields.
Packs an agent can buy over HTTP 402| Price | Credits | At 1 credit each | Request |
|---|
| $1 | 150 credits | 150 PNG captures | POST https://pageverified.com/api/v1/credits/buy/1 |
|---|
| $19 | 3,000 credits | 3,000 PNG captures | POST https://pageverified.com/api/v1/credits/buy/19 |
|---|
| $49 | 12,000 credits | 12,000 PNG captures | POST https://pageverified.com/api/v1/credits/buy/49 |
|---|
| $149 | 60,000 credits | 60,000 PNG captures | POST https://pageverified.com/api/v1/credits/buy/149 |
|---|
Each pack also answers at https://pageverified.com/api/v1/credits/buy?pack=<price>.
So an agent never pays twice
Retries and errors
- 202
payment_pending. The payment may have gone through. Send the identical request again, with the same PAYMENT-SIGNATURE, after the Retry-After time. Do not ask for a new quote. - Lost the 201? Send the identical request again. The same key is returned for a limited time after the payment.
- 402
payment_failed with "charged": false. Nothing was taken, for example because the wallet did not hold enough USDC. Start again from step 1. - 410
quote_expired. Quotes are short-lived. Nothing was taken. Start again from step 1. - 400
x402_version_not_supported. The request used the version 1 X-PAYMENT header. Use version 2 and PAYMENT-SIGNATURE. - 409
retry_original_payment. This quote is already tied to a different signed payment, or this payment to a different quote. Send the original request again. Do not sign a new payment. - 400
invalid_payment_window. validAfter or validBefore is outside the range in step 3. Nothing was taken. - 429. New quotes and failed attempts are rate limited. Wait for the
Retry-After time before trying again.
Other ways to pay
x402 is the working route for agents today. A Stripe Machine Payments Protocol challenge is also offered on the same 402, in the WWW-Authenticate header. People can buy the card packs with checkout in a browser on the pricing page.
Machine-readable details: /openapi.json describes the buy endpoint, and /services/pricing.json lists the pack prices an agent can name.
The same on every page
Prices and limits
- Formats. PNG, PDF or rendered HTML. One format per call.
- Cost. A PNG or HTML capture costs 1 credit. A PDF costs 2 credits. A capture that fails is not charged.
- Signed Capture Record. The capture cost plus 4 credits.
- Free key. 25 credits, with no email and no card. Free keys render at up to 1,280 by 800 pixels, stop full-page captures at 2,400 pixels and allow 10 captures a minute. New free keys are issued in limited numbers; when none are left the API answers 429.
- Every key. Free or paid, one key can run up to 120 captures an hour. Each key also has a daily share of the shared browser pool. A key capturing at that rate reaches it in under an hour.
- Paid keys. Viewports from 320 to 2,560 pixels wide and 240 to 2,000 pixels high. Full-page captures stop at 16,000 pixels.
- Packs. Credit packs are one-time payments in US dollars, bought with card checkout: $19 for 3,000 credits, $49 for 12,000 credits, $149 for 60,000 credits. Nothing renews.
- Agents. An agent can buy the same packs over HTTP 402 with no person involved, plus $1 for 150 credits. How an agent pays.
- Storage. The captured file is kept in private storage until you ask for it to be deleted. Download links are signed and expire after 24 hours. By default a capture has a public receipt page, which issues a fresh link each time it is loaded.
- Time. The capture time is UTC from PageVerified's own server clock. For a signed Capture Record, outside time-stamp authorities later sign the record's hash with their own time, usually within 15 minutes; the record check at /verify shows it.
- Pages it can capture. Public
http and https pages only. It cannot log in, send cookies or set request headers, and private network addresses are refused.
- What a capture is. A capture records what PageVerified's renderer saw at the recorded time. It is not a forensic chain of custody, proof of who wrote a page, or a legal certification.
- Not offered. No uptime guarantee and no security or compliance certifications.
The card packs and the cost of every tool are on the pricing page, and more limits are in the API reference. How long data is kept is on the data handling page.
Next steps
Related guides: Screenshot API with hash and timestamp · Capture a web page as evidence · Verify a capture · Screenshot MCP server.