How it works
Everything an agent or a seller needs: the quote, the payment, the receipt, the errors and the rules we keep.
One call
- The agent sends
POST /v1/buy/<item>with its JSON input and no payment. It gets402and a quote. - The agent builds one Solana transaction from the quote, signs it and sends the same request again with the transaction, base64, in the
X-Paymentheader. - The gateway checks the transaction is exactly the quoted payment, signs it as fee payer and simulates it. Then it calls the seller.
- Only after the seller answers with 2xx is the transaction sent. When it confirms, the agent gets the answer and a receipt.
The kit does all of this in one call: bodega buy <item> key=value.
The quote
| Field | Meaning |
|---|---|
sellerAccount, sellerAmount | The seller's USDC account and what it gets, in units of 0.000001 USDC. |
feeAccount, feeAmount | The fee wallet's USDC account and the fee. Zero when the seller holds the token. |
feePayer | Our key that pays the network fee and signs last. Your agent needs no SOL. |
blockhash | A recent blockhash, so the kit needs no RPC of its own. A payment lives about a minute. |
ref | Goes in the memo, so each payment is unique. |
The payment
One transaction, signed by the agent key and our fee payer, with these instructions and nothing else:
- a compute unit limit, up to 40,000, and optionally a compute price up to 50,000 micro-lamports;
- a USDC
TransferCheckedto the seller and one for the fee, both from the same account; - one memo,
bodega:<ref>.
The agent key signs either as the owner of the USDC account or as its delegate. A delegate can spend only the allowance the owner set on the agents page.
The receipt
A paid call returns { item, result, receipt }. The receipt has the transaction, an explorer link, what was paid, what the seller got and the fee. The same receipt comes base64 in the X-Payment-Response header.
If the transaction was sent but has not confirmed in about 20 seconds, the call returns 202 with receipt: /v1/receipt/<tx>. The answer waits there for ten minutes and is handed over once the chain shows the payment. If it never lands, nothing was charged and no answer is given.
Errors
| Code | What happened | Charged |
|---|---|---|
402 payment_required | No payment yet: here is the quote. | No |
402 wrong_amount, wrong_recipient, unexpected_instruction | The transaction is not the quoted payment. | No |
402 over_budget, no_funds | The key may not spend this much, or the wallet does not hold it. | No |
402 would_not_settle | The payment would fail on chain, often because it is too old. Sign a new one. | No |
402 payment_used | That payment already bought an answer. | Once, before |
4xx seller_refused | The seller turned the input down. Their reply is in sellerReply. | No |
502 seller_failed, seller_unreachable | The seller errored or did not answer in 25 seconds. | No |
202 payment_pending | Sent, not confirmed yet. Fetch the receipt URL. | Once it lands |
Rules
- We never hold money. The buyer's USDC goes to the seller and the fee wallet in one transaction.
- The fee is 3% of the price, taken from the seller's part. A seller holding the token pays none.
- The seller carries one small risk: a buyer can empty the wallet between our check and the send. Then the seller answered for nothing. We check right before calling the seller to keep that short.
- Every forwarded call is signed for the seller with HMAC-SHA256. See Sell here.
- We can take an item off the shelf. Its owner cannot bring it back.
Endpoints
GET /v1 | Fee payer, fee, minimum price. |
GET /v1/shelf, /v1/shelf/<item> | The catalog with paid and failed counts. |
POST /v1/shelf | List, change or remove an item, signed by the payout wallet. |
POST /v1/buy/<item> | Buy one call. |
POST /v1/sample/<item> | A free call to a house item, limited per day. |
GET /v1/receipt/<tx> | The answer of a call that confirmed late. |
GET /v1/budget?owner= | A wallet's USDC, delegate and allowance. |
GET /v1/ledger, /v1/stats | Confirmed payments and totals. |