FurlPay Docs
Open App
  • Services & Availability
  • Quickstart
  • For AI Agents
  • Monorepo
  • API Routes
  • Authenticationupdated
  • Webhook Eventsupdated
  • Error Codesupdated
  • Rate Limitsnew
  • Configuration & Setupnew
  • Merchant Paymentsnew
  • Payroll & Payoutsnew
  • Agentic Payments (x402)updated
  • Agent Trust & Mandates (TAP)updated
  • CCTP Cross-Chainupdated
  • LI.FI Swapsupdated
  • FurlPay Travels (Travel MCP)updated
  • Solana Actions & Blinks
  • Settlement Workspacenew
  • FURL Tokennew
  • Claude Connectorupdated
  • AI Assistants
  • Circlenew
  • Ramp Providersnew
  • Telegram Mini Appnew
  • Stripe Crypto
  • Persona KYC
  • Regulatory status
  • Screening & Casesnew
  • Security Postureupdated
  • Signing & WebAuthnupdated
  • Help Center
  • Getting Started
  • KYC Verification
  • Passkeys & Biometrics
  • Privacy & Data Protection
  • Transaction Statuses
  • Gasless Transfers
  • Deposits & Withdrawals
  • Managing Virtual Cards
  • Freezing & Unfreezing Cards
  • Declined Transactions
  • SDK & API Support
  • x402 Monetization Basics
  • Booking Travel
  • Travel Refunds & Cancellations

Resources

  • Changelog
  • System Status
  • OpenAPI Spec
  • Community
  • GitHub
Docs/Architecture/Error Codes

Architecture

Error Codes

Errors are boring on purpose: a machine-readable code, an optional human detail, and the right HTTP status. Nothing sensitive ever rides an error body.

Response shapes

Product APIs return a flat error object; ops APIs use the envelope with a request id:

jsonproduct API error
{ "error": "amount_over_limit", "detail": "amount exceeds the per-transaction limit ($500)" }
jsonops API error
{
  "ok": false,
  "error": { "code": "reason_required", "message": "A reason (min 8 chars) is required." },
  "meta": { "requestId": "req_…", "timestamp": "2026-07-12T00:00:00Z" }
}

When its operational controls are available, the x402 endpoint returns 402 with an error string and a fresh accepts quote. A control-plane failure returns 503 instead; on 11 October 2026 the production x402 endpoint returned503 controls_unavailable with reason plan_limit.

HTTP status conventions

  • 400 — validation failed (zod), malformed payload, bad parameters.
  • 401 — no valid session; 402 — payment required / payment rejected.
  • 403 — authenticated but forbidden (role, over-cap, policy).
  • 409 — conflict (replayed nonce, duplicate idempotency key with different body).
  • 423 — account locked; 429 — rate limited (check Retry-After).
  • 502 — upstream (chain RPC, provider) failed; 503 — feature not configured, rail paused, or operational controls unavailable.

Machine-readable codes

ParameterTypeDescription
amount_over_limitrequired403Amount exceeds the server-side per-transaction cap for the rail. The detail names the cap.
replay_rejectedrequired409 / 402The EIP-3009 nonce or quote was already used. Sign a fresh authorization — never resign the same nonce.
invalid_signaturerequired400 / 402Signature recovery did not match the payer (ECDSA and ERC-1271 both failed).
rail_pausedrequired503The rail is administratively paused. Retry after the status page clears.
controls_unavailablerequired503Current rail status cannot be read. Treat availability as unknown and do not submit a payment.
authorization_expiredrequired400validBefore has passed. Sign a fresh authorization.
quote_expiredrequired402The 402 quote TTL elapsed. Re-request the resource for a fresh quote.
settlement_pendingoptional202Submitted on-chain but confirmation not yet observed. Poll pending.statusPath — do NOT sign a fresh authorization until it resolves.
service_unavailablerequired503The feature is not configured on this deployment (e.g. no on-chain relayer). Production never fabricates success.
reason_requiredrequired400Ops control changes require a typed reason for the audit trail.
unknown_pageoptional400Docs feedback referenced a path outside the documentation.

Retries

Retry 429 after the Retry-After value and 502 with backoff. Never blind-retry 402 replay rejections or 202 pending settlements — both can double-pay; follow the recovery path in the body instead.
Did this page help?
Edit this page on GitHub

← Previous

Webhook Events

Next →

Rate Limits