x402: AI training crawler access policy

Status: ENABLED · Network: eip155:8453 (Base mainnet) · Asset: USDC (0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913) · Pay to: 4 per-facilitator addresses (see table)

War-Tracker uses the x402 protocol (HTTP 402 Payment Required) to require AI training crawlers to pay a USDC micropayment per request when they fetch our paid surfaces. The facilitator at https://facilitator.xpay.sh handles all signature verification and on-chain settlement; we never see or hold the bot's private keys. See the x402 docs for client libraries (Python, TypeScript, Go).

Multi-facilitator accepts: every 402 we issue contains a top-level accepts array of one or more PaymentRequirements entries — one per (facilitator, network, payTo) combination we currently advertise. Each facilitator gets a distinct on-chain recipient address so the buyer's EIP-3009 signature uniquely identifies which facilitator to route /verify and /settle to. Buyer wallets that hold USDC on multiple networks should prefer the earliest entry they can pay (per x402 v2 §5.1.2). The operator's own IPs (see X402_TESTNET_ALLOWED_IPS) also receive testnet entries so new paid routes can be QA-tested with free Sepolia/Amoy/Fuji USDC without a parallel staging stack.

Facilitators in use

Each row below is one (facilitator, network, payTo) tuple that may appear in the 402 accepts array. The +fee column is the per-tx facilitator fee passed through to the buyer on top of the base price — sellers retain 100% of the base price net of fees.

FacilitatorURLPay to (per facilitator)Networks+fee per tx
xpay · xpayhttps://facilitator.xpay.sh0x8B7243F652D3641F661619862157686992640b37eip155:8453 (Base mainnet)+0 µUSDC
cdp · Coinbase Developer Platform (auth)https://api.cdp.coinbase.com/platform/v2/x4020x2633ba64e28A6F6989c343Cb98d43Ea06Bd9bd89eip155:8453 (Base mainnet), eip155:137 (Polygon mainnet)+1,000 µUSDC
payai · PayAIhttps://facilitator.payai.network0xF50C0D73C68EF2d8B3388Ec060ED39edCeb62BAFeip155:8453 (Base mainnet), eip155:137 (Polygon mainnet), eip155:43114 (Avalanche C-Chain)+1,000 µUSDC
dexter · Dexterhttps://x402.dexter.cash0x9FfDCaEAf9ef166b4fA16f8707923CB89F2A09feeip155:8453 (Base mainnet)+0 µUSDC

xpay is the default no-auth, gas-sponsored choice on Base. cdp is Coinbase Developer Platform (JWT-authenticated, multi-chain incl. Polygon, Arbitrum, Solana). payai is PayAI (no auth, multi-chain incl. Avalanche, IoTeX, Sei). dexter is Dexter (no auth, gas-sponsored on Base; EVM exact-scheme uses Uniswap Permit2 instead of EIP-3009 — the x402 SDK dispatches on extra.assetTransferMethod client-side so buyers route to the right signer automatically). Clients should always read the facilitator URL out of the 402 response rather than hard-coding it.

Who pays

The gate is scoped to AI training crawlers. Search engines, in-AI search index crawlers, runtime fetchers driven by a human user, and link-preview bots are all free:

Charged user-agents (must pay):

Free user-agents (never charged):

What costs money

