# Errors, charging, retries and limits

Schema lordevo.errors/1. A payment is settled (charged) only when our answer is below 400. Any status >= 400 is not settled, so you are not charged; error bodies say "charged": false. Exception: long service jobs are settled when accepted (202); a later failure is not refunded automatically and is reported to the owner.

Error body: `{"error": "<code>", "message": "<human text>", "charged": false, ...optional "retry_after_seconds"}`

| Status | Codes | When | Charged? | Retry |
|---|---|---|---|---|
| 200 |  | Answered. Quick checks and data tools answer in the same request. "partial": true means part of the work could not finish; the parts that did are in the answer and "failed", "not_checked" or the per-item results name the rest. "cache.stale": true means the source was down and this is an older answer; cache.age_seconds says how old. | Yes when you sent a payment (it is settled after the answer). Free-trial calls, discovery, A2A message/send, MCP list/sample tools, preflight and polling are free. | No need. |
| 202 |  | Long service jobs (deep security scan, content plan, article, fix plan, site report): the job was accepted and runs in the background. The body has delivery_id, status "running" and result_url. | Yes: the payment is settled when the job is accepted. If the job fails afterwards there is no automatic on-chain refund: the failure is logged, the owner is alerted and the delivery shows status "error". | Poll result_url (free) every 30-60 s until status is "done" or "error". Results and links expire after 30 days (then 410). |
| 400 | missing_parameter, bad_json, bad_url, bad_target, bad_key, topic_required, brief_too_large, bad_request, invalid parameter codes per tool | Missing or invalid input on a request that sent a payment or asked for the free trial. An unpaid request with invalid input gets the 402 terms plus input_hint instead (see 402). The body names the bad input in "field" and gives a working "example" and "example_input". | No ("charged": false). | Fix the input; do not retry as is. |
| 402 | payment required (no payment sent), payment refused at verification (payment sent), free_trial.status: used_up_today / daily_cap_reached / not_eligible | x402 payment terms. v2: the PAYMENT-REQUIRED header (base64 JSON, x402Version 2, accepts[]) - retry the same request with PAYMENT-SIGNATURE. v1: the same terms in the JSON body (x402Version 1, accepts[] with maxAmountRequired) and X-PAYMENT-REQUIRED - retry with X-PAYMENT. Network eip155:8453 (Base), asset USDC, scheme exact. If the input is invalid, the body also has input_hint (error, message, field, example, example_input) and the header X-Lordevo-Input-Error: fix the input before you pay, because a paid call with that input is refused with a 400 and not charged. A final 402 after you sent a payment means the payment was not accepted (balance, amount, network or expiry). | No. | Pay and retry once (any x402 client does this). After a refused payment, check the USDC balance on Base and sign a new payment. |
| 403 | robots_disallowed (fetch tools), authorization_required, ownership_verification_required, ownership_not_verified | robots.txt does not allow the shop to fetch that URL (checked for every redirect hop before it is requested), or a service needs the authorization statement / verified ownership first. | No. | Pick another URL, or complete the free verify steps first. |
| 404 | not_found | Unknown tool, product, delivery or key. | No. | No. |
| 405 | method_not_allowed | Wrong HTTP method (e.g. GET /mcp; HEAD with a payment header). | No. | Use the documented method. |
| 409 | payment_in_use (Retry-After 5), not_ready (report formats of a running delivery) | The same signed payment is already being processed by another request (sent twice at once), or a delivery is not finished yet. | No (the copy is refused without work; the first request decides). | Do not resend the same payment in parallel; make a new call with a new payment. For not_ready, poll later. |
| 410 | expired | Delivery links older than 30 days. | No. | No. |
| 413 | body_too_large, pdf_too_large | Request body over the limit (quick tools 2 MB, MCP 2 MB, A2A 64 KB, services 16 KB) or a target file over the tool's cap. | No. | Send less. |
| 422 | dns_not_found, target_http_error, no_readable_content, all_failed, not_a_feed, no_feed_found, not_pdf, pdf_encrypted, pdf_unreadable, pdf_no_text, bad_schema, unrepairable, bad_regex, regex_timeout, too_long_for_mode, diff_timeout, date_out_of_range, unprocessable | The input passed validation but could not be used: the target does not resolve or answered an error, the file is not what the tool reads, or the data cannot be processed. Also used after a payment was verified. | No: an answer >= 400 is never settled, even after you sent a payment. | Do not retry as is; fix the target or input. |
| 429 | rate_limited (Retry-After 3600), busy, one_at_a_time, daily_limit, daily_cap_reached | Free features over their caps (free ownership verification 5/day start and 40/day checks per IP; free preflight 30/day per IP, 3000/day overall, one at a time per IP), or a service backend is busy. | No. | Wait Retry-After seconds (or retry_after_seconds in the body), then retry once. |
| 499 | client_closed | Your connection closed (timeout or cancel) before a paid quick check could send its answer. The payment is not settled. You will not see this answer; it is listed so you know a cancelled call costs nothing. If you cancel while the payment is already being settled, the payment may still go through: we are alerted and review such payments for a refund. | No. | Wait at least the tool timeout (table below) plus 10 s before you cancel, and do not cancel the other calls of a batch when one of them fails. |
| 500 | internal | Unexpected error on our side. | No. | Retry once after a few seconds; tell us if it repeats. |
| 502 | target_unreachable, target_bad_body, backend_error, engine_error, delivery_failed, Facilitator verify request timed out / Facilitator verify failed (x402 library text; MCP: verify_failed) | The target site or one of our backends failed (could not connect, broke off, could not start the job), or the payment facilitator could not check your payment in time (nothing was run). | No. | Retry later; for a target site, check it is up (the free preflight helps). After a facilitator error, the same signed payment can be sent again (it was not settled), or sign a new one. |
| 503 | busy (Retry-After 5; AI tools 30), not_for_sale_yet, backend_unavailable (Retry-After 300), backend_not_ready, payments_not_running | At capacity (12 quick checks run at once, at most 6 of them AI tools; the local AI model is shared; a paid call first waits up to 8 s for a free slot), a product not on sale yet, or a backend down. Checked before the 402 where possible, so you are not asked to pay for something that cannot run now. | No. | Wait Retry-After seconds, then retry once. |
| 504 | timeout, target_timeout | The check or the target site took longer than the tool timeout (table below). | No. | Retry later or with a lighter target. |

