/pay endpoint to settle. Ababil handles signature verification and the on-chain relay only.
You write: Frontend wallet connect, chain switching, EIP-3009 signing logic, and one settlement call.
Ababil handles: Signature verification, USDC balance check, on-chain transferWithAuthorization, and intent status update.
This path is required for AI agents paying programmatically. For browser-based human buyers, the Hosted Gateway is simpler to implement.
Flow
Step 1 — Create Intent
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
amount_usdc | number | ✓ | Payment amount in USDC. E.g. 29.99. |
description | string | Human-readable label. | |
order_id | string | Your internal order reference. | |
metadata | object | Arbitrary key-value pairs stored on the intent. |
Response 201
| Field | Description |
|---|---|
payment_requirements | One entry per chain the merchant supports. Pick the one matching the buyer’s chain. |
maxAmountRequired | Amount in atomic USDC units (×1,000,000). $29.99 = "29990000". |
usdcDomainName | Always read from the API — never hardcode "USD Coin". |
payTo | Merchant wallet address. Used as to in the EIP-3009 signature. |
checkout_url | Available even on custom integrations — use it as a fallback if needed. |
Step 2a — Sign EIP-3009 (EVM: Base, Ethereum, Arc)
Build and sign aTransferWithAuthorization EIP-712 typed data message with the buyer’s wallet.
Typed Data Structure
Signing Rules
| Field | Rule |
|---|---|
domain.name | Read usdcDomainName from payment_requirements — do not hardcode |
domain.chainId | Parse from payment_requirements[n].network — e.g. "eip155:84532" → 84532 |
domain.verifyingContract | The asset field from payment_requirements[n] |
message.to | The payTo field from payment_requirements[n] |
message.value | BigInt(maxAmountRequired) — integer atomic units, not a float |
message.validAfter | 0n (no lower bound) |
message.validBefore | BigInt(Math.floor(Date.now() / 1000) + 900) — must be before intent expires_at |
message.nonce | Fresh crypto.getRandomValues(new Uint8Array(32)) — never reuse |
| Sign method | eth_signTypedData_v4 |
Code Examples
Step 2b — Sign Solana SPL Transfer
Solana uses a two-step process: first fetch an unsigned transaction from Ababil (which requires the buyer’s public key), then sign it with the buyer’s Solana wallet.2b.1 — Build the Unsigned Transaction
200:
2b.2 — Sign with Phantom (browser)
Step 3 — Settle Payment
Submit the signed authorization to Ababil for on-chain settlement.- EVM (Base / Ethereum / Arc)
- Solana Devnet
Response 200
What Ababil Does Server-Side
- Validates the EIP-3009 signature (viem
verifyTypedData) or Solana transaction signatures. - Checks the buyer’s USDC balance is sufficient.
- Confirms the intent is still
pendingand not expired. - Calls
usdc.transferWithAuthorization(from, to, value, validAfter, validBefore, nonce, v, r, s)via relay EOA. - USDC moves directly buyer → merchant. Ababil never holds funds.
- Marks the intent
paidin the database withtx_hash,buyer_address, andpaid_at.