{"version":1,"codes":{"TIMEOUT":"Request or upstream provider timed out. Retry later. Response includes retry_after_seconds (~20).","CONTENT_FILTERED":"Output blocked by safety/content moderation. Rephrase the prompt.","CONTENT_FILTERED_RETRY":"The upstream model's own safety filter refused the request, but our content screen passed it — so the payment was NOT spent and NOT refunded. Change the input (the prompt, or the image where the service takes one) and call again with the SAME paymentId; the retry is free. The retry must START before rework_until (ISO time, 10 minutes after the last refusal; rework_seconds_left gives the same deadline counted from this response). After it the call is refused with REWORK_EXPIRED and the payment is refunded. Response includes attempt, retries_left, retries_max, rework_until, rework_seconds_left, rework_token (a per-refusal secret: send it as reworkToken with the retry — the retry is refused with REWORK_TOKEN_INVALID without it — or with the paymentId to /api/decline-retry to take the refund instead) and, on a content refusal, cause, fix, model_said (the model's own words) and refusal_scope (prompt | image-or-prompt | input-or-output). At the cap the payment is refunded in full.","REWORK_EXPIRED":"The free retries for this payment ended at its rework_until deadline, so the call was refused and nothing ran. The payment was not used; its refund opens within 15 minutes — claim it at /recover.","REWORK_TOKEN_INVALID":"This payment is in a free retry, and the retry must carry the rework_token from the refusal that offered it (as reworkToken). The paymentId alone is not enough. Nothing ran and nothing was spent. Without the token, the payment is refunded within 15 minutes after rework_until; claim it at /recover.","CONTENT_POLICY_HELD":"The request was held for content review and was not delivered. Payment is held, not automatically refunded. Request human review using appeal_url. Response includes held, appeal_sats, and payment_id.","RATE_LIMITED":"Too many requests. Wait and retry. Response includes retry_after_seconds (~10).","INVALID_INPUT":"Request parameters were rejected. Fix and resubmit.","SERVICE_ERROR":"Generic upstream service failure. Try a different model or contact support.","PAYMENT_NOT_FOUND":"No payment exists with this paymentId. Pass the exact paymentId returned by create_payment.","PAYMENT_PENDING":"The Lightning invoice has not been paid yet. Pay it, then retry with the same paymentId. Response includes retry_after_seconds (~5).","PAYMENT_ALREADY_USED":"Each payment covers one tool call and this one is spent. Call create_payment again.","RESULT_NOT_AVAILABLE":"A free result request (GET /api/l402/job-status, MCP get_job_result or await_result) cannot hand over this video or 3D job's output: its payment was refunded, or the purchase settles only where the job started (a web purchase: the page's own result step). Nothing was charged by this request. If the payment was refunded, claim it at /recover with your payment ID.","L402_INVALID_PARAMS":"Pre-payment validation failed. No invoice was created; no sats charged.","L402_UPSTREAM_FAILED":"Upstream provider failed after payment. Refund issued via LNURL-withdraw.","L402_REFUND_ISSUED":"Response payload includes a `refund` object with an LNURL-withdraw link.","L402_AUTO_ROUTED":"Request was routed via model:'auto'. The chosen model id is in the X-Route-Model header.","L402_ESTIMATE_ONLY":"This response is a price estimate from /api/estimate-cost. No invoice was created.","L402_CALLBACK_INVALID":"callback_url was rejected. Must be public HTTPS (no loopback / private ranges). Polling still works.","REFUND_NOT_AVAILABLE":"POST /api/l402/refund cannot refund this payment: it was delivered, it was already refunded, or an automated refund is already queued for it. When the response carries `refund_status`, claim that refund at /recover with your payment ID instead.","BOOK_QUALITY_CHECK_FAILED":"Source EPUB chapters failed runtime sanity checks (empty, undecoded HTML entities, mojibake, parser overlap, or wrong language). Refund issued. Webhook payload includes `smoke_failures` with per-chapter detail.","OUTPUT_DURATION_INSANE":"Rendered audiobook reports an impossible duration (>24h) — usually mixed audio formats from upstream TTS providers corrupting the AAC metadata. Refund issued. Webhook payload includes `output_duration_seconds`."},"response_envelope":{"error":"string — human-readable message (provider names stripped)","error_code":"string — one of the keys in `codes` above","suggestion":"string — what the agent should do next","example":"string — concrete next-action example","retry_after_seconds":"number — present only when the code is retryable: TIMEOUT (~20s), RATE_LIMITED (~10s), PAYMENT_PENDING (~5s); how long to back off before retrying","refund":"object — present when a post-payment failure triggered an LNURL-withdraw refund; contains lnurl_withdraw, amount_sats (refund_amount is a deprecated alias), refund_secret, status, charge_id"},"docs_url":"https://sats4ai.com/docs#error-codes"}