## MCP and A2A
- **MCP (POST /mcp)**: JSON-RPC 2.0. Parse error -32700 (HTTP 400). Batches of 1-20 messages, otherwise -32600 (initialize-based clients only). MCP 2026-07-28 requests (per-request _meta): unsupported protocol version -32022, header mismatch -32020, missing _meta fields -32602 (all HTTP 400), unknown method -32601 (HTTP 404). Unknown tool -32602. Tool errors come back as results with isError: true and the same error codes as HTTP; paid tools return the x402 terms as a result and you retry with _meta["x402/payment"].
- **A2A (POST /a2a)**: JSON-RPC 2.0, protocol 0.3.0, message/send only. Parse error -32700 (HTTP 400). Free: it never charges; it answers with the endpoint, price and payment terms of the tool you name. GET/HEAD /a2a answer 200 with a short description.

## Idempotency
There are no idempotency keys. One signed x402 payment pays for one call: the same payment sent twice at once gets 409 payment_in_use for the copy, and a payment that was already settled cannot be settled again (the facilitator refuses it, 402). A payment that was not settled (answer >= 400) did not move money; to retry, sign a new payment. Quick-check answers are cached per input for a few minutes for some tools (cache_seconds below; the answer says cache.hit), so a retry right after a success returns the same result and is charged again only if you pay again.

## Limits
```json
{
  "body": {
    "quick": "2mb",
    "precheck": "16kb",
    "a2a": "64kb",
    "mcp": "2mb",
    "services": "16kb"
  },
  "quick_checks_at_once": 12,
  "mcp_batch_max": 20,
  "free_trial": {
    "per_ip_per_utc_day": 3,
    "http_per_day": 200,
    "mcp_per_day": 100,
    "tools_priced_up_to_usd": 0.005,
    "note": "add trial=1 (or X-Lordevo-Trial: 1; MCP \"trial\": true); failed calls do not count; when used up the answer is the normal 402"
  },
  "free_preflight": {
    "per_ip_per_utc_day": 30,
    "per_day": 3000,
    "concurrent": 8,
    "hop_timeout_seconds": 8,
    "deadline_seconds": 25
  },
  "free_verification": {
    "starts_per_ip_per_day": 5,
    "checks_per_ip_per_day": 40
  },
  "delivery_ttl_days": 30
}
```

