{"service":"whocalledit","name":"Who Called It?","description":"Evidence-backed crypto-caller attribution. Submit a ticker or contract; the API rebuilds the token's first significant move and identifies the Twitter/Farcaster accounts who called it BEFORE that move started, with tweet URLs, timestamps, tiers, and gain-since-call. Free to use: fresh lookups are rate-limited because analysis costs compute; stored reports and the ledger of past calls serve without limit.","version":"2.0.0","generated_from":"src/alphadash/api/docs_router.py","base_url":"https://whocalledit.io","docs_url":"https://whocalledit.io/api/v1/docs","llms_txt":"https://whocalledit.io/llms.txt","auth":{"model":"anonymous","detail":"No API key or account is required. Submit lookups, poll status, and read reports anonymously. Signing in is only needed to mint or revoke share links."},"free_quota":{"full_reports_per_day":40,"fresh_lookups_per_day":200,"reset_timezone":"UTC","detail":"Everything is free. Two daily pools reset at 00:00 UTC: 200 fresh lookups (new analyses) and 40 full-report opens. When a pool is spent the API answers 429 with an over_quota or daily_budget_reached body carrying the reset time. Cached lookups and stored reports with an active share token serve without limit. Live pool state: GET /api/v1/lookups/free-quota."},"rate_limits":{"scope":"per client IP, fixed window","applies_to":["POST /api/v1/lookups","POST /api/v1/lookups/{id}/retry"],"default_limit":50,"default_window_seconds":3600,"on_exceeded":{"status":429,"behavior":"honor the Retry-After header before retrying"}},"agent_flow":[{"step":1,"action":"Submit the lookup","method":"POST","path":"/api/v1/lookups","detail":"POST a LookupRequest JSON body. The response carries lookup_id, dedup/cache info, and — when a free slot was available — a share_token plus share_url for the eventual full report.","returns":"lookup_id, status, share_token?, free_quota"},{"step":2,"action":"Poll status until completed","method":"GET","path":"/api/v1/lookups/{id}","detail":"Poll every 2-3 seconds. A completed row includes the redacted summary (top callers with blurred handles) and any active free_share_token.","returns":"status, resolved?, summary? (redacted)"},{"step":3,"action":"Fetch the full report","method":"GET","path":"/api/v1/lookups/{id}/report","detail":"Append ?share=<token> when you hold one; without a token the server mints one from today's free pool automatically. When the pool is spent the response is 429 over_quota and the report opens after the 00:00 UTC reset. CSV and PDF exports live at /report.csv and /report.pdf with the same rules.","returns":"FullReport JSON (callers, evidence, methodology)"}],"endpoints":[{"method":"POST","path":"/api/v1/lookups","summary":"Submit a ticker/contract to investigate.","request_fields":[{"name":"query","type":"string","required":true,"constraints":"min_length 1, max_length 128. Ticker symbol, contract address, or token name."},{"name":"chain","type":"string","required":false,"default":"auto","constraints":"One of: arb, auto, avax, base, bsc, eth, native_market, opt, pol, sol, ton. Registry-backed chain details live at GET /api/v1/chains; auto and native_market are synthetic API values."},{"name":"asset_class","type":"string","required":false,"default":"crypto","constraints":"crypto (V1) only."},{"name":"premove_window_days","type":"integer","required":false,"default":90,"constraints":"ge 7, le 90. Days before move-start to search for callers."},{"name":"boost_with_ai","type":"boolean","required":false,"default":false,"constraints":"When true, runs an AI pass over each caller's thesis (budget-capped, rate-limited per IP)."},{"name":"selected_pair_address","type":"string","required":false,"default":null,"constraints":"Optional DexScreener pair address, max_length 160."}],"response_summary":"{lookup_id, status, dedup_hit, free_report, share_token?, share_url?, free_quota}"},{"method":"GET","path":"/api/v1/lookups/{id}","summary":"Poll lookup status; redacted summary when completed.","request_fields":[{"name":"id","in":"path","type":"string","required":true,"constraints":"lookup_id from POST /lookups"}],"response_summary":"LookupStatus: {lookup_id, status, resolved?, summary?, free_share_token?, share_url?}. summary is the redacted caller list (handles blurred)."},{"method":"GET","path":"/api/v1/lookups/{id}/report","summary":"Full report: every caller with evidence.","request_fields":[{"name":"id","in":"path","type":"string","required":true,"constraints":"lookup_id of a completed lookup"},{"name":"share","in":"query","type":"string","required":false,"constraints":"share token from POST /lookups or a share_url; optional — without it the server tries to mint one from today's free pool"}],"response_summary":"FullReport: callers with full handles, tweet URLs, timestamps, tiers, gains, methodology, raw evidence. 429 over_quota when today's free pool is spent."},{"method":"GET","path":"/api/v1/lookups/free-quota","summary":"Live state of today's free full-report pool.","request_fields":[],"response_summary":"{total, remaining, reserved, completed, day, reset_timezone, enabled}"},{"method":"GET","path":"/api/v1/lookups/{id}/og.svg","summary":"Open Graph share card image (SVG) for a lookup.","request_fields":[{"name":"id","in":"path","type":"string","required":true,"constraints":"lookup_id"}],"response_summary":"image/svg+xml social share card."},{"method":"GET","path":"/api/v1/lookups/{id}/og.png","summary":"Rendered Open Graph share card (PNG, 1200x630) for a completed lookup. Also available per share token at /api/v1/shared/{token}/og.png and per certified caller at /api/v1/callers/{handle}/og.png.","request_fields":[{"name":"id","in":"path","type":"string","required":true,"constraints":"lookup_id (lookup must be completed)"}],"response_summary":"image/png share card; Cache-Control public max-age=86400."},{"method":"GET","path":"/api/v1/lookups/{id}/price-series","summary":"Stored daily-close price series backing the report's price-timeline chart. Public market data only.","request_fields":[{"name":"id","in":"path","type":"string","required":true,"constraints":"lookup_id"}],"response_summary":"{lookup_id, points: [{date, close}], move: {start_date, peak_date, start_price, peak_price}}; 404 series_unavailable when no series is stored."},{"method":"GET","path":"/api/v1/sitemap.xml","summary":"Dynamic sitemap: static pages, completed lookup pages, certified caller pages. Lookup IDs only - share tokens are never emitted.","request_fields":[],"response_summary":"application/xml sitemap."},{"method":"GET","path":"/api/v1/chains","summary":"Supported chains + tiers for the `chain` field.","request_fields":[],"response_summary":"ChainsResponse: {tier_1, tier_2, chains}."}],"share_tokens":"Share tokens are bearer credentials for one lookup's full report. Pass them as ?share=<token> on GET /report or open /shared/{token}. They expire; a fresh one can be minted from the daily free pool at any time.","errors":{"404":{"meaning":"not_found — no such lookup_id (or no stored series/card)."},"409":{"meaning":"not_ready — lookup exists but is not completed; poll GET /api/v1/lookups/{id} until status == 'completed' before requesting the report."},"413":{"meaning":"request_too_large — request body exceeds 4096 bytes."},"422":{"meaning":"validation error — a request field violated its constraints (see endpoints[].request_fields)."},"429":{"meaning":"rate_limited (per-IP write budget; honor Retry-After), over_quota (today's free full-report pool is spent), or daily_budget_reached (today's fresh-lookup budget is spent). Quota bodies carry resets_at — everything reopens at 00:00 UTC."}},"politeness":"Use this API instead of scraping the HTML site — every public data point an agent needs is here in stable JSON shapes. Respect the per-IP rate limits and poll status politely (every 2-3s, not in a tight loop)."}