Skip to content

Scam & reality checks API

Screen suspicious messages or investigate whether an offer or claimed source is legitimate. No account or API key. Pay in USDC; retrieve results with your wallet.

Choose a check

Your taskEndpointWhat it doesUSDC
Screen a message or URL for scam indicatorsPOST /checks/messageModel + deterministic checks; optional LLM review0.01 / 0.10 with LLM
Screen a screenshot of a conversation or offerPOST /checks/screenshotSame scam checks, using your transcript plus QR extraction; no OCR0.01 / 0.10 with LLM
Investigate an offer, claim, or claimed sourcePOST /checks/realityLLM research and evidence assessment across text, URLs, and media0.50
Retrieve a submitted checkGET /checks/{check_id}Wallet-authenticated status and resultFree

Scam: “Does this message show fraud or manipulation indicators?”
Reality: “Is this offer or source legitimate, given this evidence?” A related batch returns one combined assessment. Media analysis is not a forensic authenticity guarantee.

All paths above use the /api/v1 prefix. Prices are per check. LLM means large language model; OCR means extracting text from an image.

Getting started

New to x402? It’s an HTTP payment protocol: the API returns 402 Payment Required with a price, and your client signs a payment and retries. Common Defense uses it to charge per check in USDC on Base.

Use those guides for payment setup, then follow the wallet-signing and request-ID requirements below for this API.

API origin: https://app.commondefense.ai

Requirements: A wallet controlled by a private key (EOA; smart-contract wallets are not supported), USDC on the Base network (eip155:8453), and an x402 v2 client. Use its EVM exact payment scheme and the payment-identifier and Sign-In-With-X (SIWX) extensions. SIWX proves you control the wallet, so you can retrieve your results without paying again.

1. Create a check request

Choose an endpoint and build its request body. For example, to screen a message:

const body = JSON.stringify({
  request_id: crypto.randomUUID(),
  text: "Send a deposit now to claim your prize.",
  mode: "standard"
});

Generate request_id once per check and save this body before sending. It is a UUID used as an idempotency key: retrying with the same ID and body retrieves the original check instead of charging again. A new check gets a new ID; a retry keeps the original.

2. Authorize payment and submit

  1. POST the saved body to /api/v1/checks/message without payment. Read the 402 PAYMENT-REQUIRED header; the SDK decodes its payment requirements.
  2. Validate Base (eip155:8453), the USDC asset, recipient, and price. Sign payment with the x402 SDK. Set its payment-identifier extension’s info.id to the same UUID as request_id—no second ID is needed.
  3. POST the same bytes with PAYMENT-SIGNATURE and fresh SIGN-IN-WITH-X. Receive 202 + check_id, not a verdict.

3. Retrieve the result

The API returns a check_id, separate from your client-generated request_id. Use it to GET /api/v1/checks/{check_id} with fresh SIWX every few seconds. Read result when status == "complete". Polling is free.

Checks, LLM calls, and paid transcription start only after payment is confirmed. Validation and local media preparation happen before payment. Keep your private key client-side.

Request bodies

These are JSON bodies for your x402 client, not standalone requests. Replace example IDs and base64 placeholders. Unknown fields are rejected.

Message · POST /api/v1/checks/message

{
  "request_id": "c321be46-70b3-48da-ab59-c964b5292075",
  "text": "Send a deposit now to claim your prize.",
  "mode": "llm"
}

text is required. Omit mode for the 0.01 USDC standard check. Standard checks make no hosted LLM call; an inconclusive result may require review.

Screenshot · POST /api/v1/checks/screenshot

{
  "request_id": "84cbd78a-9db5-4ef1-85b2-3857363ca45c",
  "image_base64": "<base64 image bytes>",
  "transcript": "Send a deposit now to claim your prize.",
  "text": "Optional context",
  "mode": "standard"
}