## Timeouts per tool
| Tool | Price | Timeout (s) | Cache (s) | POST body |
|---|---|---|---|---|
| agent-readiness | $0.002 | 40 | 0 | no |
| broken-links | $0.002 | 45 | 0 | no |
| can-fetch | $0.002 | 20 | 600 | no |
| canonical-check | $0.002 | 20 | 3600 | no |
| cors-check | $0.002 | 20 | 300 | no |
| cron-next | $0.002 | 8 | 0 | no |
| csv-parse | $0.002 | 12 | 0 | yes |
| date-calc | $0.002 | 5 | 0 | no |
| dns-lookup | $0.002 | 12 | 120 | no |
| domain-intel | $0.002 | 30 | 0 | no |
| domain-lookalike | $0.002 | 5 | 0 | no |
| domain-rdap | $0.002 | 20 | 86400 | no |
| email-auth | $0.002 | 45 | 0 | no |
| email-validate | $0.002 | 15 | 600 | no |
| federal-register | $0.002 | 20 | 900 | no |
| feed-parse | $0.002 | 45 | 600 | no |
| http-ping | $0.002 | 20 | 0 | no |
| ip-info | $0.002 | 20 | 86400 | no |
| json-query | $0.002 | 8 | 0 | yes |
| json-repair | $0.002 | 10 | 0 | yes |
| json-schema-infer | $0.002 | 8 | 0 | yes |
| json-validate | $0.002 | 12 | 0 | yes |
| link-check | $0.002 | 30 | 300 | no |
| link-preview | $0.002 | 20 | 3600 | no |
| links-batch | $0.002 | 45 | 0 | no |
| math-eval | $0.002 | 5 | 0 | yes |
| myr-rates | $0.002 | 20 | 900 | no |
| page-diff | $0.002 | 30 | 0 | yes |
| page-markdown | $0.002 | 45 | 0 | no |
| page-markdown-batch | $0.01 | 60 | 0 | no |
| page-meta | $0.002 | 45 | 0 | no |
| page-quality | $0.005 | 75 | 0 | no |
| pdf-text | $0.002 | 45 | 3600 | no |
| prompt-injection-scan | $0.002 | 8 | 0 | yes |
| readability | $0.002 | 20 | 3600 | no |
| redirect-chain | $0.002 | 45 | 0 | no |
| regex-test | $0.002 | 8 | 0 | yes |
| sec-filings | $0.002 | 25 | 600 | no |
| security-headers | $0.002 | 45 | 0 | no |
| security-scan-lite | $0.02 | 60 | 0 | no |
| seo-audit-lite | $0.002 | 60 | 0 | no |
| seo-page | $0.002 | 45 | 0 | no |
| site-check | $0.02 | 50 | 0 | no |
| site-snapshot | $0.02 | 45 | 0 | no |
| site-verdict | $0.01 | 75 | 0 | no |
| sitemap-urls | $0.002 | 40 | 3600 | no |
| ssl-cert | $0.002 | 15 | 3600 | no |
| structured-data | $0.002 | 20 | 3600 | no |
| tech-stack | $0.002 | 45 | 0 | no |
| text-chunk | $0.002 | 30 | 0 | yes |
| text-diff | $0.002 | 12 | 0 | yes |
| text-extract | $0.002 | 8 | 0 | yes |
| time-convert | $0.002 | 5 | 0 | no |
| token-count | $0.002 | 5 | 0 | yes |
| unit-convert | $0.002 | 5 | 0 | no |
| url-clean | $0.002 | 5 | 0 | yes |
| url-trust | $0.002 | 40 | 0 | no |
| verdict-card | $0.01 | 75 | 0 | no |

## Versioning
Output schemas are versioned (e.g. site-report/1, trust/2, lordevo.status/1). Within a version we only add fields; renaming or removing a field, or changing its meaning, means a new version, a dated /changelog entry before it goes live, and the old fields kept (marked deprecated) where possible. OpenAPI info.version follows semver.

Status: https://shop.lordevo.com/status · Changelog: https://shop.lordevo.com/changelog · Samples: https://shop.lordevo.com/samples
