FurlPay Docs
Open App
  • Introduction
  • Quickstart
  • For AI Agents
  • Monorepo
  • API Routes
  • Authenticationnew
  • Webhook Eventsnew
  • Error Codesnew
  • Rate Limitsnew
  • Agentic Payments (x402)
  • Agent Trust & Mandates (TAP)
  • CCTP Cross-Chainnew
  • LI.FI Swapsnew
  • FurlPay Travels (Travel MCP)
  • Solana Actions & Blinks
  • Claude Connectornew
  • AI Assistants
  • Stripe Crypto
  • Persona KYC
  • MiCA Roadmap
  • Security Posturenew
  • MPC & WebAuthn
  • Help Centernew
  • 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" }
}

x402 endpoints are special: a rejected payment returns 402 with an error string and a fresh accepts quote, so an agent can recover in one round-trip.

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 on this deployment or rail paused.

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.
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