Image and caller-supplied transcript (the text visible in the screenshot) are required. Encode the image bytes as base64 without a data:image/...;base64, prefix. Same mode options as message checks.

Reality · POST /api/v1/checks/reality

{
  "request_id": "c662389e-2957-4a37-9699-ad9cfa6e50fc",
  "text": "Is this offer from the organization it claims to represent?",
  "attachments": [
    {
      "file_name": "offer.pdf",
      "mime_type": "application/pdf",
      "data_base64": "<base64 file bytes>"
    }
  ]
}

Provide text, attachments, or both. Put research URLs in text; attachments contain bytes, not download URLs. Supports images, PDFs, audio/video, and related batches. No mode field. 0.50 USDC for the whole request.

Sign each request

Use the x402 SDK’s SIWX helpers to create and encode the wallet proof in SIGN-IN-WITH-X. On Base, this uses Sign-In With Ethereum (SIWE) and EIP-191 signatures. Use the same wallet that pays for the check. SIWX is an optional x402 extension that this API requires for paid submissions, recovery, and result retrieval.

Proof fieldValue
domain / uriAPI host / exact HTTPS origin + path
version / type"1" / "eip191"
chainId"eip155:8453" (Base)
issuedAtCurrent UTC timestamp; valid within five minutes
nonceFresh alphanumeric value, 8–64 characters; single use
requestIdLowercase SHA-256 below; not the JSON UUID
import hashlib

digest = hashlib.sha256(
    method.upper().encode() + b"\n" + path.encode() + b"\n" + body_bytes
).hexdigest()

The SIWX requestId above is a hash of this HTTP request, not your check’s UUID. This method/body binding is specific to our API. Use the full path including /api/v1, an empty body for GET, and no query string. Sign the bytes you send.

Keep the check’s UUID; refresh the proof. Every retry and poll needs a new signature with a fresh nonce (a single-use random value) and timestamp.

Results and recovery

settling (confirming payment) → pending (queued) → processing (running) → complete

GET returns 200 even while processing. Inspect status; the completed assessment is in result. The envelope also includes check_id, error, transaction, amount_usdc, and result_expired.

OutcomeClient action
completeRead result; if result_expired: true, it has been removed
payment_failedAuthorization expired without settlement; a new purchase is allowed
refund_requiredContact support with check ID + transaction hash; refund is manual, not already sent
Timeout / prolonged settlingRecover the existing request; do not create another purchase

Recovery: resend the same POST body and UUID with fresh SIWX, without a new payment signature. An existing check returns 200 if complete, otherwise 202. Never change the UUID just because a response was lost.

Input limits

InputLimit
Text / screenshot transcript50,000 characters each
Screenshot10 MiB decoded; 14 MiB request body
Reality attachments5 files; 25 MiB combined decoded by default; 32 MiB request body
Reality prepared evidence20 image parts; 50 pages/PDF; 100,000 combined characters
Audio/video10 minutes combined decoded audio
Wallet concurrency / rate2 active checks; 30 purchase admissions/min; 120 polls/min

Requests are validated before payment; these size limits do not guarantee acceptance. Additional ingress and media-preparation limits apply.

Errors

HTTPAction
401Supply a fresh signature from the purchasing wallet
404For GET, verify the check ID and wallet; for POST, the paid API may not be enabled
402Read payment challenge; if PAYMENT-REQUIRED is absent, recover the existing request
409Fresh nonce for retries; unchanged body/UUID for recovery; changed content needs a new check
413Reduce the request size
422Check the response detail for invalid or unsupported input
429Back off before retrying; preserve the request ID and use a fresh signature
503Service unavailable; preserve the request ID for recovery

Retention

Inputs are cleared on completion or failure. All results, including safe verdicts, expire 30 days after completion; cleanup sets result: null and result_expired: true on completed checks. Payment/replay metadata is retained indefinitely. Privacy policy.

Close every gap before it becomes an incident.

Schedule Demo