API documentation
Base URL: https://api.inboxpolicy.com · Auth: x-api-key: ip_live_... header, or pay per call with x402.
Updated 2026-07-12 · llms.txt
Quickstart: make one paid request in five minutes
Prerequisites: bring an EVM wallet funded with USDC on Base and an x402 v2 client. No account or API key is required. The optional X-InboxPolicy-Payer header asks for that wallet's rolling 30-day usage rate; the server binds the short-lived quote to the same wallet that signs. The client preserves the quote extension, signs it, retries with PAYMENT-SIGNATURE, and returns the paid decision.
import { x402Client } from "@x402/core/client";
import { encodePaymentSignatureHeader } from "@x402/core/http";
import { toClientEvmSigner } from "@x402/evm";
import { registerExactEvmScheme } from "@x402/evm/exact/client";
import { createPublicClient, http } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { base } from "viem/chains";
const account = privateKeyToAccount(process.env.WALLET_KEY);
const publicClient = createPublicClient({ chain: base, transport: http() });
const x402 = new x402Client();
registerExactEvmScheme(x402, {
signer: toClientEvmSigner(account, publicClient),
networks: ["eip155:8453"]
});
const request = {
method: "POST",
headers: { "content-type": "application/json", "X-InboxPolicy-Payer": account.address },
body: JSON.stringify({ email: "[email protected]" })
};
let res = await fetch("https://api.inboxpolicy.com/v1/decide", request);
if (res.status === 402) {
const payment = await x402.createPaymentPayload(await res.json());
res = await fetch("https://api.inboxpolicy.com/v1/decide", {
...request,
headers: { ...request.headers, "PAYMENT-SIGNATURE": encodePaymentSignatureHeader(payment) }
});
}
console.log(await res.json()); // { action: "send", confidence: 95, ... }
Wallet usage rates: the standard single-call rate is $0.01. A wallet receives 20% off the current single or batch base quote after 1,000 settled units in the prior 30 days and 40% off after 10,000. Omit X-InboxPolicy-Payer to use the standard quote.
Prefer an API key? Buy a prepaid credit pack (card checkout) — your key arrives by email. With a key, send x-api-key instead of paying per call:
curl -X POST https://api.inboxpolicy.com/v1/decide \
-H "x-api-key: ip_live_..." \
-H "content-type: application/json" \
-d '{"email": "someone@example.com"}'
POST /v1/decide
Decision-shaped verification: for a schema-valid request body, answers with one action — send, send_with_caution, review, retry_later, or avoid — plus reason, confidence, signals, and cost. A syntactically invalid email string in a schema-valid body returns avoid at no charge; schema-invalid bodies can fail validation. Unknown addresses resolve to review; catch-all addresses resolve to review by default or send_with_caution under aggressive strictness — see how to handle catch-all email addresses, or browse the send-decision benchmark for 40 worked input-to-decision scenarios.
{
"request_id": "vrf_...",
"action": "send",
"reason": "Verified mailbox with acceptable risk.",
"confidence": 95,
"status": "valid",
"signals": { "catch_all": false, "disposable": false, "free": false, "role_account": false },
"from_cache": false,
"cost": { "credits": 1, "billable": true }
}
POST /v1/verify
Full verification detail: status, deliverability and reachability flags, catch-all/disposable/role signals, MX context, confidence, recommended action, and normalized signals. Malformed input returns 422. Same request body as /v1/decide: {"email", "strictness?", "force_refresh?"} with strictness one of aggressive | default | strict.
Batches
POST /v1/batches/verify
Async verification for up to 50,000 emails: {"emails": [...], "strictness?", "webhook_url?"}. Returns 202 with a batch_id, worst-case credit estimate, and a webhook_secret when a webhook URL was given (completion webhooks are signed x-inboxpolicy-signature: HMAC-SHA256(secret, body)). Duplicate emails are deduplicated internally and billed once.
Batches via x402 (keyless)
The same endpoint also accepts x402 payment — no account or key needed. The x402 path caps at 5,000 emails per call (the API-key path keeps its 50,000 cap). Without a PAYMENT-SIGNATURE header the API replies 402 with a PAYMENT-REQUIRED quote for emails × the per-email bulk rate, in USDC; a v2 x402 client reads the quote, signs, and retries automatically.
curl -i -X POST https://api.inboxpolicy.com/v1/batches/verify \
-H "content-type: application/json" \
-d '{"emails": ["a@x.com", "b@y.com"], "strictness": "default"}'
# 402 Payment Required — quotes total = emails x per-email bulk rate, in USDC
Once payment settles, the same call returns 202:
{
"batch_id": "bat_...",
"status": "queued",
"total_items": 2,
"amount_usd": 0.02,
"access_token": "btok_..."
}
Poll keylessly with that token: GET /v1/batches/:batchId and GET /v1/batches/:batchId/items with header x-batch-access-token: btok_... — same response shapes as the API-key path. webhook_url works the same way. For bigger lists, chunk client-side and submit multiple calls; each payment covers exactly the emails submitted in that call, and duplicates within a call are charged as submitted.
GET /v1/batches/:batchId
Status and summary counts: total_items, processed_items, valid/invalid/unknown/error counts, timestamps.
GET /v1/batches/:batchId/items
Per-email results, paginated: ?status=queued|processing|completed|failed&limit=100&offset=0.
GET /v1/batches
Your recent batch jobs, newest first.
Usage & account
GET /v1/usage — remaining credits, month-to-date spend and request counts. GET /v1/requests — recent verification activity. POST /v1/estimate — credit estimate before an operation: {"operation": "verify_email|verify_batch|send_decision", "count": n}.
Billing rules
- 1 credit = 1 fresh verification (verify, decide, or batch item — same price).
- Can cost 0 credits: eligible cache hits for the same normalized address and strictness within 72 hours when
force_refreshis false, and malformed-input rejections. Authenticated API-key calls can also replay matching idempotent requests within the record TTL. - Insufficient balance returns
402. Credit checks are atomic — concurrent requests cannot overdraw. - Unknown verdicts may escalate automatically to a wholesale fallback verifier at no extra charge;
evidencediscloses the chain.
Idempotency
For authenticated API-key calls, send an idempotency-key header on /v1/verify or /v1/decide. Keyless x402 bypasses this wrapper; after indeterminate settlement, do not submit a second payment. Exactly one concurrent request executes; others replay the stored response or receive 409 while it is in flight. Reusing a key with a different payload returns 409. A crashed owner releases the key after ~5 minutes.
MCP server (agents)
Remote MCP over Streamable HTTP. Tools: decide_send, verify_email, estimate_credits, create_verify_batch, get_batch_status, get_batch_items, get_usage.
{
"mcpServers": {
"inboxpolicy": {
"url": "https://mcp.inboxpolicy.com",
"headers": { "x-api-key": "ip_live_..." }
}
}
}
x402 pay-per-call
No account needed: keyless requests to /v1/decide or /v1/verify return 402 with an x402 v2 PAYMENT-REQUIRED challenge (standard rate $0.01 per call, USDC on Base). Send X-InboxPolicy-Payer to receive a wallet-bound rolling-usage quote: 20% off after 1,000 settled units in 30 days and 40% off after 10,000. Retry with a PAYMENT-SIGNATURE header; the settlement receipt returns in PAYMENT-RESPONSE. Credit packs provide fixed card pack pricing ($3.16–$5.00 per 1,000); model your own list with the cost calculator. Batches accept x402 too — one payment per call, up to 5,000 emails, with the earned percentage applied to the current per-email base quote.
Errors & limits
| Code | Meaning |
|---|---|
400 | Validation failure (body includes an issues array) |
401 | Missing or invalid API key |
402 | Insufficient credits, or x402 payment required (keyless) |
404 | Unknown batch ID |
409 | Idempotency conflict or in-flight duplicate |
422 | Email failed syntax validation (verify only) |
429 | Rate limited (default 10 req/s per key) |