Furlpay Docs
Open App

Architecture

Rate Limits

Two layers: a Redis-backed baseline that backstops every mutating call, and tighter per-route budgets on anything that moves money or sends messages. Limits hold across all serverless instances.

The baseline

Every mutating request (POST/PUT/PATCH/DELETE) passes a per-IP budget of 150 requests per minute in the edge middleware. It is generous enough that no legitimate client hits it — it exists to blunt floods, not to meter usage. Signature-authenticated webhooks are exempt (providers batch deliveries from few IPs).

Per-route budgets

ParameterTypeDescription
POST /api/transfers/gaslessrequired12 / min / IPGasless relay — each call can submit an on-chain transaction.
GET /api/railsrequired60 / min / IPPublic rail discovery.
POST /api/docs/feedbackrequired10 / min / IPAnonymous docs feedback counters.
GET /api/x402/fxrequiredquote-gatedUnpaid requests get quotes; each paid call is naturally metered by the payment itself.
OTP / email routesrequiredtight per-routeSMS/email-sending endpoints carry the strictest budgets to prevent pumping.

Handling 429

A rejected request returns 429 with a Retry-After header (seconds):

typescript
const res = await fetch("/api/transfers/gasless", { method: "POST", body });
if (res.status === 429) {
  const wait = Number(res.headers.get("retry-after") ?? "5");
  await new Promise((r) => setTimeout(r, wait * 1000));
  // retry ONCE — if it 429s again, back off exponentially
}
  • Respect Retry-After exactly — retrying earlier just resets your window.
  • For agents: budget your call rate below the limit rather than treating 429 as flow control.
  • x402 flows should reuse the pending-settlement poll path instead of re-requesting quotes in a loop.

Limits are per deployment configuration

Budgets are conservative launch values and rise per rail as volume and monitoring mature. The values above are current defaults, not contractual ceilings.
Did this page help?
Edit this page on GitHub