Skip to main content

Payments

Unwall provides three payment rails — x402 protocol, on-chain USDC transfer, and fiat ACH — all accessible through a single endpoint. The POST /v1/pay endpoint auto-routes to the correct rail based on the recipient field.

Unified Endpoint

POST /v1/pay
The endpoint inspects the recipient value and routes automatically:
Recipient FormatRailExample
URL (https://...)x402 Protocol"https://api.example.com/v1/data"
Ethereum address (0x...)USDC Transfer"0x742d35Cc6634C0532925a3b844Bc9e7595f2bD18"
Object with bank detailsFiat ACH{"name": "Acme Corp", "account_number": "...", ...}
No rail selection logic is needed in your agent. Just provide the recipient and Unwall handles the rest.

Three Payment Rails

x402 Protocol

Pay for API calls in USDC using the HTTP 402 payment standard. When the recipient is a URL:
  1. Unwall proxies your request to the target API.
  2. If the API returns HTTP 402 with payment requirements, Unwall parses the payment details.
  3. Unwall signs a USDC authorization (EIP-3009) and retries the request with payment attached.
  4. The API response is returned to your agent.
If the target API responds normally (no 402), the response is passed through at no charge.
Set max_amount_usdc to cap how much your agent can spend per x402 call. See the x402 Protocol guide for details.

USDC Transfer

Send USDC on-chain to any Ethereum address on Base. The transfer is executed through Bridge.xyz and recorded in the ledger.

Fiat ACH

Convert USDC to USD and send via ACH bank transfer. Provide the recipient’s name, account number, routing number, and email. Bridge.xyz handles the off-ramp conversion and transfer.
ACH transfers are not instant. Expect 2-3 business days for settlement.

Fee Model

Fees are tier-based and charged on top of the payment amount:
PlanFee Rate
Free2%
Pro1.5%
Business1%
For example, if you send a 100paymentontheProplan,100 payment on the Pro plan, 101.50 is debited from your wallet (100payment+100 payment + 1.50 fee). The fee is recorded as a PLATFORM_FEE transaction in the ledger.

Idempotency

Include an idempotency_key in your request to prevent duplicate payments. If a request is retried with the same key, the original transaction is returned without creating a new one.
{
  "recipient": "0x742d35Cc6634C0532925a3b844Bc9e7595f2bD18",
  "amount_usd": 50.00,
  "idempotency_key": "invoice-1234-payment"
}
Idempotency keys are unique per project. The same key can be used in different projects without conflict.

Transaction Lifecycle

Every payment goes through a defined set of statuses:
pending → processing → completed
                    ↘ failed
                    ↘ reversed
StatusMeaning
pendingPayment recorded, not yet submitted to the payment provider
processingSubmitted to Bridge.xyz or x402 facilitator, awaiting confirmation
completedPayment settled successfully
failedPayment failed. Balance is automatically credited back to the project.
reversedPayment was reversed after completion (e.g., ACH return)

Safety Guarantees

Balance is debited using ledger RPC functions with PostgreSQL advisory locks for per-project serialization. Two concurrent payment requests cannot both succeed when only enough balance exists for one.
The project balance is never served from cache when authorizing a payment. It is always fetched directly from the ledger to prevent overdraw.
If a payment fails after the balance has been debited, the amount is automatically credited back to the project. If the rollback itself fails, the error is captured in Sentry for manual resolution.
For x402 payments, the max_amount_usdc field ensures an agent never pays more than intended for a single API call.

Deprecated Endpoints

The following endpoints still work but POST /v1/pay is the recommended replacement:
Deprecated EndpointRailReplacement
POST /v1/paymentsFiat ACHPOST /v1/pay with bank details recipient
POST /v1/x402/payx402 ProtocolPOST /v1/pay with URL recipient
POST /v1/usdc/transferUSDC TransferPOST /v1/pay with 0x address recipient

Next Steps