Payments
x402 + USDC
LettersByLetter implements HTTP-native x402 v2 concepts. Protected resources return 402 with a base64 JSON PAYMENT-REQUIRED header. Clients retry with PAYMENT-SIGNATURE. Success includes PAYMENT-RESPONSE.
Flow
1. POST /api/v1/credits { "amountCents": 5000 }
2. 402 Payment Required
Header PAYMENT-REQUIRED: base64(PaymentRequired)
accepts[] includes:
- scheme: exact
- network: eip155:8453 (USDC on Base)
- network: solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp
3. Client signs EIP-3009 transferWithAuthorization (or Solana exact payload)
4. Retry the same URL with PAYMENT-SIGNATURE: base64(PaymentPayload)
5. 200 OK + PAYMENT-RESPONSE: base64(SettlementResponse)
Credits are added 1:1 with USD cents.curl
curl -i -X POST "$HOST/api/v1/credits" \
-H "Authorization: Bearer lbl_your_key" \
-H "Content-Type: application/json" \
-d '{"amountCents":1000}'
# Decode PAYMENT-REQUIRED, sign, then:
curl -i -X POST "$HOST/api/v1/credits" \
-H "Authorization: Bearer lbl_your_key" \
-H "PAYMENT-SIGNATURE: $SIGNED_PAYLOAD" \
-H "Content-Type: application/json" \
-d '{"amountCents":1000}'Facilitator
Set X402_FACILITATOR_URL to a Coinbase CDP-style facilitator exposing /verify and /settle. If unset, a mock facilitator accepts well-formed demo signatures so the 402 → pay → retry path can be tested locally.
Merchant wallets come from X402_PAY_TO (Base) and X402_PAY_TO_SOLANA. Never commit those keys; only public receive addresses belong in env.
The dashboard Billing page can mint a demo PAYMENT-SIGNATURE and settle against the same path — useful when a wallet is not connected.