Path patternPriceAtomic unitsDescription
^/share/\d+(/[^/?]*)?/?$$0.0011000 µUSDCGeneric per-event article template at /share/{event_id}/{slug} (substitute any id/slug from /api/v1/events). Default response is SEO HTML with embedded JSON-LD @graph (NewsArticle + Event + VideoObject + FAQPage) for the requested event. Content-negotiable: Accept application/json returns the same JSON as /api/v1/events/{id}. One payment covers either representation. OpenAPI probe id 397003 is an audit example only.
^/api/v1/events/?$$0.0055000 µUSDCPaginated event corpus at /api/v1/events (up to 200 rows per call).
^/api/v1/events/\d+/?$$0.0011000 µUSDCSingle event at /api/v1/events/{id}. Returns canonical JSON: scalar fields (id, date, country, event_type, lat/lng), headline, TL;DR, article paragraphs, full schema.org JSON-LD @graph (NewsArticle + Event + VideoObject + BreadcrumbList + FAQPage), thumbnail (free), media URL (paid via /media/{id}), transcript when available, FAQ, super-event metadata. Equivalent to /share/{id}/{slug} with Accept: application/json.
^/media/\d+/?$$0.0110000 µUSDCFull media bytes (photo or video) for an event at /media/{event_id}. Flat price.
^/region/[^/?]+/?$$0.0011000 µUSDCRegion hub page at /region/{slug}. Aggregates conflict events for a single region (continent, sub-continent, or maritime bbox). HTML with embedded CollectionPage + Dataset JSON-LD that points back at /api/v1/events?region=… so agents can read the JSON-LD instead of scraping the DOM.
^/country/[^/?]+/?$$0.0011000 µUSDCCountry hub page at /country/{iso2}. Aggregates conflict events for a single sovereign nation, keyed by ISO-3166-1 alpha-2. HTML with embedded CollectionPage + Dataset JSON-LD pointing back at /api/v1/events?country={iso2}.
^/event-type/[^/?]+/?$$0.0011000 µUSDCEvent-type hub page at /event-type/{slug}. Aggregates events matching one classification slug (e.g. drone-strike, airstrike, skirmish). HTML with embedded CollectionPage + Dataset JSON-LD pointing back at /api/v1/events?event_type={slug}.
^/api/v1/vessels/\d+/?$$0.0011000 µUSDCSingle vessel identity by IMO. Returns scalar identity: name, MMSI, flag (ISO-3166-1 alpha-2), AIS type (e.g. `Tanker`, `Cargo`, `Fishing`), subtype (e.g. `Crude Oil Tanker`), commercial market (13-value enum: `WET BULK`, `DRY BULK`, `CONTAINER SHIPS`, …), overall length in metres, year built, and the boolean `sanctioned` / `watchlisted` rollups across OFAC, FCDO, EU, UANI, ASO, GAC, UN, SECO, MFAT, and the War-Tracker OSINT shadow-fleet watchlist. Free for browsers, AI-search crawlers (PerplexityBot, OAI-SearchBot, ChatGPT-User, Claude-User, …), and link-preview bots (facebookexternalhit, Twitterbot, Slackbot, …); paid via x402 for training-crawler UAs (GPTBot, ClaudeBot, CCBot, anthropic-ai, Bytespider, Google-Extended, …). Identity rows refresh on a 4-hour batch from the MarineTraffic upstream; for the latest AIS position call /api/v1/vessels/{imo}/position. Typical workflow: enumerate candidates via /api/v1/vessels/search → call this for full identity → /api/v1/vessels/{imo}/sanctions for per-body sanctions detail or /api/v1/vessels/{imo}/track for the recent AIS path. Returns 404 when the IMO is well-formed (7 digits, 1000000-9999999) but missing from our mirror.
^/api/v1/vessels/\d+/position/?$$0.0011000 µUSDCLatest AIS position for one vessel by IMO. Returns lat/lon (WGS84), speed over ground (`sog`, knots), course over ground (`cog`, degrees true 0-360), AIS destination string (free-form, operator-entered), captured-at UTC, and `age_seconds` since the ping was received. Free for browsers, AI-search crawlers, and link-preview bots; paid via x402 for training-crawler UAs (GPTBot, ClaudeBot, CCBot, …). AIS pings arrive every 1-180 s depending on vessel speed and satellite/terrestrial coverage — `age_seconds` >300 is normal in low-coverage areas like the open Indian Ocean, while <60 s is typical near coastlines and chokepoints. Median server latency is ~10-50 ms even on cold cache (`IX_mtvp_ship_captured` covering index). Returns 404 when the IMO has no position rows in our 7-day rolling AIS window. Pair with /api/v1/vessels/{imo}/track for the recent path polyline, or /api/v1/vessels/in-area for every vessel in a bbox.
^/api/v1/vessels/\d+/sanctions/?$$0.0011000 µUSDCSanctions + watchlist rollup for one vessel by IMO. Joins our internal mirrors of the 9 sanctioning bodies (OFAC, FCDO, EU, UANI, ASO, GAC, UN, SECO, MFAT) plus the War-Tracker OSINT shadow-fleet watchlist, and returns every body that has ever listed the vessel along with the listing date per body, plus structured watchlist context (`reason`, `severity`, `source`, first/last-updated UTC). Free for browsers, AI-search crawlers, and link-preview bots; paid via x402 for training-crawler UAs. Always returns 200 — for clean hulls `bodies` is an empty array and `watchlist` is null (NOT 404); the absence of listings is itself a useful signal for KYC / cargo-origin / vessel-vetting flows. Sanctions data refreshes daily at 02:00 UTC from the upstream OFAC SDN list, FCDO consolidated list, EU FSF, UANI tanker tracker, and the other 5 sources. Typical use case: KYC vetting, cargo-origin compliance, shadow-fleet research, insurance underwriting checks.
^/api/v1/vessels/\d+/track/?$$0.01010000 µUSDCRecent AIS position polyline for one vessel by IMO. Response shape: `{imo, hours_requested, hours_effective, raw_points_in_window, downsample_step, points: [{captured_utc, lat, lon, sog, cog}, …]}` — ordered oldest-first so a client can plot the track without sorting. The `?hours=` parameter is currently clamped to 1 (anything wider is silently rolled back — the param stays in the route signature so we can ship longer windows as higher-priced tiers without a rename). When the raw window contains more than 1000 pings the response auto-downsamples evenly to ≤1000 points and reports `downsample_step` (e.g. `4` = every 4th raw ping kept) so the client can compute true gap densities. Free for browsers, AI-search crawlers, and link-preview bots; paid via x402 for training-crawler UAs. Returns 404 when the vessel has no position rows in the last 1 h. Typical workflow: see an anomalous AIS gap or destination change in /position → call this to reconstruct the actual path; for multi-vessel spatial analysis use /api/v1/vessels/in-area instead.
^/api/v1/vessels/search/?$$0.0022000 µUSDCFaceted vessel-identity search across the ~600k-vessel MarineTraffic mirror. Supports free-text `q` (matches name prefix, IMO, or MMSI), facet filters (`flag`/country_code, AIS `type`, `subtype`, `commercial_market_name`), boolean `sanctioned` and `watchlisted` flags, and numeric `min_length` (metres) / `min_year_built` filters. **Always enumerate legal facet values via the free /api/v1/vessels/facets endpoint before paying for /search** — otherwise probing unknown facet values burns $0.002 per miss and returns an empty page. Free for browsers, AI-search crawlers, and link-preview bots; paid via x402 for training-crawler UAs (GPTBot, ClaudeBot, CCBot, …). Cursor-based pagination — one paid call per page; the cursor is opaque (base64 JSON of `(last_seen_utc, ship_id)`) and encodes the original filter set, so pass it back bare on subsequent calls — DO NOT also repeat `q` / `flag` / `type` alongside the cursor (the server prefers the cursor's filters). Hard cap of 20 rows/page (vs the events corpus's 200) reflects the higher per-row indexing cost. Typical workflow: /facets → /search → /vessels/{imo}/position or /track for selected IMOs.
^/api/v1/vessels/in-area/?$$0.01010000 µUSDCDistinct vessels with at least one AIS ping inside a bounding box (`min_lat`/`min_lon`/`max_lat`/`max_lon` in WGS84) over the last `hours` hours. Page size locked at 10 vessels per paid call. Each row carries identity + last ping (`last_lat`, `last_lon`, `last_sog`, `last_cog`, `last_ping_utc`, `destination`) + the sanctioned/watchlisted booleans. Optional facet filters mirror /vessels/search: `flag`, `type`, `subtype`, `commercial_market_name`, `sanctioned`, `watchlisted`. Pagination is SNAPSHOT-based: the first call pins a `page.snapshot_utc` and returns a `next_cursor` encoding `(snapshot_utc, last_ping_utc, ship_id)`. **Every subsequent page MUST echo the cursor** so the result set stays consistent against the live AIS feed (vessels can't race ahead between pages). If `page.snapshot_utc` in a paginated response differs from your starting snapshot, your original has rotated out (stale snapshots >1 h old silently restart from a fresh one) — begin pagination again from page 1. bbox is hard-capped at 25°×25° to keep the underlying non-spatial scan bounded; `hours` is hard-capped at 1. Free for browsers, AI-search crawlers, and link-preview bots; paid via x402 for training-crawler UAs. Typical use case: chokepoint monitoring (Strait of Hormuz, South China Sea, Bosphorus, Suez approaches, Bab-el-Mandeb), new-arrival detection in port basins, sanctioned-vessel cluster detection.
^/api/v1/vessels/sanctioned/?$$0.02525000 µUSDCCursor-paginated sanctioned / shadow-fleet vessel feed. Each row carries identity (name, IMO, MMSI, flag, type, subtype, commercial market, year built, dimensions) + last-known AIS position (`last_lat`, `last_lon`, `last_sog`, `last_cog`, `last_ping_utc`, `last_destination`, `last_pos_age_seconds`) + the array of sanctioning bodies that have ever listed the vessel with their listing dates. Optional filters: `?body=` (one of `ofac`, `fcdo`, `uani`, `eu`, `aso`, `gac`, `un`, `seco`, `mfat`), `?active_only=true` (only currently-listed entries, excludes de-listings), and `?flag=` (ISO-3166-1 alpha-2 country code; use /api/v1/vessels/facets for the legal set). Hard cap of 10 rows/page — one paid call per page; rows ordered by IMO ascending so pagination is stable across daily rebuilds. Pass back `next_cursor` as `?cursor=` to fetch the next page. Free for browsers, AI-search crawlers, and link-preview bots; paid via x402 for training-crawler UAs. The full ~1.4 k-row dump costs ~$3.50 to walk (140 paid calls); for daily-delta workflows prefer filtering by `?active_only=true&body=ofac` or similar to bound the result set. Typical use case: nightly compliance mirror, shadow-fleet OSINT research, cargo-origin vetting, port-state-control pre-screening.
^/api/v1/hormuz/crossings/?$$0.01010000 µUSDCPaginated feed of individual vessel transits through the Strait of Hormuz, sourced from the ShipTracker live AIS feed. One row per (vessel, direction, crossing-day). Each row carries `dt_utc` (UTC day), MMSI + resolved IMO, vessel name and shiptype, flag (`country_code`), operator company, deadweight tonnage (`dwt`), `direction` (0 or 1), `time1` / `time2` (ShipTracker first/second-cross timestamps), and the `sanctioned` / `watchlisted` flags resolved against our internal mirror of OFAC + 8 other bodies. Filters: `?date=YYYY-MM-DD` (single UTC day) OR `?days=` (rolling window, default 7, max 14); `?direction=` (0 or 1 — ShipTracker's convention is opaque, see /api/v1/vessels/facets for the actual distinct values present); `?country_code=` (vessel flag, ISO-3166-1 alpha-2); `?sanctioned=true|false` (filter to sanctioned hulls only). Cursor-based pagination at 10 rows/page (one paid call per page); cursor is opaque base64 JSON of `(dt, mmsi)` — pass it back bare as `?cursor=`. Free for browsers, AI-search crawlers, and link-preview bots; paid via x402 for training-crawler UAs. Typical use case: daily Iran shadow-fleet detection, tanker-flow analysis, choke-point throughput monitoring, sanctioned-vessel transit alerts. Pair with /api/v1/hormuz/summary for aggregate analytics over the same window.
^/api/v1/hormuz/summary/?$$0.0055000 µUSDCDaily aggregate analytics for the Strait of Hormuz transit feed (ShipTracker-sourced). Single paid call returns three rollups in one response: (a) `daily_counts` — per-UTC-day transit counts split by direction (`direction_0` / `direction_1` / `direction_unknown`), `total`, `sanctioned`, `watchlisted`, and `distinct_operators` for each day; (b) `top_operators` — top 10 operator companies by crossing count over the window with their `sanctioned_crossings` share; (c) `top_flags` — top 10 flag country codes (ISO-3166-1 alpha-2) by crossing count with their sanctioned-crossings share. `?days=` is rolling window in days, default 14, max 14 (the rolling-window cap on the underlying scrape). Free for browsers, AI-search crawlers, and link-preview bots; paid via x402 for training-crawler UAs. NOT paginated — the response is bounded by design (≤14 daily rows + ≤10 operators + ≤10 flags). Typical use case: weekly operator-concentration analysis, flag-shift detection (IR→PA, IR→MH, etc), sanctioned-fleet activity heatmap, energy-security throughput trends. For per-vessel transit detail use /api/v1/hormuz/crossings.

Maritime data (vessels + Strait of Hormuz)

The /api/v1/vessels/* and /api/v1/hormuz/* routes expose ~600k AIS-tracked vessels (identity, position, sanctions, AIS track) and a live ShipTracker-sourced Strait-of-Hormuz transit feed. Pricing is fixed per route — there is no surge or per-row metering. Same x402 settlement (USDC on Base) as the events corpus, same four facilitators (xpay / cdp / payai / dexter).

Mandatory free pre-flight: call /api/v1/vessels/facets ONCE per session before paying for /vessels/search or /vessels/in-area — it returns the legal values for the type, subtype, commercial_market_name, flag, sanctioning body, and Hormuz country_code / direction filters. Each value carries a vessel/crossing count so you can decide whether a filter is worth applying. Skipping this step and probing on the paid endpoints wastes $0.002 per miss.

Per-route pagination contracts (each documented in its 402 envelope's Bazaar info.input.inputSchema):

Always free (discovery surfaces; AI agents need to reach these to find this page):

How to pay (curl example)

The minimum interaction is:

  1. Issue a normal request. We respond with HTTP 402 and a base64-encoded PAYMENT-REQUIRED header.
  2. Build and sign a USDC transfer authorization on the indicated network, base64 it, and resend with a PAYMENT-SIGNATURE header.
  3. We forward the signature to the facilitator's /verify endpoint, run your request, then call /settle and return the resource with a PAYMENT-RESPONSE header.
$ curl -i -H "User-Agent: GPTBot" https://war-tracker.com/share/620227
HTTP/2 402
content-type: application/json
payment-required: eyJ4NDAyVmVyc2lvbiI6MiwiYWNjZXB0cyI6W3sic2NoZW1lI...
cache-control: private, no-store

{"x402Version": 2, "resource": {"url": "...", "serviceName": "War-Tracker Event Article"},
 "accepts": [{"scheme": "exact", "network": "eip155:8453", "amount": "1000", ...}],
 "extensions": {"bazaar": {"info": {"input": {...}, "output": {...}}}},
 "error": "PAYMENT-SIGNATURE header is required"}

The easiest client is the official x402 Python SDK (pip install 'x402[httpx]') or the TypeScript fetch wrapper (@x402/fetch). Both handle the sign/verify/settle round-trip automatically.

Discovery (Bazaar)

Every paid route advertises an x402 Bazaar discovery extension on its 402 response, so AI agents can find War-Tracker without any prior integration:

$ curl -s https://facilitator.xpay.sh/discovery/resources | jq '
  .items[] | select(.resource | startswith("https://war-tracker.com"))'

Each catalog entry carries our serviceName, tags, iconUrl, input/output JSON Schemas, and the same pricing table shown above. The facilitator catalogs each route on the first successful /settle call against it; expect a brief delay (seconds to minutes) after a brand-new route ships.

Operational notes