Quick start
Free check, no signup: GET https://api.402xagent.com/v1/products/endpoint-spot-check?url=<endpoint>&mode=dry-run
Expiry check (opt-in)
Add &check_expiry=1 to endpoint-spot-check (optional &skew_s= 0 to 300, default 30). If the check would say pay but every Base USDC option in the live 402 is already expired, or expires within skew_s (extra.validBefore, expiresAt, expiry or deadline; or maxTimeoutSeconds of 5 or less), the verdict is skip with reason challenge_expired, and the answer and receipt carry an expiry_check block. Without the parameter nothing changes. In x402-spotcheck 1.4.0: { checkExpiry: true }.
Reason codes
Every verdict carries a stable reason_code and a confidence. The full list with rules is at /rules (JSON: /rules.json).
| reason_code | verdict | meaning |
|---|---|---|
price_ok | pay | payment request matches the listed price |
price_below_listing | pay | live price lower than listed |
price_mismatch | skip | asks a different price than listed |
pay_to_mismatch | skip | pays a different wallet than listed |
network_mismatch | skip | asks for payment on a different network than listed |
asset_not_usdc | skip | asks for a token other than USDC |
network_unsupported | skip | wants payment on a testnet or a network we don't support |
ssrf_blocked | skip | private or local address, not checked |
no_paywall | skip | no x402 payment request at this URL |
bad_challenge | skip | payment request has no readable USDC price |
challenge_expired | skip | payment terms are expired or expire within seconds (opt-in check) |
ambiguous | skip | payment request is unclear |
free_trial_active | recheck | seller says a free trial is active, so there is no price to check yet, try again later |
timeout | recheck | endpoint did not answer in time, try again shortly |
unreachable | recheck | could not reach the endpoint, try again shortly |
server_error | recheck | endpoint returned a server error, try again shortly |
delivery_failed | recheck | our latest paid call to this endpoint was charged but did not deliver a usable response, try again later |
terms_changed_since_quote | recheck | live payment terms differ from the quote you were given, check again without quote to approve the new terms |
rate_limited | recheck | endpoint is rate limiting us (HTTP 429), try again later |
waf_challenge | recheck | a firewall or bot challenge (HTTP 403) blocked our unpaid probe, try again later |
dns_error | recheck | the endpoint's domain did not resolve (DNS, retried once), try again later |
rate_limited_persistent | skip | endpoint has only answered HTTP 429 (rate limited) for longer than our retry window (default 24 h) |
waf_blocked_persistent | skip | a firewall or bot challenge (HTTP 403) has blocked every probe for longer than our retry window (default 24 h) |
dns_error_persistent | skip | the endpoint's domain has not resolved (DNS) for longer than our retry window (default 24 h) |
host_unstable | recheck | recent probes of this endpoint's host failed (server errors, timeouts or connection errors), so we paused probing it for a few minutes, try again later |
terms_unstable | recheck | two quick probes of this endpoint got different payment terms, try again later |
terms_stale | recheck | payment terms are older than our freshness limit, run the live check right before paying |