Pay-per-use inference over x402 — any Venice model, no API key, no account. Quote a request, sign an on-chain payment that satisfies the quote, and get the completion back. Access is gated by payment, so this same contract works for headless agents and browser wallets alike.
x402 + ERC-7710No buyer API keyOpenAPI 3.1
For agents
Point your agent at skill.md
One file teaches an agent the whole contract: discovery, quote-first pricing, ERC-7710 signing, retrieval, and multi-turn. Drop the URL into your tool config and let the agent read it.
There is no API key. Every paid completion is a single endpoint, POST /api/v1/inference, called twice. The first call carries no payment header, so DiemSum replies 402 Payment Required with a binding quote and a base64 PAYMENT-REQUIRED envelope. The second call re-sends the same body with a PAYMENT-SIGNATURE header, and the server verifies the payment, calls Venice behind the seller key, settles, and returns the completion.
5-minute quote TTLPaid body must match the quoteNo raw prompt retention — sha256 only
Walkthrough
Quote → pay → retrieve
The whole exchange in four moves. Keep the request body identical between the quote and the paid retry, or the server rejects it with 400 quoted_request_mismatch.
Request a quote (expect 402)
POST the request you actually want. Exactly one of prompt or messages[] is required; snake_case and camelCase keys are both accepted.
requesthttp
POST /api/v1/inference
Content-Type: application/json
{
"offerId": "offer_venice-llama-3_3-70b",
"messages": [
{ "role": "user", "content": "Explain x402 in one sentence." }
],
"maxOutputTokens": 512,
"buyerAddress": "0xYourBuyerOrPayerAddress"
}
Read the quote and envelope
The 402 carries the quote in the body and a base64 PAYMENT-REQUIRED header. The X-DiemSum-Quote-Id and X-DiemSum-Request-Hash headers echo the quote so you can correlate without parsing the body.
Build an x402 payload that satisfies accepts[0] exactly (same amount, asset, payTo, network), base64-encode it, and send it as PAYMENT-SIGNATURE on a re-send of the identical body.
paid retryhttp
POST /api/v1/inference
Content-Type: application/json
PAYMENT-SIGNATURE: <base64 x402 payload>
{ ...the EXACT same body you quoted in step 1... }
Retrieve the completion
A 200 returns the completion, a usage receipt, and a nextTurn lineage you keep for follow-ups.
// One paid completion = two POSTs to the SAME endpoint with the SAME body.
const base = "https://diemsum.com";
const body = {
offerId: "offer_venice-llama-3_3-70b",
messages: [{ role: "user", content: "Explain x402 in one sentence." }],
maxOutputTokens: 512,
buyerAddress: "0xYourBuyerOrPayerAddress",
};
// 1) Quote — no payment header, so the server answers 402.
const quoteRes = await fetch(`${base}/api/v1/inference`, {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify(body),
});
if (quoteRes.status !== 402) throw new Error(`expected 402, got ${quoteRes.status}`);
const { paymentRequirements } = await quoteRes.json();
// 2) Sign an x402 payload that satisfies accepts[0] exactly (ERC-7710
// delegation for agents; see docs/examples/direct-x402-erc7710.ts).
const paymentSignature = await signX402(paymentRequirements.accepts[0]);
// 3) Pay — re-send the IDENTICAL body plus PAYMENT-SIGNATURE.
const payRes = await fetch(`${base}/api/v1/inference`, {
method: "POST",
headers: {
"content-type": "application/json",
"payment-signature": paymentSignature,
},
body: JSON.stringify(body), // byte-for-byte identical or you get 400 quoted_request_mismatch
});
const result = await payRes.json();
console.log(result.completion.content);
Reference
Endpoint reference
Method
Path
Purpose
GET
/api/v1/offers
List buyer-callable offers. No auth — pick an offerId.
GET
/api/v1/market
Offers joined with the Venice reference price and savingsPct per offer.
POST
/api/v1/inference
Called twice: no payment header → 402 quote; re-send the identical body with PAYMENT-SIGNATURE → 200 completion.
GET
/api/v1/quotes/{quoteId}
Quote + payment envelope. 404 if unknown, 410 if expired.
GET
/api/v1/inference/{inferenceRequestId}
Status of a paid request. 404 if unknown.
Reference
Error codes
Every error carries a stable code alongside the HTTP status. Branch on the code, not the prose.
Status
Code
Meaning
402
payment_required
Quote issued. Pay and retry the identical body.
400
quoted_request_mismatch
The paid body does not reproduce the quoted request.
400
transcript_hash_mismatch
A supplied transcriptHash does not match the server hash.
400
invalid_payment_signature
The PAYMENT-SIGNATURE header could not be decoded.
402
verification_failed
The facilitator rejected the payment during verification.
409
settlement_in_progress
Settlement for this quote is mid-flight. Retry with the same PAYMENT-SIGNATURE shortly.
409
quote_not_payable
The quote was already consumed or canceled.
410
quote_expired
Quote older than the 5-minute TTL. Re-quote.
429
rate_limited
Back off using the Retry-After header.
502
settlement_failed
Venice ran but settlement failed: output is withheld and the request is marked withheld. Retry with the samePAYMENT-SIGNATURE to resume settlement and retrieve the stored output — Venice is not re-run. A background reconciler also retries withheld settlements automatically.
502
venice_execution_failed
Venice failed before output was produced; the reservation is released and nothing settles.
503
seller_route_unavailable
The seller route lost its key, approval, or capacity after quoting.
503
facilitator_config_missing
The deployment is not payment-capable.
500
paid_inference_failed
Server-side failure mid-payment. Retry with the same PAYMENT-SIGNATURE.
Two buyer identities
Direct agent vs browser human
Both paths speak the same x402 contract above. They differ only in how the payer authorizes the facilitator to pull funds.
Headless
Direct agent · ERC-7710
Your agent owns an EOA, upgrades or validates it for EIP-7702, and signs a direct ERC-7710 delegation to the quoted facilitator redeemers. No browser, no wallet UI.
Signs an x402 payload satisfying accepts[0] exactly.
Reference: docs/examples/direct-x402-erc7710.ts
Browser
Browser human · ERC-7715
A MetaMask user grants an ERC-7715 Advanced Permission once; the dapp redelegates it per quote. This is the Order UI path, not the headless agent path.
One permission grant covers many quotes within its budget.
The browser signs each per-quote redelegation in MetaMask.
Headless agents
Agent permission bootstrap
A long-running buying agent can obtain a scoped, recurring spending mandate from its human owner once, then pay for many inferences autonomously inside that budget — no human approval per call.
The agent opens a request with its own delegate address and a recurring budget. DiemSum returns an approval URL the human opens in a browser; they connect MetaMask and grant an ERC-7715 erc20-token-periodic permission whose delegate is the agent's own address — not a browser session key. The agent polls until the grant lands, stores it locally, and redelegates it per quote for each purchase.
Method
Path
Purpose
POST
/api/v1/agent-permissions/request
Open a request with agentAddress and periodAmountUsd. Returns 201 with the request, approvalUrl, and a poll target.
GET
/api/v1/agent-permissions/{requestId}
Poll for status. Returns request plus grant (null until granted). 404 if unknown.
POST
/api/v1/agent-permissions/{requestId}/grant
Posted by the permit page after the human signs, carrying the granted permission context. You do not call this directly.
POST
/api/v1/agent-permissions/{requestId}/decline
The human declines; the request moves to declined and nothing is granted.
Request the mandate
POST your delegate agentAddress and a periodAmountUsd (e.g. 100 per day). DiemSum returns a requestId and an approval URL like /permit/{requestId}.
Hand the URL to your human
They open it, connect MetaMask, and grant the erc20-token-periodic permission. They verify in the MetaMask prompt that the delegate address matches your agent before signing — that verification is the security boundary. Granting needs the MetaMask desktop browser extension; MetaMask Mobile cannot grant ERC-7715 permissions yet, so on a phone the permit page offers a copy-the-link gate and only the decline path.
Poll, then store the grant
GET the request until status is granted, then save the permission context locally (for example ~/.diemsum/permissions.json, chmod 600).
Redelegate per purchase
For each inference, sign a child delegation from the stored root permission to the quoted facilitator redeemers with an exact-amount USDC caveat matching the quote, encode child plus root as the payment context, and send it as PAYMENT-SIGNATURE. A 100-USD-per-day root funds a 1-USD call 100 times a day with no new human approval.
The approval and poll URLs are unauthenticated capability URLs keyed by the high-entropy requestId. The real boundary is the human verifying the delegate address inside MetaMask before signing; the granted context is unusable without the agent private key that owns the delegate address. The root grant is scoped by token, budget, period, and expiry; DiemSum adds the per-quote payee and redeemer scope in the child redelegation.
Conversations
Multi-turn
DiemSum keeps no transcript server-side — only sha256: hashes. For a follow-up, re-send the full messages[](including the prior assistant content you kept) plus the lineage from the previous turn's nextTurn:
Carry forward conversationId, parentInferenceRequestId, and parentReceiptId.
The follow-up earns its own quote, receipt, and turnId under the same conversationId.
Then repeat quote → pay → retrieve for the new turn.
Copy, run, ship
Runnable examples
Both run against a local server with the facilitator stubbed: X402_VERIFY_MODE=stub npm run dev.
Node 22 · no build step
docs/examples/agent-quickstart.mjs
End-to-end discover → quote → sign → retrieve. Safe by default: prints the exact follow-up body without paying until you supply a signer key.
TypeScript
docs/examples/direct-x402-erc7710.ts
The ERC-7710 signing core: decode the PAYMENT-REQUIRED envelope, delegate to the facilitator redeemers, and encode the PAYMENT-SIGNATURE.