HTTP quickstart
Try a preflight without adding a wallet or a paid retry.
Live features and staging previews are distinguished. Index coverage is not yet available.
Send a quote or cart
POST one challenge (x402 v1 or v2) or cart, plus rules and context.spent_today_usd. Use resource_url if the challenge omits it, and resource_method when a public index URL has multiple methods. The sample is an explicit trial: three calls per IP per UTC day, shared with MCP. An exhausted trial returns 402. It never automatically pays.
// Plain fetch: trial only, no signer and no automatic paid fallback.
export async function preflightTrial(input, request = fetch) {
try {
const response = await request("https://api.spendpreflight.com/v1/preflight?trial=1", {
method: "POST", redirect: "error", headers: { "content-type": "application/json" },
body: JSON.stringify(input), signal: AbortSignal.timeout(8000),
});
if (!response.ok) return { decision: "hold", reasons: [`screening unavailable (HTTP ${response.status})`] };
const result = await response.json();
if (!["allow", "hold", "block"].includes(result?.decision) || !Array.isArray(result.reasons) || !result.reasons.every(r => typeof r === "string")) {
return { decision: "hold", reasons: ["invalid screening response"] };
}
return result;
} catch { return { decision: "hold", reasons: ["screening unavailable"] }; }
}
Download tested sourcePaying for screening
When you choose paid mode, use your x402 payment client for the SpendPreflight request. Confirm exact USDC on Base, the public payTo, and the $0.02 fee before signing. That fee buys the screening result even if the merchant decision is hold or block. It never authorizes or pays the merchant being reviewed.
Bounded input
Input hardening enforces 64 KiB actual body bytes, JSON depth 32, a 10-second body read deadline, 32 payment options and 100 entries per rule list. Text must be bounded and valid UTF-8. Invalid requests are rejected before payment. Check malformed-input tests and OpenAPI for field bounds.