Errors
Last updated: 2026-10-10
Every error code the API can return, what it means and whether the call was charged. All errors share one JSON shape:
{ "error": { "code": "invalid_url", "message": "url: …. You were not charged.", "details": { "field": "url" } } }
code is stable and meant for programs; message is for people; details is optional (for example field or retry_after_ms). An answer with status 400 or above is never charged (with L402, the token is not spent and still works). The one exception is settle_failed: the payment may have gone through even though settling reported a failure. Resend the same request with the same payment id (the x402 payment-identifier extension): if the charge went through, you get the withheld result without paying again (marked payment-redelivered: true); if not, the payment is settled at most once. A charge that went through is also recorded for reconciliation. So a payment_already_used answer can follow a charged settle_failed; that call itself charged nothing.
| Status | Code | Meaning |
|---|---|---|
| 400 | bad_request | Body is not a JSON object, or a field has the wrong type. |
| 400 | invalid_request | A field is missing or out of range (for example a quote over 1,000 characters), or both an x402 payment header and an L402 Authorization header or a credit key were sent (details.reason two_payment_headers). |
| 400 | invalid_url | The URL is malformed, too long, not http(s) or on another port; details.reason says which. |
| 400 | blocked_target | The URL points at a private, loopback or otherwise internal address. |
| 402 | payment_required | Pay with x402: see the PAYMENT-REQUIRED header and Payments. Where L402 is on, the WWW-Authenticate: L402 header carries a macaroon and a Lightning invoice too. A free-trial call to verify/citations, verify/quotes, verify/document or check/links with more than 3 citations, quotes, pairs or URLs gets this too, with details.reason trial_too_large: pay for it, or send at most 3 per trial call. |
| 402 | payment_invalid | The payment did not verify (details.reason says why). Sign a new one from the PAYMENT-REQUIRED header. For an L402 token the reason starts with l402_ (for example l402_wrong_route, l402_expired, l402_preimage_mismatch) and a fresh WWW-Authenticate offer is included. A resend for a withheld settle_failed result whose signature is not the payer's own gets this with details.reason invalid_exact_evm_payload_signature: resend the original signed payment, or a new one signed with the payer's key. |
| 403 | robots_disallowed | robots.txt or our opt-out list disallows the page (or a redirect from it). |
| 403 | payer_refused | The paying address is on a sanctions list. For a credit key: a payment to it came from a listed address, so the key is blocked (details.reason credits_payer_refused). |
| 404 | not_found | No such route or sample, or (GET /v1/credits) no such credit key. |
| 409 | payment_id_conflict | The payment id was already used for a different request. |
| 409 | payment_already_used | This payment signature was already spent, and this call did not charge again. Sign a new payment; the PAYMENT-REQUIRED header is included. If an earlier call with it ended in settle_failed, resend that request with its payment id to get the result. details.reason result_not_kept: that earlier call was charged but its result is no longer kept; the charge is recorded for reconciliation. For L402: the token already paid for another call (details.reason l402_spent); pay the fresh invoice in WWW-Authenticate. |
| 409 | settle_pending | An earlier call with this payment id ended in settle_failed, it is not charged on chain yet, and its payment could still go through. Resend the same signed payment now, or a new one after Retry-After (details.retry_after_ms). |
| 409 | idempotency_conflict | The attest idempotency_key was already used with a different hash or note. |
| 413 | body_too_large | Body over 64 KB (168 KB on receipt/verify and /mcp). |
| 422 | host_not_found | The URL's host name does not resolve (for check/links and verify/citations: none of the URLs resolves; for verify/document: none in the part). |
| 422 | page_too_large_for_edge | Edge server only: the page is over the 64 KB it reads, or (check/packages) a registry answer is over the 256 KB it reads, with only the names over that size in details.too_large (no results for the others); details.full_service is the server to send the call to. |
| 422 | edge_subrequest_limit | Edge server only: the call needs more outbound requests than the edge allows (many hosts or redirects); use details.full_service. |
| 422 | match_too_costly | Fuzzy matching this quote would take too long; use "match": "exact" or a shorter quote. For verify/citations and verify/quotes this is an error on that citation or quote only and the call is charged; only when every one fails does the call get 422, with details.failed listing them. verify/document works the same way per part. |
| 422 | no_pairs | verify/document: no quote with a link was found in the document; details.skipped counts what was skipped and why. Never charged. |
| 429 | rate_limited | Too many requests to that host or from your address, or (for check/packages) the crates.io queue of one lookup a second is full; see Retry-After. Where L402 is the only offer, also too many unpaid Lightning invoices (details.reason l402_invoice_cap). For verify/citations, verify/quotes and verify/document (one shared count), also too many calls from your address that failed uncharged (details.reason uncharged_failures). |
| 429 | trial_exhausted | Free trial calls used up for the day; see Retry-After. |
| 500 | internal_error | Something failed on our side. |
| 502 | registry_unavailable | check/packages only: every registry lookup in the batch failed (details.reasons), so nothing was charged. Try again later. |
| 502 | facilitator_unavailable | The payment facilitator could not be reached, so no payment was taken. Try again later. |
| 502 | settle_failed | The work ran but the payment could not be settled, so the result is withheld. Resend the same request with the same payment id: if the charge went through on chain, you get the result without paying again; if not, the payment is settled at most once. If a charge went through, it is recorded for reconciliation. Redelivery runs on the full service only; on the edge server see Payments. |
| 501 | not_on_edge | Edge server only: POST /v1/attest, POST /v1/verify/citations, POST /v1/verify/quotes and POST /v1/verify/document run on the full service (the free verify/document/preview works on the edge) (details.full_service). Also fetch and verify/quote when the page is a PDF (details.reason pdf, with details.final_url): only the full service reads PDFs. Never charged. |
| 503 | paused | Paid routes are paused for maintenance. |
| 503 | over_capacity | verify/citations, verify/quotes and verify/document: too many batches are waiting to be matched (details.reason match_queue_full). fetch, verify/quote, verify/quotes and verify/citations: the page is a PDF and too many PDFs are waiting to be read (details.reason pdf_queue_full, with details.field). Retry after Retry-After. Never charged, even when it comes after your payment was verified. |
| 503 | signing_unavailable | Signing keys are not loaded. |
| 503 | payments_unavailable | Payments are not set up on this server, (with L402 only) no invoice could be made, or a new payment for a payment id whose earlier call ended in settle_failed came while the chain could not be read. Where credit keys are on, also: no credit address could be issued (the signet explorer is down, the server's addresses are used up, or too many issued addresses are still unpaid: details.reason credits_gap_full). |
| 503 | sanctions_list_stale | Edge server only: its built-in sanctions list is more than 8 days old, so it refuses payments until it is rebuilt (details.list_date, details.full_service). Never charged. |
| 503 | payment_screening_unavailable | The payment check could not be completed (the chain read failed or timed out, or the sanctions list could not be read); retry after Retry-After and do not pay again. For a credit key that needs a new payment counted: details.reason credits_screening_unavailable. |
L402 reasons
Where L402 is on, a token that is refused carries one of these in details.reason. None of them spends the token or charges anything.
| Reason | Code | Meaning |
|---|---|---|
l402_malformed | payment_invalid | The Authorization: L402 <macaroon>:<preimage> header or the macaroon cannot be read. |
l402_bad_signature | payment_invalid | The macaroon was not issued by this server, or was changed after it was issued. |
l402_bad_version | payment_invalid | The macaroon identifier has a version this server does not issue. |
l402_unknown_caveat | payment_invalid | The macaroon has a caveat this server does not understand. |
l402_missing_caveat | payment_invalid | The macaroon lacks its route, price or expires caveat. |
l402_wrong_route | payment_invalid | The token was issued for a different route. |
l402_price_mismatch | payment_invalid | The token's price is below this route's sats price. |
l402_expired | payment_invalid | The token's expires time has passed. |
l402_preimage_mismatch | payment_invalid | The preimage does not hash to the invoice's payment hash (the invoice was not paid). |
l402_spent | payment_already_used | The token already paid for a different call. |
l402_invoice_cap | rate_limited | No new Lightning invoice: too many unpaid ones from your address (see Limits) (details.scope ip) or open on the server (global). Wait for Retry-After. When x402 can be offered, the answer is instead the usual 402 payment_required with the x402 offer, no L402 offer, this reason and Retry-After. |
two_payment_headers | invalid_request | Both an x402 payment header and an L402 Authorization header were sent. |
Credit key reasons
Where prepaid credit keys are on (POST /v1/credits/order, then Authorization: Bearer qpc_… on a paid route; Bitcoin signet, full service only), a refusal carries one of these in details.reason. None of them takes sats from the key. Before a payment to a key's address is credited, every input address of that payment is checked against the OFAC sanctions list; a payment with an input that has no address (a coinbase or bare script) cannot be checked and is held (held_sats, status held), not credited.
| Reason | Code | Meaning |
|---|---|---|
credits_amount | invalid_request | POST /v1/credits/order: sats is not a whole number from details.min_sats to details.max_sats. |
credits_order_cap | rate_limited | Too many credit orders from your address in the last hour; pay a key you have, or wait for Retry-After (details.retry_after_ms). |
credits_gap_full | payments_unavailable | POST /v1/credits/order: too many credit addresses in a row are still waiting for payment, so no new one is issued until one is paid or expires unpaid (see Payments). Pay a key you already have, or try again later. |
credits_no_key | invalid_request | GET /v1/credits without Authorization: Bearer <credit key>. |
credits_malformed | payment_invalid on a paid route, not_found on GET /v1/credits | The qpc_ key is not 47 characters of base64url. |
credits_unknown_key | payment_invalid on a paid route, not_found on GET /v1/credits | This server never issued that key. |
credits_insufficient | payment_required | The key has fewer confirmed, screened sats available than the route's price (details.price_sats); details also carries the key's address, status and balances. Pay the address again to top up. |
credits_payer_refused | payer_refused | A payment to the key's address came from an address on the sanctions list: the key is blocked for good and that payment is not credited. |
credits_screening_unavailable | payment_screening_unavailable | The key has fewer sats than the price, and its address could not be read and screened now (the chain read failed or timed out, or the sanctions list cannot be read), so a new payment may not be counted yet. Do not pay again: retry after Retry-After (details.retry_after_ms). Sats already credited still work. |
two_payment_headers | invalid_request | A credit key was sent with an x402 payment header. |
Results that are not errors
A 404, 500, bot wall, timeout or dead link on the page you asked about is a result, not an error. It comes back with status 200, a content_kind such as http_error or bot_wall, and a receipt, and it is charged. See How it works.