Skip to content

Proposal preview

Pay per request

Pay for one API request with a signed INFERENCE permit, following the x402 pattern. No API key and no gas.

POST/api/proposal/x402/chat

Pay per request lets a client without an API key pay for one answer. It follows x402 version 2: the server answers 402 Payment Required with the price, the client signs a payment and retries, and the server settles it. The payment is an EIP-2612 permit for INFERENCE, so the holder signs once and pays no gas.

Proposal preview

Pay per request runs on Sepolia and is not part of deference.si yet. The permit and the activation are real Sepolia transactions; the answer is an example answer while this deployment has no model key.

1. The challenge

Send the request with no payment:

curl -i https://deference.dea.web.id/api/proposal/x402/chat \
  -H "Content-Type: application/json" \
  -d '{"prompt":"Write one sentence about Sepolia."}'

The answer is 402 with a PAYMENT-REQUIRED header, base64 of this JSON (the body carries the same JSON):

{
  "x402Version": 2,
  "resource": { "url": "https://deference.dea.web.id/api/proposal/x402/chat", "description": "One chat answer", "mimeType": "application/json" },
  "accepts": [
    {
      "scheme": "permit",
      "network": "eip155:11155111",
      "asset": "0x59e95fEde655A5E3e62067658e113A5292538193",
      "amount": "100000",
      "payTo": "0xA74120dae0e8453D0Ba0FC4333a4D0840702a446",
      "maxTimeoutSeconds": 600,
      "extra": { "name": "Inference", "version": "1" }
    }
  ]
}

amount is in INFERENCE base units (6 decimals): 100000 is 0.1 INFERENCE. payTo is the X402Activator. extra is the token's EIP-712 domain.

2. The permit

Sign an EIP-2612 Permit with the token's domain (Inference, version 1, chain 11155111, the INFERENCE address): owner your address, spender the payTo address, value the amount, nonce from nonces(owner) on the token, and a deadline no more than a day away.

const signature = await wallet.signTypedData({
  domain: { name: "Inference", version: "1", chainId: 11155111, verifyingContract: inference },
  types: { Permit: [
    { name: "owner", type: "address" }, { name: "spender", type: "address" },
    { name: "value", type: "uint256" }, { name: "nonce", type: "uint256" }, { name: "deadline", type: "uint256" },
  ] },
  primaryType: "Permit",
  message: { owner, spender: activator, value: 100000n, nonce, deadline },
});
const { v, r, s } = parseSignature(signature);

3. The paid request

Retry the same request with PAYMENT-SIGNATURE: base64 of {"owner","amount","deadline","v","r","s"}. The x402 envelope {"x402Version":2,"scheme":"permit","network":"eip155:11155111","payload":{...}} is accepted too.

The server checks the amount and the deadline, then calls X402Activator.activateWithPermit from its own wallet. The activator applies the permit, takes exactly the amount and activates it, with the activation fee, as credit for your own Deference account. A used or invalid permit is refused with a new 402 whose error says why.

The answer is a chat completion with a PAYMENT-RESPONSE header, base64 of:

{ "success": true, "transaction": "0x…", "network": "eip155:11155111", "payer": "0x…" }

The Pay per request page runs the whole exchange with your wallet.