x402 pay-per-request
For agents with a Solana wallet and no account: pay each image, video or audio request in USDC.
Available on POST /v1/images/generations, POST /v1/media/generations and the MCP media tools. Chat, embeddings and streaming need an API key.
- Send the request with no
Authorizationheader. - We answer
402 Payment Requiredwith aPAYMENT-REQUIREDheader (x402 v2): USDC on Solana devnet, the exact amount for this request, and our pay-to address. - Your x402 client signs the USDC transfer and retries the same request with a
PAYMENT-SIGNATUREheader (X-PAYMENTalso works). - We verify and settle the payment, then run the model. The response carries a
PAYMENT-RESPONSEreceipt with the transaction.
- The amount is quoted from the request itself: the model and its image count, video seconds and resolution, or audio length. Change the body and you get a new quote.
- Your split, per call. By default the whole discount is yours: you pay the model's discounted price and nothing is bought back. To send part of it to buybacks, add
X-Split: xinf=<bps>,custom=<bps>,discount=<bps>(shares of the discount in basis points, summing to 10000) andX-Split-Token: <mint>when custom is above 0. On the media endpoints a body field"split": {"xinf_bps", "custom_bps", "discount_bps", "custom_mint"}works too; the header wins.xavaandxava_bpsare still accepted as deprecated aliases ofxinfandxinf_bps. The custom token must be eligible in our buyback index. A bad split is a400, before any payment is asked for. - The split is part of the quote: keep it identical on the paid retry, or the payment will not match.
- Models priced by their output cannot be prepaid (
400 x402_unsupported_model); use a key for those. - If a paid request fails, you still get the receipt: contact us with the
x-request-id.
x402 flow
# 1. call with no key: the answer is 402 + what to pay
curl -i https://zinf.dev/v1/images/generations \
-H "Content-Type: application/json" \
-d '{"model":"pruna/p-image","prompt":"a lighthouse at dusk"}'
# HTTP/1.1 402 Payment Required
# PAYMENT-REQUIRED: <base64 of the JSON below>
# {"x402Version":2,"accepts":[{"scheme":"exact","network":"solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",
# "asset":"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU","amount":"4250","payTo":"6Bt7cFqEYPZhMS661vAGkjcGpFGW85BCH9XicLYusBLf",
# "maxTimeoutSeconds":60,"extra":{"feePayer":"...","memo":"xm_...","paymentFlow":"upfront"}}]}
# 2. sign that USDC transfer with your agent's Solana wallet, retry the SAME body
curl https://zinf.dev/v1/images/generations \
-H "PAYMENT-SIGNATURE: <base64 signed payment>" \
-H "Content-Type: application/json" \
-d '{"model":"pruna/p-image","prompt":"a lighthouse at dusk"}'
# HTTP/1.1 200 OK
# PAYMENT-RESPONSE: <base64 receipt: success, transaction, payer>optional: a split (here 20% of the discount to buybacks)
curl -i https://zinf.dev/v1/images/generations \
-H "X-Split: xinf=2000,custom=0,discount=8000" \
-H "Content-Type: application/json" \
-d '{"model":"pruna/p-image","prompt":"a lighthouse at dusk"}'typescript (@x402/fetch + @x402/svm)
import { wrapFetchWithPayment } from "@x402/fetch";
import { x402Client } from "@x402/core/client";
import { ExactSvmScheme } from "@x402/svm/exact/client";
import { createKeyPairSignerFromBytes } from "@solana/kit";
const signer = await createKeyPairSignerFromBytes(walletSecretBytes);
const client = new x402Client().register("solana:*", new ExactSvmScheme(signer));
const pay = wrapFetchWithPayment(fetch, client);
const res = await pay("https://zinf.dev/v1/images/generations", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ model: "pruna/p-image", prompt: "a lighthouse at dusk" }),
});
console.log(await res.json()); // { data: [{ url }] }over MCP
An unpaid media tool call returns an error whose structured content is the payment requirements. Retry the same call with the signed payment in _meta["x402/payment"]; the result carries the receipt in _meta["x402/payment-response"].