Developer payments

x402 payments for developers

Send a First-Class letter, Certified Mail piece, or full-color postcard to a US address and pay for the approved order with USDC using x402 v2. Both 5.5 × 4.25 single-sided and 8.5 × 5.5 two-sided postcards are supported. No credit top-up is required for direct order payment. Protected resources return 402 with a base64 JSON PAYMENT-REQUIRED header. Clients retry with PAYMENT-SIGNATURE. Success includes PAYMENT-RESPONSE.

Coinbase Bazaar discovery

The order endpoint /api/v1/orders, standard-mail endpoint /api/v1/letters and credit endpoint /api/v1/creditsinclude Bazaar input schemas, public examples and a service description in their payment challenges. Unauthenticated, unpaid requests return public price previews only. Purchases and mailing submissions require a workspace Bearer API key. Public mail previews show a sample one-page price only. A ready product quote fixes the actual artwork, recipients, options and order total before payment.

Credit purchases start at $1 USDC and fund the workspace without sending mail. Discovery metadata is attached by the server during payment verification and settlement. A successful settlement can trigger Coinbase indexing; metadata availability alone does not confirm a listing. Stateful MCP mailing tools retain their quote-and-approval workflow and are not advertised as independently callable Bazaar resources.

Pay for a letter or postcard

The API reference describes catalog discovery and PDF quote creation. After reviewing and approving the quote, the order payment below charges its full total directly, even when the workspace has credits. The sample 199-cent amount is illustrative; the saved quote is authoritative.

A successful payment and mailing submission returns a receipt. This is not postal delivery confirmation. A 409 response with payment_outcome_unknown, authorizing or needs_review requires checking the saved quote. Do not pay again or create another order. charged: null means the charge is unknown, not zero. A rejection before settlement returns charged: false and mailed: false.

Staging and simulation quotes cannot accept payments here. Email automation retains its prepaid-credit workflow. MCP profiles retain their existing funding permissions; this direct-order route is available through the REST API.

Flow

1. POST /api/v1/product-quotes with PDF artwork, options and US addresses.
   Wait for status:ready; review the exact artwork, recipients and total.
2. After customer approval, POST /api/v1/orders
   { "quoteId": "quote_...", "confirmed": true, "expectedTotalCents": 199 }
   The total above is illustrative; use your saved quote total.
3. 402 Payment Required
   Header PAYMENT-REQUIRED: base64(PaymentRequired)
   accepts[] includes (live stables):
     - scheme: exact · network: eip155:8453 · USDC on Base
     - scheme: exact · network: solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp · USDC on Solana
4. Client signs EIP-3009 transferWithAuthorization (or Solana exact payload)
5. Repeat the identical approved body at /api/v1/orders with PAYMENT-SIGNATURE: base64(PaymentPayload)
6. 201 Created + PAYMENT-RESPONSE: base64(SettlementResponse)
   The approved mailing is submitted; workspace credits are unchanged.
   Recover with GET /api/v1/product-quotes?id=quote_... .

curl

HOST=https://directmailamerica.com
curl -i -X POST "$HOST/api/v1/orders" \
  -H "Authorization: Bearer lbl_live_your_key" \
  -H "Content-Type: application/json" \
  -d '{"quoteId":"quote_from_previous_step","confirmed":true,"expectedTotalCents":199}'

# Decode PAYMENT-REQUIRED, sign, then:
curl -i -X POST "$HOST/api/v1/orders" \
  -H "Authorization: Bearer lbl_live_your_key" \
  -H "PAYMENT-SIGNATURE: $SIGNED_PAYLOAD" \
  -H "Content-Type: application/json" \
  -d '{"quoteId":"quote_from_previous_step","confirmed":true,"expectedTotalCents":199}'

Facilitator

Settlement is on-chain. Set X402_FACILITATOR_URL to a facilitator that exposes Coinbase CDP-style /verify and /settle and returns a real transaction hash. Missing facilitator URL or keys fail closed — the payment is not marked paid and no credits or jobs are recorded. The server never invents or hex-encodes a placeholder hash.

