Furlpay Docs
Open App

Architecture

API Routes

The API surface lives under apps/web/src/app/api as Next.js route handlers. Every request body is validated with zod; every mutation is written through the double-entry ledger.

Authentication

MethodPathDescription
POST/api/auth/webauthnRegister / authenticate a passkey (FIDO2)
POST/api/auth/otp/startSend a phone / email OTP (Twilio Verify)
POST/api/auth/googleSign in with Google Identity Services

Cards

MethodPathDescription
POST/api/cardsIssue a 2-of-2 MPC virtual card
POST/api/cards/settingsFreeze, set limits, update controls
bash
curl -X POST https://furlpay.app/api/cards/settings \
  -H "Authorization: Bearer sk_live_…" \
  -d '{ "cardId": "card_1a2b", "frozen": true, "spendLimit": 25000 }'

Investing & market data

MethodPathDescription
POST/api/investing/orderFractional stock / ETF order (Alpaca)
GET/api/investing/portfolioHoldings, cost basis and P/L

Quotes and fundamentals are sourced from the Twelve Data API; real-time execution and price streams run over Alpaca WebSockets.

Agentic payments (x402)

Furlpay speaks x402 — the HTTP 402 "Payment Required" protocol — so AI agents and API clients pay per-request in USDC with no account or key. An unpaid request returns a signed quote; the client pays and retries with an X-PAYMENT header.

MethodPathDescription
GET/api/x402/fxPay-per-call mid-market FX quote ($0.01 USDC)
bash
# 1. unpaid request → 402 with a payment quote
curl -i https://furlpay.com/api/x402/fx?from=USD&to=EUR&amount=100

# 2. sign the EIP-3009 authorization, then retry with the payment attached
curl https://furlpay.com/api/x402/fx?from=USD&to=EUR&amount=100 \
  -H "X-PAYMENT: $(base64_payload)"   # → 200 + X-PAYMENT-RESPONSE receipt

Verification is hardened against the authorization, binding, replay, and web-layer attack classes documented in 2026 x402 research. See /docs/payments/agentic-x402 for the full flow.

Solana Actions & Blinks

Shareable checkout links unfurl into signable payment widgets on X, Discord, and any Blink client.

MethodPathDescription
GET/actions.jsonBlink client discovery rules
GET/api/actions/pay/[orderId]Blink metadata (icon, label, buttons)
POST/api/actions/pay/[orderId]Return the base64 SOL/USDC transaction to sign

Webhooks & signature verification

MethodPathDescription
POST/api/webhooks/marqetaCard processor events
POST/api/webhooks/bridgeOn/off-ramp settlement events
POST/api/webhooks/wiseLocal bank account events

Every webhook carries a Furlpay-Signature header. Verify it against your endpoint secret before acting on the payload.

typescript
import { Furlpay } from '@furlpay/furlpay-node';

export async function POST(req: Request) {
  const raw = await req.text();
  const event = Furlpay.webhooks.constructEvent(
    raw,
    req.headers.get('furlpay-signature'),
    process.env.FURLPAY_ENDPOINT_SECRET!,
  );
  // event is now trusted — handle event.type
}

Idempotency

Send an Idempotency-Key header on POSTs so retries never double-issue a card or double-place an order.