Trango ComputeContextIQ
x402Policy CheckAgent Commerce GateUSDCBasesettlement verification

Policy Check Receipt Verification via x402 Wire v2: A Technical Tutorial

Verify an x402 settlement on-chain via ContextIQ's receipt endpoint: ERC-20 Transfer decoding, CAIP-2 networks, and binding a tx hash to a prior Policy Check decision.

September 14, 2026Trango Compute Inc.

An allow decision from Policy Check tells you a payment is safe to make. It doesn't tell you the payment actually happened, or happened correctly — that's what this endpoint verifies, independently, against the chain itself rather than trusting a caller's word. This is a tutorial for its x402 wire v2 endpoint.

The Endpoint

POST /api/v1/policy-check/receipt/x402-v2
Price: $0.02 per call
Body: { "checkId": "<checkId from a prior decision>", "transaction": "<on-chain transaction hash>" }

The 402 Challenge

curl -i -X POST https://contextiq.trango-compute.com/api/v1/policy-check/receipt/x402-v2 \
  -H "Content-Type: application/json" \
  -d '{"checkId":"...","transaction":"0x..."}'
{
  "x402Version": 2,
  "resource": { "url": "https://contextiq.trango-compute.com/api/v1/policy-check/receipt/x402-v2" },
  "accepts": [{ "scheme": "exact", "network": "eip155:8453", "amount": "20000", "payTo": "0x4eba5ea3cf0f3fc307099317e17e54390f7a4c58", "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913" }],
  "extensions": { "bazaar": { "info": { "input": { "type": "http", "method": "POST", "schema": { "properties": { "checkId": { "type": "string" }, "transaction": { "type": "string" } }, "required": ["checkId", "transaction"] } } } } }
}

Option A: API Key

curl -X POST https://contextiq.trango-compute.com/api/v1/policy-check/receipt/x402-v2 \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"checkId":"8875a324-9577-48f8-b506-877c26500a7e","transaction":"0x0d7d80b1388b13f52de90ad8887ae86e353628f4ad0127bee5a71c5e4dc79332"}'

Option B: Pay With x402, No API Key

import { createWalletClient, http } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { base } from "viem/chains";
import { wrapFetchWithPayment } from "@x402/fetch";

const account = privateKeyToAccount(process.env.WALLET_PRIVATE_KEY as `0x${string}`);
const client = createWalletClient({ account, transport: http(), chain: base });
const fetchWithPayment = wrapFetchWithPayment(fetch, client);

const res = await fetchWithPayment("https://contextiq.trango-compute.com/api/v1/policy-check/receipt/x402-v2", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ checkId: "8875a324-9577-48f8-b506-877c26500a7e", transaction: "0x0d7d80b1388b13f52de90ad8887ae86e353628f4ad0127bee5a71c5e4dc79332" }),
});

console.log(await res.json());

The Response

Real output, from a real settled payment:

{
  "checkId": "8875a324-9577-48f8-b506-877c26500a7e",
  "receipt": {
    "network": "base",
    "status": "confirmed",
    "blockNumber": "51240606",
    "payer": "0xe72f0af4cf41356d433723547f1412ca27fbb1b8",
    "transfers": [{ "token": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", "from": "0xf8912aa5a6c06a07fd97c75555f1abc6837c4be5", "to": "0x4eba5ea3cf0f3fc307099317e17e54390f7a4c58", "valueAtomic": "20000" }],
    "matchesExpectedPayment": true
  }
}

status is confirmed, reverted, not_found, invalid_transaction_hash, unrecognized_network, or rpc_error. That last one exists because of a real bug we shipped a fix for: the public RPC provider backing this verifier started rejecting receipt lookups on some chains with an "archive request" error, and the original code treated any RPC failure the same as a genuine null result — meaning a real, confirmed payment could come back looking identical to "this never happened." rpc_error is now distinct from not_found specifically so that distinction is never lost again. If you're building against this endpoint, treat rpc_error as "retry later," not as a negative signal about the counterparty.

matchesExpectedPayment is the field to actually gate on: it's true only if a decoded ERC-20 Transfer log in the transaction sends at least the expected amount to the exact payTo address from the original decision's payment challenge. confirmed alone just means some transaction with that hash exists and succeeded — it says nothing about whether it paid the right party.

Try It

This closes the loop with the decision endpoint: check before paying, pay, then verify the settlement actually landed where it was supposed to. Open Policy Check to explore all three calls from the dashboard.

Try ContextIQ free

Free tools for AI engineers.

Follow Trango Compute on LinkedIn

We post updates on new tools, context engineering patterns, and LLM cost research.

Follow on LinkedIn