--- name: trustless-commerce-invoice description: >- Create Trustless Commerce crypto invoices and check payment status. Use when building or verifying USDC/USDT pay links, invoiceAddress, awaiting_payment, POST /api/invoices create invoice API, GET /api/invoices/:id polling, sweep status, Trustless Commerce checkout, Sepolia, Nile, fiat/crypto/combined paymentMode, GET /api/public/pay-in/quotes, /buy card funding, or crypto invoice integration for shops and agents. --- # Trustless Commerce — create & check invoices ## When to use - Create a payment link or embed button for a shop order - Call the one-shot create invoice API (`crypto`, `crypto_or_fiat`, or `fiat`) - Fund a Base USDC invoice with card/bank via `/buy` and `GET /api/public/pay-in/*` - Check whether an invoice is `created`, `awaiting_payment`, `paid`, `paid_partial`, or `swept` No merchant wallet connection is required for create or status check. ## Rate limits (read first) | Bucket | Default | Routes | |--------|---------|--------| | `create` | ~1/s/IP | `POST /api/invoices` | | `quote` | ~2/s, burst 20/IP | `/api/public/pay-in/` | | `public` | ~20/s/IP | other public GETs | **429** responses include `Retry-After`, `RateLimit-Remaining`, and `RateLimit-Reset`. Back off and retry — do not hammer create or quote. ## Canonical agent path (one step) ### Crypto — Sepolia USDC ```http POST /api/invoices Content-Type: application/json { "price": "10.00", "to": ["0x…"], "chains": ["11155111"], "tokens": ["USDC"], "clientInvoiceId": "order-1", "chainId": "11155111", "token": "USDC", "selectedTo": "0x…", "title": "Order", "allowPartial": false, "paymentMode": "crypto" } ``` ### Crypto — Nile USDT ```http POST /api/invoices Content-Type: application/json { "price": "10.00", "to": ["T…"], "chains": ["nile"], "tokens": ["USDT"], "clientInvoiceId": "order-1", "chainId": "nile", "token": "USDT", "selectedTo": "T…", "title": "Order", "allowPartial": false, "paymentMode": "crypto" } ``` Multi-chain links may include both an EVM `0x…` and Tron `T…` in `to`, with `chains: ["11155111","nile"]` and `tokens: ["USDC","USDT"]`. Pick `chainId` / `token` / `selectedTo` consistent with one kind when creating. **Do not** send `invoiceSeed` / `invoice_seed` — the API assigns a random seed and derives `invoice.id`. Client-supplied seeds are rejected (`400`). Response includes `invoice` (with `invoiceAddress`, status `awaiting_payment`), resume `payLink` (`/pay?id=…`), and `checkoutLink` (shareable template without seed). Duplicate invoice ids are rejected with `409`. Use `Idempotency-Key` for safe retries of the same create. **Do not** use deprecated `POST /api/sessions` + `POST /api/invoices/activate`. ### Crypto — Solana Devnet ```http POST /api/invoices Content-Type: application/json { "price": "10.00", "to": ["So111…"], "chains": ["devnet"], "tokens": ["USDC", "USDT"], "clientInvoiceId": "order-1", "chainId": "devnet", "token": "USDC", "selectedTo": "So111…", "title": "Order", "allowPartial": false, "paymentMode": "crypto" } ``` ### Combined (`crypto_or_fiat`) ```http POST /api/invoices Content-Type: application/json { "price": "49.00", "to": ["0x…"], "chains": ["8453"], "tokens": ["USDC"], "clientInvoiceId": "order-both-1", "chainId": "8453", "token": "USDC", "selectedTo": "0x…", "paymentMode": "crypto_or_fiat", "displayFiat": "EUR", "quoteCountry": "de" } ``` Payer chooses crypto or card on `/pay`. Card funding: `/buy?address={invoiceAddress}&amount=…&fiat=EUR&country=de&invoice={id}` (or the card panel on `/pay`). Quotes: `GET /api/public/pay-in/quotes`. Checkout URL: `GET /api/public/pay-in/widget`. Poll the invoice; do not create an onramp session. ### Fiat only Fiat invoices **require `price`** (USDC on Base). The API locks `chains`/`tokens` to `8453` / `USDC`. Optional `displayFiat` / `displayAmount` / `quoteCountry` are payer hints. ```http POST /api/invoices Content-Type: application/json { "price": "49.00", "to": ["0x…"], "chains": ["8453"], "tokens": ["USDC"], "clientInvoiceId": "order-fiat-1", "chainId": "8453", "token": "USDC", "selectedTo": "0x…", "paymentMode": "fiat", "displayFiat": "SEK", "displayAmount": "500.00", "quoteCountry": "se" } ``` Full docs: https://naiemk.github.io/onchain-invoice/invoice-types/ and https://naiemk.github.io/onchain-invoice/quote/ ## Pay link (browser) ```text /pay?price=10&to=0x…&chains=11155111&tokens=USDC&title=Order&allow_partial=0 /pay?price=10&to=T…&chains=nile&tokens=USDT&title=Order&allow_partial=0 ``` Optional chrome: `header=full` (default) | `minimal` | `none`. Use `none` inside an iframe (or omit `header` — embedded `/pay` defaults to no chrome). Gateways allow cross-origin framing of `/pay` only: ```html ``` Shareable checkout links never include `invoice_seed`. The API creates the seed when the payer continues (or when you call `POST /api/invoices`). After create, resume with `/pay?id=` (preserve `header` if present). Deterministic `invoiceId` = `keccak256(abi.encode(bytes32 invoiceSeed, string[] toAddresses))`. Uniqueness comes from a server-generated random `invoiceSeed`; `toAddresses` bind payout destinations. `clientInvoiceId`, price, title, etc. are metadata only (not part of the hash). `chains` / `tokens` are not part of the hash. Helpers: `ui/src/shared/invoice.ts`. Manual UI: `/create` (3-step wizard). Docs: https://naiemk.github.io/onchain-invoice/ ## Check status ```http GET /api/invoices/{invoiceId} ``` Poll every few seconds until `paid`, `paid_partial`, or `swept`.