For USDC on Base the client signs EIP-3009 transferWithAuthorization. After settle, History / billing stores the Base transaction hash and links it on Basescan.

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 Coinbase CDP facilitator authenticates with a per-request JWT from CDP_API_KEY_ID and CDP_API_KEY_SECRET. A static X402_FACILITATOR_API_KEY Bearer is only a fallback for non-CDP facilitators. Optional X402_EVM_RPC_URL / BASE_RPC_URL add Base receipt proof.

Payments and checkout

send_letter with an explicitly approved saved quoteId, matching approvedTotalCents, sufficient workspace credits and idempotencyKey reserves the total durably and sends once. If credits are short, no partial credit payment is taken: x402 requests the full total, or you can fund the workspace by card first. Supplying paymentSignature explicitly selects x402 even if credits are available. Obtain authorization for the physical mailing and total before calling a paid send tool.

For guest send_letter, first create and explicitly approve a saved quote_letter. The approved unpaid send, or purchase_credits without payment, returns payment_required with PAYMENT-REQUIRED and accepts[]. Standard Streamable HTTP clients receive an HTTP 200 MCP tool error; legacy JSON-only callers receive HTTP 402. Choose a currently offered asset/network and sign its payload; retry the same request with paymentSignature or PAYMENT-SIGNATURE. The server verifies and settles it; do not separately transfer funds or settle it yourself. Success includes PAYMENT-RESPONSE. Supported live assets are USDC on Base (eip155:8453) and Solana (solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp); the returned challenge is authoritative for network, token, amount and recipient.

purchase_credits requires a Bearer key, minimum 100 cents ($1), default 1000 cents ($10). create_credit_checkout returns a Square hosted Payment Link: amountCents is the amount to add, purpose=credits has a 100-cent minimum, and purpose=mailing has a 1-cent minimum. Never send card numbers, CVV, private keys or seed phrases to MCP. The human pays through Square.

After card checkout, call reconcile_credit_payment with paymentId using OAuth or a key for the same workspace. A paid result credits the balance once. Then call the chosen send tool after approval; purpose=mailing does not automatically mail anything. send_product_quote supports workspace credits only through MCP, so top up first. The website also offers its own on-site Square checkout.

Staging, errors and safe retries

lbl_test_ keys and guest environment=staging prevent real postage and dry-run fulfillment. They do not guarantee free calls, isolate workspace credits, select Square sandbox or switch x402 to testnet. Credit debits and payment settlements can still be real. Use public read-only quotes/catalogs for no-charge checks, and a separately configured local payment sandbox for payment tests.

Inspect the JSON-RPC error, result.isError and result.structuredContent.error; HTTP 200 alone does not mean success. Tool results also contain a JSON text copy in result.content. Payment challenges are MCP tool errors with PAYMENT-REQUIRED (HTTP 402 for legacy JSON-only clients); authentication uses HTTP 401 with OAuth resource metadata. OAuth permission failures are tool errors with mcp/www_authenticate metadata. Examples below contain placeholders and are not mailing approval.

Every send_letter requires a reviewed quoteId, confirmed:true, approvedTotalCents and idempotencyKey (16-128 letters, digits, underscores or hyphens). Generate it once per intended mailing and reuse for identical retries; changed payload reuse is rejected. Uncertain results retain the debit and block resubmission. Reconcile the intent, list_jobs, get_letter_status and billing before using a new key or signing another payment. get_letter_status reads the stored status and does not itself refresh mailing status. In Production does not mean delivered, and tracking may remain pending or be unavailable for the product.

send_product_quote retries must reuse the same saved id. authorizing or needs_review requires reconciliation; do not create a replacement order. An expired unsent quote needs a new quote and total review. reconcile_credit_payment can safely be repeated for the same checkout without adding credits twice.

A standard fulfillment failure before acceptance for production refunds a credit-funded send. If x402 was captured, fulfillment_failed_payment_captured returns the amount as workspace credits (and guestApiKey for a new guest); this is not an on-chain refund. Reconcile the failure and balance before retrying with the workspace key. Preserve job, quote and payment IDs for support.