# Mindjack Agent Data API On-chain risk and identity intelligence for Solana tokens, plus a research surface: point-in-time features joined to labelled outcomes, so you can test your own hypotheses rather than only reading ours. We keep outcomes: what happened to ~24,000 earlier launches, and the cross-token history of the wallets holding this one. That is what a single-token snapshot cannot reconstruct. ## What we cover, before you test us We hold pump.fun and letsbonk migrations. Two dates matter and they are not the same one: our records begin at history_from, and gapless completeness begins at complete_since. GET /v1/coverage (free) returns both, plus current_through, tokens_indexed and what we exclude. Read them there — do not read the earlier date as the completeness date. Nothing before that window, and it cannot be backfilled. What we record is point-in-time: holder distribution, insider and fresh wallets, sniper detection, as they stood at the migration moment. That state cannot be reconstructed from the chain afterwards — not by us, not by anyone. The window is the asset. So testing us with an established token you already know will return nothing and tell you nothing about us. /v1/coverage also returns a live example_mint with real data. Start there. ## Your first two calls, in full curl -s https://api.mindjack.xyz/v1/coverage curl -s https://api.mindjack.xyz/v1/sample Free, no key, no payment, no signup. coverage tells you the window and hands you a mint that works. sample returns the complete screen, inspect and identity bodies for one fixed token, so you can read the real shape of what you would be buying before spending anything. ## One header every POST needs Our POST endpoints (/v1/keys, /v1/compare, /v1/cohort, /v1/analyze) all require `Content-Type: application/json`, even the ones that take no body. It is a CSRF defence shared with the website: without the header the request is refused with 415 BEFORE authentication, so you get a media-type error rather than the 402 payment challenge you expected. Send `-H 'Content-Type: application/json' -d '{}'` and it behaves. ## Try it before you pay, without a key GET /v1/sample free, no key, no payment. One fixed token, answered by the same handlers a paying caller hits: the complete screen, inspect and identity responses for it, with the real price of each in _meta. It is a depth sample, not a freshness one — the token never changes, which is why it can be free. For freshness use /v1/coverage. ## Paying us: two ways, both open x402, per call, USDC on Solana. GET /.well-known/x402 (free, no key) lists every priced route with its price, the asset, the network and the payTo address. Any priced route answers 402 carrying a full `accepts` block and a PAYMENT-REQUIRED header; send the proof back in a PAYMENT-SIGNATURE header. Sign and submit promptly: a Solana blockhash expires in roughly 60-90 seconds, which is why maxTimeoutSeconds is 60 rather than something more generous. Prepaid credits, if you would rather hold a balance. POST /v1/keys is free — no signup, no card, no dashboard. Minting one, in full: curl -s -X POST https://api.mindjack.xyz/v1/keys \ -H 'Content-Type: application/json' -d '{}' The key is shown once, so save it, and send it as X-API-Key. It starts empty and buys nothing until you fund it: send USDC to the payTo address, then POST {"tx_signature": "..."} to /v1/credits/deposit. 1 USDC = 2000 credits at the base rate, more per dollar on a larger deposit, and a signature credits exactly once. That address is in /.well-known/x402 if you want it before minting a key; /v1/credits/deposit also returns it in pay_to on any request that does not carry a signature. If a key may have leaked, POST /v1/keys/rotate with it: you get a new secret and the balance moves over. The old key dies the moment the call returns, and nothing is lost by rotating early. Those are the only two ways to pay here: per call, or from a deposit. Every price below is per call, and nothing here is a subscription. Per-route payment metadata is in /openapi.json. /auth.md is the same story in markdown, at the path agent tooling looks for it, and /.well-known/api-catalog links the spec and the docs together. A 401 from this host means you were not at a route. Real routes answer 402 when they want money and 200 when they are free; the 404 body lists the ones that exist. ## Rate limits 300 requests per minute. Every response carries x-ratelimit-limit, x-ratelimit-remaining and x-ratelimit-reset — read those rather than guessing at ours. Over the limit is 429, and 429 is never charged. ## Calling a priced route, in full curl -s https://api.mindjack.xyz/v1/screen/MINT \ -H 'X-API-Key: mj_live_...' Without a key the same request answers 402 with an `accepts` block; settle it and resend with a PAYMENT-SIGNATURE header. Either way the body is identical, and it looks like this (trimmed): {"mint": "3R637...Pump", "name": "Brotchen", "rug_risk": {"score": 34, "verdict": "low", "action": "clear", "rug_probability_pct": 38.6, "calibration": {"measured_rug85_pct": 38.6, "n": 1695, "window_days": 30, "says": "..."}, "collapse_speed": {"median_seconds_peak_to_minus70": 591, "exit_window": "minutes"}, "confidence": 0.6}, "facts": {"holders": 582, "insiders": 5, "snipers": 5, "fresh_wallets": 58, "top_10_holder_pct": 8.48, "controlled_supply_pct": 40.61, "market_cap_at_analysis": 17656096.0}, "says": "...", "_meta": {"coverage": "full", "staleness_s": 1746413, "billing": {"credits": 1, "usd": 0.001, "mode": "key"}}} Read `rug_risk.verdict` with `rug_risk.calibration` beside it: the verdict is a band, and the calibration says what that band measured. `_meta.coverage` is none when we hold nothing on the mint, and a none is never billed — check it before trusting an empty body. ## When it does not return data Every answer that is not the 200 you asked for is below, and none of them is charged. Two are worth telling apart: a payment we refused is not the same as a payment we could not process. Branch on the `error` field, or on `_meta.coverage`. 402 no key and no payment yet. The body carries `accepts` with the amount, asset, network and payTo, plus price_usd: {"error": "payment_required", "price_usd": 0.001, "accepts": [{"scheme": "exact", "amount": "1000", "asset": "EPjFWdd5...TDt1v", "payTo": "BdGx7...y4TP", "maxTimeoutSeconds": 60}], "says": "..."} 402 key present, balance too low. Same error, and the same `accepts` block: a key that cannot cover the call is not a refusal to serve you, so the per-call terms are offered anyway, with the key’s own numbers alongside them: {"error": "payment_required", "price_usd": 0.001, "credits_needed": 2, "credits_remaining": 0, "credits_per_usd": 2000, "accepts": [ ...as above... ], "says": "The key you sent has 0 credits ($0.0000) and this call needs 2 ($0.0010). ..."} Presenting a payment proof on a key with no credits settles the call; the empty balance does not block it. 402 you sent a proof and we would not take it. `error` is payment_invalid and `reason` names the fault, e.g. verify_rejected:... or malformed_payment_payload. The `accepts` block comes back with it, so a corrected retry is one call and not two. Two of these reasons — amount_mismatch and network_mismatch — mean the transfer DID settle before we refused; those carry `funds_moved: true` and `settlement_tx`. Keep that signature, it is your proof of what was paid. 402 insufficient_credits. Not the gate, the middle: the balance ran out while the call was being served, or while a stream was running. That batch was not charged. On a stream it arrives as an `exhausted` event and the connection closes; reconnect with Last-Event-ID after topping up and you resume where it stopped. 503 payment_unavailable. The proof was not the problem: our settlement path failed or is switched off. Nothing of yours was consumed. Retry-After says when; the same proof can be resent, since a signed Solana transaction keeps its signature and cannot charge you twice. 200 we hold nothing on that mint. This is a real answer, not a failure, and it is free: {"mint": "...", "coverage": "none", "says": "We have never analysed that token, so there is nothing to report and nothing was charged.", "_meta": {"coverage": "none", "billing": {"credits": 0, "usd": 0.0}}} 429 rate_limited. Over 300 requests a minute. Never charged; x-ratelimit-reset says when to come back. 400 invalid_address, when a mint or wallet in the path is not base58 32-44. `says` names the parameter. Also invalid_mint and invalid_query_params, same shape. 401 key_required when no key was sent, invalid_api_key when one was and it is unknown or revoked. Never expired. Both are answered by POST /v1/keys, which mints one free in a single call; nothing was attached to the old one, and credits live on the key, so the new one starts empty. 402 key_required on the streams, which bill per token delivered and so need a funded key rather than a per-call payment. /v1/discover answers the same question over x402 if you would rather pay per request. 503 mirror_unavailable. Our index, not your request. Never charged. Retry. Three rules that follow from those: check `_meta.coverage` before you read a body as a verdict; treat a 402 payment_required as a price quote rather than an error, since it is how the endpoint tells you what it wants; and never stop paying on a 503 — that one is ours to fix, not yours. ## In code # Python import requests r = requests.get(f'https://api.mindjack.xyz/v1/screen/{mint}', headers={'X-API-Key': KEY}, timeout=15) d = r.json() if d['_meta']['coverage'] == 'none': ... # we hold nothing on it, and you were not charged risk = d['rug_risk'] risk['verdict'], risk['rug_probability_pct'], risk['calibration']['n'] // JavaScript const r = await fetch(`https://api.mindjack.xyz/v1/screen/${mint}`, { headers: { 'X-API-Key': key } }); const d = await r.json(); if (d._meta.coverage === 'none') return null; // nothing held, nothing charged const { verdict, rug_probability_pct, calibration } = d.rug_risk; Same two lines for every other endpoint: swap the path, keep the header. Without a key you get 402 instead of 200 and the body carries `accepts` — pay it, resend with PAYMENT-SIGNATURE, and the 200 you get back is byte-identical to the one above. ## If you are an MCP client npx -y @mindjack/mcp Twenty-six tools over the same endpoints, for Claude, Cursor, Codex or anything else that speaks MCP. It mints and stores its own key on first use, so there is nothing to configure; set MINDJACK_API_KEY to use one you already hold. Everything below applies unchanged. Or, if your client takes a URL rather than a command: https://api.mindjack.xyz/mcp Streamable HTTP, MCP 2025-11-25 (2024-10-07 and up negotiated). Stateless. Two ways in, and your client picks: OAuth the connector flow. Give the client this URL and it finds the rest on its own: calling a tool without a token answers 401 with the address of the resource metadata, that names the authorization server, and you approve once in a browser. API key `Authorization: Bearer ` or `X-API-Key: `, exactly as before. initialize, tools/list, resources/list, prompts/list, ping and server/discover all answer without either, so a client can read the whole catalogue before it decides to ask for anything. tools/call needs one of the two. ChatGPT's research modes look for two tools by name, `search` and `fetch`, and connect to nothing without them. Both exist here. They are aliases rather than extra products: `search` is search_tokens and `fetch` is token_report, at the same endpoints and the same prices, returning the {id, title, url} rows and the single document those modes expect. Same 26 tools, same prices, same 402. Beyond the tools, both servers carry the same four resources and the same three prompts: mindjack://coverage the window we hold, and a mint that works mindjack://scorecard every calibrated band and its measured rate mindjack://prices every priced route, asset, network, payTo mindjack://sample one real token answered in full, free vet_before_buying (mint) should I take this position find_candidates (hours, min_mcap) what launched worth a look vet_counterparty (address) who is this wallet All four resources read free routes, so resources/read costs nothing and needs no key. Prompt arguments are strings on the wire: send "6", not 6. Every tool declares an outputSchema and returns structuredContent beside the text, so you can validate the answer and plan the next call from the field names. One exception, and it is the common case rather than the edge: an error body comes back as text only. A 402 shares no field with the shape the tool advertised, and handing it back as structure invites you to read a payment challenge as the data you asked for. ## Prices scan $0.001 screen, stream (per token delivered) standard $0.005 discover, inspect, price wallet $0.006 wallet deep $0.025 identity, changes, cohort, compare, serial-insiders graph $0.04 graph on-demand $5.00 analyze (pre-migration only) free sample, coverage, scorecard, cohort/fields, credits/balance ## Choosing an endpoint /v1/discover $0.005 Answers: which tokens should I even look at. Use when: you need candidates. Every row already carries a calibrated verdict and its measured rug probability, so you are not getting a bare list of new mints. Filters: hours, min_mcap, platform, limit, and max_rug_pct. max_rug_pct is the one worth knowing: `?max_rug_pct=45` returns only tokens our measured score puts at or under 45%. It is applied before the page is cut, so you do not pay per row for rows you were going to throw away. Answering it at all needs the outcome record. Read the number for what it is: a MEASURED collapse frequency for a band, not a per-token risk that starts at zero. The safest band we publish still rugged about 35% of the time, so 35 is the floor and anything under it returns an empty page however long you widen the window — which looks like "no clean tokens exist" and is not. The universe base rate is 45%. GET /v1/scorecard lists every band. Not for: a token you already have — go straight to screen. Next: screen the ones that look interesting. /v1/stream/migrations $0.001 per token delivered Answers: the same as discover, without asking. Server-sent events; tokens are pushed as they finish analysis. Use when: you run a process and want new launches as they land rather than on a timer. Polling discover for this costs more, arrives later, and hands back the same rows repeatedly. Filters: max_rug_pct, min_mcap, platform, max_events. They are applied before anything is charged, so an idle stream is free and you never pay for a token you filtered out. max_events closes the stream after a set number, which is how you cap what a run can spend. Auth: X-API-Key, and a funded key rather than x402 — a stream settles many times and there is no second request to attach a payment to. Resuming: every event carries an id. Reconnect with Last-Event-ID and you continue without a gap. A fresh connect sends only what happens next, never the backlog. Not for: an agent in a chat loop — use discover, which answers in one call. This is for a process that stays up. /v1/screen/{mint} $0.001 Answers: is this one dangerous. Use when: scanning. Cheap enough to call on every token you see. Returns: calibrated rug verdict plus the concentration facts behind it. Not for: the names of the holders — that is inspect. /v1/inspect/{mint} $0.005 Answers: who is involved in this token. Use when: screen flagged something and you want to see who is in it. Returns: top holders, sniper/fresh/insider/early split, group topology, and tracked-trader activity with direction. Not for: what those wallets did in other tokens — that is identity. /v1/graph/{mint} $0.04 Answers: how are the wallets in this token wired to each other. Use when: inspect reported group topology and you want the edges themselves — who is tied to whom, how strongly, which cluster each wallet sits in and what role it plays there. Returns: edges with strength and confidence, cluster membership, wash wallets, and edges_total / members_total so you can tell a truncated answer from a complete one. Not for: a first look. screen and inspect are far cheaper and usually answer the question you actually have. /v1/wallet/{address} $0.006 Answers: who is this wallet. Use when: vetting one counterparty — a large holder, or a wallet you are considering copying. Takes a wallet, not a token. /v1/serial-insiders $0.025 Answers: which wallets keep turning up early, across many tokens. Use when: building a watchlist of operators rather than reading one token. Params: min_tokens (2-50), limit. Priced per page, like discover. Returns per wallet: insider_in, also_held, early_investor_in, avg_supply_pct, realized_sol. Read it as a ratio, not a total. A wallet that is insider in 1642 tokens but a holder in 4091 is a bot that buys everything early, not an operator. A real serial insider looks like insider in 43 of 45 held. Both numbers are in the response; we do not pick the threshold for you. /v1/compare $0.025 (POST) Answers: do these tokens share the same people. Use when: you suspect one operator behind several launches. Send 2-4 mints as {"mints": [...]}. Returns: the wallets present in more than one, with their role in each (holder / insider / early / sniper), how many appear in all of them, and which of your mints we do not hold — the rest is still answered, as coverage=partial. /v1/funder-networks $0.025 Answers: which funders keep seeding fresh wallets, across the index. Use when: a funder inside one token is a line item; across every analysis it is a desk. Params: min_wallets, limit. Priced per page. Returns per funder: wallets_funded, tokens, first/last seen, sample wallets, and funder_known — the exchange's name when we know the address. A null label with a high count is the shape worth opening. /v1/kols $0.02 Answers: which tracked KOL wallets are worth watching, ranked. Use when: building or refreshing a copy-trading watchlist. Params: days (recent window), sort=profit|success|activity, limit. Priced per page. Returns per KOL: wallet, name, handle, and lifetime plus recent blocks computed from the recorded trades — realized SOL, volume, tokens touched, and a per-token win rate on NET realized SOL. /v1/kol/{address} $0.02 Answers: what exactly did this KOL do. Use when: the leaderboard surfaced a name and you want the record: per-token buys, sells, volume and realized SOL, plus latest trades. Not for: an address we do not track — that answers as null and charges nothing; /v1/wallet covers any wallet. /v1/stream/kols $0.002 per trade delivered Answers: the moment a tracked KOL trades, without asking. Use when: copy-trading or monitoring runs on a process, not a timer. Server-sent events; each carries the KOL, token, side, SOL size and realized PnL where settled. Filters: watch (up to 50 KOL wallets), min_sol, side=buy|sell, max_events — applied before billing, so a filtered-out trade is free and max_events caps what a run can spend. Latency, measured: typically ~20s behind the chain — the tracker's confirmation tail can run to a few minutes; delivery follows our record within seconds. Auth: funded key, like the other streams. Resume: Last-Event-ID is the trade id; nothing re-bills. /v1/search $0.005 Answers: find me that token, anywhere in the analysed catalogue. Use when: you have a symbol, a name fragment, or a mint and want to know if we hold it — before spending real calls. Params: q, platform, min_mcap, days, limit, offset. Priced per page. Not for: what just migrated — that is discover, which also carries the verdicts. /v1/price/{mint} $0.005 Answers: what did it do after we called it. Use when: checking an outcome, or a position you hold. Returns: peak, drawdown from peak, now — at 4-5s resolution. Coverage: starts at our analysis. No bonding-curve phase before that. /v1/wallet/{address}/network $0.025 Answers: who this wallet is wired to — direct ties with direction, and who those wallets connect onward to. /v1/stream/wallets $0.005 per event Answers: the moment a wallet you watch appears in a new analysis, with the role it appeared in. Idle watching is free. /v1/web/{mint} $0.04 Answers: which launches this token is tied to through shared wallets, naming the wallets, with each launch's outcome and recorded peak. /v1/wallets/{mint} $0.005 Answers: who exactly — insider, sniper, early, fresh (with funder), wash and KOL wallets behind one token, as addresses. /v1/exit/{mint} $0.005 Answers: can I sell this right now, and what does it cost. Use when: at the trigger. Everything else here tells you what happened to tokens like this one. This tells you whether you can get out of this one, at this moment. Returns: a verdict (clear / elevated / thin / trapped / blocked) plus a ladder — at $100 and $1000, does a buy route exist, does a sell route exist, and what fraction of your money survives the round trip. The verdict follows the WORST rung, because the size that traps you is the one that matters. Method: two Jupiter quotes per rung, in and back out. Quotes only — nothing is signed and no transaction is built. Not for: a historical read. This ignores our index completely. Note: the only endpoint here that is not served from cache, so it answers in hundreds of milliseconds rather than tens. That is the point: a cached answer to this question is a wrong one. A route is not an execution — transfer hooks and seller-side blacklists do not appear in a route Jupiter is willing to plan. /v1/changes/{mint} $0.025 Answers: who sold since we analysed it. Use when: your cached read is older than you are comfortable with, or you hold a position and want to know if the concentrated wallets are exiting. This is the only endpoint that reads the chain live. Not for: routine scanning — screen is 15x cheaper and usually enough. /v1/cohort $0.025 (POST) Answers: what happened to tokens shaped like the one I am describing. Use when: researching rather than screening. Send up to six min/max filters; get collapse rate vs base rate, peak-gain percentiles, time to peak and collapse speed for the whole matching cohort. Body: filters (up to six), window_days (7-90, default 30). GET /v1/cohort/fields (free) lists the queryable fields and bounds. Not for: a single token — that is screen or identity. /v1/report/{mint} $0.025 (?depth=full $0.07) Answers: everything we hold on one token, in one call. Use when: you have already decided a token matters and want the whole picture without three requests. depth=core is screen + inspect + identity; depth=full adds price, exit and graph. Cheaper than the parts, but only just — the saving is for the round trips, not the data. Screen five hundred tokens; report the three that survived. Not for: scanning. That is screen, at a fortieth of the price. /v1/identity/{mint} $0.025 Answers: who is behind this, from both sides — what this token's holders did in earlier launches, AND which sibling tokens the same wallets ran and how those ended. Also returns the upside band: how often tokens with this much holder winning-history reached 5x. Use when: at the decision point. Note: coverage varies and is reported per call; very new tokens often have none, and an empty result is free. /v1/analyze/{mint} $5.00 (POST) Answers: what does a PRE-MIGRATION token look like. Use when: a bonding-curve token our monitor has not reached yet. Not for: migrated tokens — those are analysed automatically and served from cache. Asking anyway is refused and costs nothing. /v1/coverage and /v1/scorecard free coverage: what we hold and how fresh, per data family. scorecard: our measured hit rate per risk band. Read this to decide how much weight to give our verdicts. ## A typical run discover -> screen each candidate -> inspect the few that flag -> identity at the decision point. graph when inspect's topology is the thing you care about; compare when you hold several mints and suspect one hand behind them; serial-insiders to build the watchlist in the first place. wallet vets a counterparty at any stage; changes and price follow a position you already hold. ## What we promise - Every response carries _meta.coverage (full/partial/none) and _meta.billing. - A token we do not know is coverage=none and costs nothing. - Failed calls, rate-limited calls, and empty results cost nothing. - rug_probability is a measured frequency, not an opinion: see /v1/scorecard. - We do not predict price or return. Where we report upside it is a measured historical frequency for a cohort, never a forecast, and it is not adjusted for fees or slippage.