{"openapi":"3.1.0","info":{"title":"FomoScan Identity API","version":"1.1.0","description":"Resolve a FOMO trader handle to their on-chain wallet addresses, and\nany wallet back to the traders behind it. Every returned address is a\nverified match.\n\n## Authentication\nSend your API key as `Authorization: Bearer fsk_live_…` (or the\n`X-Api-Key` header). Press **Authorize** on this page to call any\nendpoint live with your key.\n\n```bash\ncurl -s -H \"Authorization: Bearer $KEY\" \\\n  \"https://api.fomoscan.sh/v2/user/handle/tradername\"\n```\n\n## Response envelope\nEvery successful response carries the answer under `data` and two\nfields under `meta`:\n\n- `meta.asOf`: the time the data in `data` was observed.\n- `meta.requestId`: unique per request. Include it when you contact support.\n\n## Billing\n- A lookup that finds nothing is still charged, at the miss price stated on the endpoint.\n- `GET /v2/me` is free and reports your remaining units.\n- Errors that are our fault or your client’s (`401`, `403`, `429`, `5xx`) are not billed.\n- When the allowance is spent, calls return `402 QUOTA_EXCEEDED` until the counter resets.\n\n## 404 NOT_OBSERVED\nA `404` does not mean the handle or wallet is unknown to FOMO. It means\nwe hold no verified link for it. Treat it as \"no answer today\", cache\nthe negative briefly and ask again later.\n\n## Errors\nEvery error uses one shape: `{ \"error\": { \"code\": \"…\", \"message\": \"…\" } }`.\n\n| HTTP | Code | Meaning |\n|---|---|---|\n| 400 | `VALIDATION_ERROR` | A malformed handle, address or query parameter. |\n| 400 | `BAD_REQUEST` | The request cannot be served as sent. |\n| 401 | `UNAUTHORIZED` | Missing or invalid API key. |\n| 402 | `QUOTA_EXCEEDED` | Out of credits. |\n| 402 | `REVEAL_LIMIT_REACHED` | The key’s reveal limit is reached. |\n| 403 | `FORBIDDEN` | The key may not perform this action. |\n| 403 | `FORBIDDEN_SCOPE` | The key is not provisioned for this endpoint. |\n| 403 | `FREE_TIER_DISABLED` | The key has no allowance. |\n| 404 | `NOT_OBSERVED` | No verified match. See the section above. |\n| 404 | `NOT_FOUND` | No such route or resource. |\n| 409 | `CONFLICT` | The request conflicts with one already accepted. |\n| 429 | `RATE_LIMITED` | Per-minute limit exceeded. Retry after `retryAfter` seconds. |\n| 500 | `INTERNAL_ERROR` | Our fault. Retry, and send `meta.requestId` if it persists. |\n| 503 | `OVERLOADED` | We are shedding load. Retry. |\n| 503 | `B2B_DISABLED` | The API is switched off on this deployment. |\n| 504 | `TIMEOUT` | The answer did not arrive in time. Retry. |\n\nA `429` also carries `retryAfter`, in seconds.\n\n## Rate limits\nEach key has one per-minute request limit across every endpoint,\nreadable from `GET /v2/me` as `ratePerMinute`. A per-IP burst ceiling\nsits behind it. Exceeding either returns `429 RATE_LIMITED`.","contact":{"name":"FomoScan","url":"https://fomoscan.sh","email":"fomoscan-support@proton.me"}},"servers":[{"url":"https://api.fomoscan.sh","description":"Production"}],"tags":[{"name":"Identities","description":"Resolve handles ↔ wallets."},{"name":"Thesis Feed","description":"Trader \"thesis\" posts, newest first — by token, by author, or both. Poll with no `before` for a live feed. Clients MUST dedupe on `id`."},{"name":"WebSocket","description":"The streaming surface. Everything above is a request you make; this is a connection you hold. It delivers the same thesis objects `Thesis Feed` returns."},{"name":"Pump","description":"pump.fun lookups: a user by wallet, the global callout feed or one coin's or wallet's wall, and the PnL leaderboard. On pump.fun the wallet IS the account, so a wallet lookup here is a stored read, not a resolution."},{"name":"Account","description":"Your key: entitlements and usage."}],"paths":{"/v2/user/handle/{handle}":{"get":{"summary":"Resolve a FOMO handle to the user and their verified wallet","tags":["Identities"],"description":"Looks a user up by their fomo.family handle.\n\n- **404** when we do not know the handle.\n- A **200** with both addresses null means we hold no verified wallet\n  for this user.\n\n**Price:** 100 CU on a hit, 200 CU on a 404.","parameters":[{"schema":{"type":"string","minLength":1,"maxLength":64},"example":"tradername","in":"path","name":"handle","required":true,"description":"fomo.family username (case-insensitive; leading @ is stripped)."}],"security":[{"b2bApiKey":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["id","handle","name","bio","banner","profilePicture","twitter","solanaAddress","evmAddress"],"properties":{"id":{"type":"string","format":"uuid","description":"Stable FOMO user id. Unlike `handle` it never changes, so it is the key to store."},"handle":{"type":"string","description":"The canonical handle. Users rename — do not key on it."},"name":{"type":["null","string"],"description":"Display name."},"bio":{"type":["null","string"],"description":"Profile blurb as written by the user, or null if they have none."},"banner":{"type":["null","string"],"description":"Cover photo URL, or null. May no longer resolve."},"profilePicture":{"type":["null","string"],"description":"Avatar URL, or null. May no longer resolve."},"twitter":{"type":["null","string"],"description":"Canonical X profile link, `https://x.com/<handle>`, or null. Normalised from whatever the user typed on FOMO; null when that could not be reduced to a plausible handle. Self-declared and NOT verified by us — a claim, not a proof.","example":"https://x.com/tradername"},"solanaAddress":{"type":["null","string"],"description":"Verified Solana address (base58), or null."},"evmAddress":{"type":["null","string"],"description":"Verified EVM address, `0x`-prefixed, or null."},"socials":{"type":"array","description":"Verified social account links. Present only when social account links are enabled on the API. Absent, not null, when they are not.","items":{"type":"object","required":["provider","subject","handle"],"properties":{"provider":{"type":"string","description":"Platform identifier: 'x', 'telegram', 'youtube', 'reddit', etc."},"subject":{"type":"string","description":"Provider-stable user id (e.g. Twitter numeric id '12345678'). Stable across renames; use this as your join key."},"handle":{"type":["null","string"],"description":"Display username at verification time. May change; do not key on it."}}}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/def-0"}}}}}}},"/v2/user/wallet/{address}":{"get":{"summary":"Resolve a wallet address to the user(s) behind it","tags":["Identities"],"description":"The same record as `/v2/user/handle/{handle}`.\n\n- **EVM addresses must be `0x`-prefixed.** The chain is inferred\n  from the address.\n- **404** when we hold no user for the address.\n- One record is returned even when the address is linked to more than\n  one user. Repeat calls return the same one.\n\n**Price:** 30,000 CU on a hit, 200 CU on a 404.","parameters":[{"schema":{"type":"string","minLength":1,"maxLength":128},"example":"So11111111111111111111111111111111111111112","in":"path","name":"address","required":true,"description":"Solana address (base58) or EVM address (**must** include the `0x` prefix)."}],"security":[{"b2bApiKey":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["id","handle","name","bio","banner","profilePicture","twitter","solanaAddress","evmAddress"],"properties":{"id":{"type":"string","format":"uuid","description":"Stable FOMO user id. Unlike `handle` it never changes, so it is the key to store."},"handle":{"type":"string","description":"The canonical handle. Users rename — do not key on it."},"name":{"type":["null","string"],"description":"Display name."},"bio":{"type":["null","string"],"description":"Profile blurb as written by the user, or null if they have none."},"banner":{"type":["null","string"],"description":"Cover photo URL, or null. May no longer resolve."},"profilePicture":{"type":["null","string"],"description":"Avatar URL, or null. May no longer resolve."},"twitter":{"type":["null","string"],"description":"Canonical X profile link, `https://x.com/<handle>`, or null. Normalised from whatever the user typed on FOMO; null when that could not be reduced to a plausible handle. Self-declared and NOT verified by us — a claim, not a proof.","example":"https://x.com/tradername"},"solanaAddress":{"type":["null","string"],"description":"Verified Solana address (base58), or null."},"evmAddress":{"type":["null","string"],"description":"Verified EVM address, `0x`-prefixed, or null."},"socials":{"type":"array","description":"Verified social account links. Present only when social account links are enabled on the API. Absent, not null, when they are not.","items":{"type":"object","required":["provider","subject","handle"],"properties":{"provider":{"type":"string","description":"Platform identifier: 'x', 'telegram', 'youtube', 'reddit', etc."},"subject":{"type":"string","description":"Provider-stable user id (e.g. Twitter numeric id '12345678'). Stable across renames; use this as your join key."},"handle":{"type":["null","string"],"description":"Display username at verification time. May change; do not key on it."}}}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/def-0"}}}}}}},"/v2/user/id/{id}":{"get":{"summary":"Resolve a FOMO user id to the user and their verified wallet","tags":["Identities"],"description":"Looks a user up by the `id` from a previous response. `id` is stable\nwhere `handle` is not, so it is the value to store against your own\nrecords and come back with.\n\n- **404** when we do not know the id.\n- A **200** with both addresses null means we hold no verified wallet\n  for this user.\n\n**Price:** 100 CU on a hit, 200 CU on a 404.","parameters":[{"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-0000-0000-000000000000","in":"path","name":"id","required":true,"description":"FOMO user id, as returned in `id` on any user record. Same id FOMO uses."}],"security":[{"b2bApiKey":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["id","handle","name","bio","banner","profilePicture","twitter","solanaAddress","evmAddress"],"properties":{"id":{"type":"string","format":"uuid","description":"Stable FOMO user id. Unlike `handle` it never changes, so it is the key to store."},"handle":{"type":"string","description":"The canonical handle. Users rename — do not key on it."},"name":{"type":["null","string"],"description":"Display name."},"bio":{"type":["null","string"],"description":"Profile blurb as written by the user, or null if they have none."},"banner":{"type":["null","string"],"description":"Cover photo URL, or null. May no longer resolve."},"profilePicture":{"type":["null","string"],"description":"Avatar URL, or null. May no longer resolve."},"twitter":{"type":["null","string"],"description":"Canonical X profile link, `https://x.com/<handle>`, or null. Normalised from whatever the user typed on FOMO; null when that could not be reduced to a plausible handle. Self-declared and NOT verified by us — a claim, not a proof.","example":"https://x.com/tradername"},"solanaAddress":{"type":["null","string"],"description":"Verified Solana address (base58), or null."},"evmAddress":{"type":["null","string"],"description":"Verified EVM address, `0x`-prefixed, or null."},"socials":{"type":"array","description":"Verified social account links. Present only when social account links are enabled on the API. Absent, not null, when they are not.","items":{"type":"object","required":["provider","subject","handle"],"properties":{"provider":{"type":"string","description":"Platform identifier: 'x', 'telegram', 'youtube', 'reddit', etc."},"subject":{"type":"string","description":"Provider-stable user id (e.g. Twitter numeric id '12345678'). Stable across renames; use this as your join key."},"handle":{"type":["null","string"],"description":"Display username at verification time. May change; do not key on it."}}}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/def-0"}}}}}}},"/v2/user/handle/{handle}/resolve":{"post":{"summary":"Resolve a handle to its wallets","tags":["Identities"],"description":"Returns the wallet we hold for this handle. If we hold none, we go and look for one.\n\n- **200** returns the ordinary user record.\n- **202** `{ pending: true, reason }` means the answer is not ready, not that the call\n  failed. `retryAfterSeconds` says when to ask again. Asking again does not start a\n  second resolve, it joins the one already running.\n- **404** when no such FOMO user exists, as opposed to a 202, which means we could not\n  answer yet.\n- A live answer can take several seconds, so allow for it in your client timeout.\n- `x-fomoscan-resolve: cached` on a response answered from a wallet we already held, `live` when we went and looked.\n- Refused with **402** before any work starts when the key cannot pay for a hit.\n- Rate limited to **10/minute** per IP, separately from your plan rate.\n\n**Price:** 30,000 CU on a hit, 200 CU on a 202 or a 404.","parameters":[{"schema":{"type":"string","minLength":1,"maxLength":64},"example":"tradername","in":"path","name":"handle","required":true,"description":"FOMO handle (case-insensitive; leading @ is stripped)."}],"security":[{"b2bApiKey":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["id","handle","name","bio","banner","profilePicture","twitter","solanaAddress","evmAddress"],"properties":{"id":{"type":"string","format":"uuid","description":"Stable FOMO user id. Unlike `handle` it never changes, so it is the key to store."},"handle":{"type":"string","description":"The canonical handle. Users rename — do not key on it."},"name":{"type":["null","string"],"description":"Display name."},"bio":{"type":["null","string"],"description":"Profile blurb as written by the user, or null if they have none."},"banner":{"type":["null","string"],"description":"Cover photo URL, or null. May no longer resolve."},"profilePicture":{"type":["null","string"],"description":"Avatar URL, or null. May no longer resolve."},"twitter":{"type":["null","string"],"description":"Canonical X profile link, `https://x.com/<handle>`, or null. Normalised from whatever the user typed on FOMO; null when that could not be reduced to a plausible handle. Self-declared and NOT verified by us — a claim, not a proof.","example":"https://x.com/tradername"},"solanaAddress":{"type":["null","string"],"description":"Verified Solana address (base58), or null."},"evmAddress":{"type":["null","string"],"description":"Verified EVM address, `0x`-prefixed, or null."},"socials":{"type":"array","description":"Verified social account links. Present only when social account links are enabled on the API. Absent, not null, when they are not.","items":{"type":"object","required":["provider","subject","handle"],"properties":{"provider":{"type":"string","description":"Platform identifier: 'x', 'telegram', 'youtube', 'reddit', etc."},"subject":{"type":"string","description":"Provider-stable user id (e.g. Twitter numeric id '12345678'). Stable across renames; use this as your join key."},"handle":{"type":["null","string"],"description":"Display username at verification time. May change; do not key on it."}}}}}}}}},"202":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["pending","reason"],"properties":{"pending":{"type":"boolean","enum":[true]},"reason":{"type":"string","enum":["queued","timeout","unavailable","rate_limited","no_preview","not_ingested"],"description":"`queued` — accepted. The answer is not ready yet.\n`timeout` — the answer did not arrive in time. Ask again.\n`unavailable` — no answer can be produced right now.\n`rate_limited` — the request was not accepted. Ask again later.\n`no_preview` — no wallet can be attested for this user. Retrying rarely helps.\n`not_ingested` — the record is not readable yet. Ask again shortly."},"retryable":{"type":"boolean","description":"False only for `no_preview`, where a prompt retry is wasted effort."},"retryAfterSeconds":{"type":"integer","description":"Seconds to wait before asking again. Present on `queued` and `rate_limited`."},"position":{"type":"integer","description":"On `queued` only: the rank of this request. 1 is next up."}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/def-0"}}}},"429":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/def-0"}}}}}}},"/v2/user/handle/{handle}/pnl":{"get":{"summary":"One trader's FOMO trading numbers","tags":["Identities"],"description":"Net cash flow, return, volume and trade count for one account's FOMO trades.\n\n- `netUsd` is sold minus bought. It is not realized profit: an account that only bought shows negative whatever it holds.\n- Four windows (`24h`, `7d`, `30d`, `all`) in one call, each with the\n  account's `rank` for that window.\n- **404** when we do not hold the handle.\n- A **200** with every window null means we hold no FOMO trade for this\n  account's wallets.\n\n**Price:** 30,000 CU on a hit, 200 CU on a 404.","parameters":[{"schema":{"type":"string","minLength":1,"maxLength":64},"example":"tradername","in":"path","name":"handle","required":true,"description":"fomo.family username (case-insensitive; leading @ is stripped)."}],"security":[{"b2bApiKey":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["handle","wallet","evmWallet","updatedAt","windows"],"properties":{"handle":{"type":"string"},"displayName":{"type":["null","string"]},"avatarUrl":{"type":["null","string"]},"twitter":{"type":["null","string"],"description":"Bare X username."},"followers":{"type":["null","integer"]},"wallet":{"type":["null","string"],"description":"The Solana address these numbers include. Null means we hold no verified Solana wallet for this account."},"evmWallet":{"type":["null","string"],"description":"The EVM address these numbers include, across every EVM chain FOMO runs on."},"updatedAt":{"type":["null","integer"],"description":"Epoch ms when these numbers were last refreshed."},"windows":{"type":"object","description":"One entry per window, with all four keys present. Null means we hold no FOMO trade for this account's wallets.","properties":{"24h":{"type":["null","object"],"properties":{"netUsd":{"type":"number","description":"Quote received on sells minus quote paid on buys across the account's FOMO trades in the window, USD. Cash flow, not realized profit: an account that only bought shows negative whatever it holds."},"returnPct":{"type":["null","number"],"description":"netUsd as a percentage of what was paid on buys in the window. Null when nothing was bought."},"volumeUsd":{"type":"number","description":"Bought plus sold in the window, USD."},"trades":{"type":"integer","description":"Swaps in the window."},"rank":{"type":"integer","description":"Position on the netUsd ranking for this window, 1 = highest. Ties share a rank."}}},"7d":{"type":["null","object"],"properties":{"netUsd":{"type":"number","description":"Quote received on sells minus quote paid on buys across the account's FOMO trades in the window, USD. Cash flow, not realized profit: an account that only bought shows negative whatever it holds."},"returnPct":{"type":["null","number"],"description":"netUsd as a percentage of what was paid on buys in the window. Null when nothing was bought."},"volumeUsd":{"type":"number","description":"Bought plus sold in the window, USD."},"trades":{"type":"integer","description":"Swaps in the window."},"rank":{"type":"integer","description":"Position on the netUsd ranking for this window, 1 = highest. Ties share a rank."}}},"30d":{"type":["null","object"],"properties":{"netUsd":{"type":"number","description":"Quote received on sells minus quote paid on buys across the account's FOMO trades in the window, USD. Cash flow, not realized profit: an account that only bought shows negative whatever it holds."},"returnPct":{"type":["null","number"],"description":"netUsd as a percentage of what was paid on buys in the window. Null when nothing was bought."},"volumeUsd":{"type":"number","description":"Bought plus sold in the window, USD."},"trades":{"type":"integer","description":"Swaps in the window."},"rank":{"type":"integer","description":"Position on the netUsd ranking for this window, 1 = highest. Ties share a rank."}}},"all":{"type":["null","object"],"properties":{"netUsd":{"type":"number","description":"Quote received on sells minus quote paid on buys across the account's FOMO trades in the window, USD. Cash flow, not realized profit: an account that only bought shows negative whatever it holds."},"returnPct":{"type":["null","number"],"description":"netUsd as a percentage of what was paid on buys in the window. Null when nothing was bought."},"volumeUsd":{"type":"number","description":"Bought plus sold in the window, USD."},"trades":{"type":"integer","description":"Swaps in the window."},"rank":{"type":"integer","description":"Position on the netUsd ranking for this window, 1 = highest. Ties share a rank."}}}}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/def-0"}}}}}}},"/v2/user/handles/pnl":{"post":{"summary":"FOMO trading numbers for up to 100 traders in one call","tags":["Identities"],"description":"GET /v2/user/handle/{handle}/pnl for up to 100 handles at once.\n\n- Each entry is the object the single endpoint returns, with the same four\n  windows and ranks.\n- Entries come back in the order requested. Handles match case-insensitively,\n  a leading @ is stripped, and a repeated handle counts once.\n- A handle we do not know goes into `missing` and the call still succeeds.\n- A batch is charged as one call: it is served in full or refused as a whole\n  with **402**, before any entry comes back.\n- A handle with no FOMO trade comes back with every window null, as on the\n  single endpoint.\n\n**Price:** 30,000 CU per handle found, 200 CU per handle in `missing`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["handles"],"properties":{"handles":{"type":"array","minItems":1,"maxItems":100,"items":{"type":"string","minLength":1,"maxLength":64},"description":"fomo.family usernames (case-insensitive; leading @ is stripped).","example":["tradername","anothertrader"]}}}}}},"security":[{"b2bApiKey":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["count","missing","entries"],"properties":{"count":{"type":"integer","description":"Entries returned: the handles we hold."},"missing":{"type":"array","items":{"type":"string"},"description":"Requested handles we do not hold, lowercased and without a leading @. Each is still charged."},"entries":{"type":"array","items":{"type":"object","required":["handle","wallet","evmWallet","updatedAt","windows"],"properties":{"handle":{"type":"string"},"displayName":{"type":["null","string"]},"avatarUrl":{"type":["null","string"]},"twitter":{"type":["null","string"],"description":"Bare X username."},"followers":{"type":["null","integer"]},"wallet":{"type":["null","string"],"description":"The Solana address these numbers include. Null means we hold no verified Solana wallet for this account."},"evmWallet":{"type":["null","string"],"description":"The EVM address these numbers include, across every EVM chain FOMO runs on."},"updatedAt":{"type":["null","integer"],"description":"Epoch ms when these numbers were last refreshed."},"windows":{"type":"object","description":"One entry per window, with all four keys present. Null means we hold no FOMO trade for this account's wallets.","properties":{"24h":{"type":["null","object"],"properties":{"netUsd":{"type":"number","description":"Quote received on sells minus quote paid on buys across the account's FOMO trades in the window, USD. Cash flow, not realized profit: an account that only bought shows negative whatever it holds."},"returnPct":{"type":["null","number"],"description":"netUsd as a percentage of what was paid on buys in the window. Null when nothing was bought."},"volumeUsd":{"type":"number","description":"Bought plus sold in the window, USD."},"trades":{"type":"integer","description":"Swaps in the window."},"rank":{"type":"integer","description":"Position on the netUsd ranking for this window, 1 = highest. Ties share a rank."}}},"7d":{"type":["null","object"],"properties":{"netUsd":{"type":"number","description":"Quote received on sells minus quote paid on buys across the account's FOMO trades in the window, USD. Cash flow, not realized profit: an account that only bought shows negative whatever it holds."},"returnPct":{"type":["null","number"],"description":"netUsd as a percentage of what was paid on buys in the window. Null when nothing was bought."},"volumeUsd":{"type":"number","description":"Bought plus sold in the window, USD."},"trades":{"type":"integer","description":"Swaps in the window."},"rank":{"type":"integer","description":"Position on the netUsd ranking for this window, 1 = highest. Ties share a rank."}}},"30d":{"type":["null","object"],"properties":{"netUsd":{"type":"number","description":"Quote received on sells minus quote paid on buys across the account's FOMO trades in the window, USD. Cash flow, not realized profit: an account that only bought shows negative whatever it holds."},"returnPct":{"type":["null","number"],"description":"netUsd as a percentage of what was paid on buys in the window. Null when nothing was bought."},"volumeUsd":{"type":"number","description":"Bought plus sold in the window, USD."},"trades":{"type":"integer","description":"Swaps in the window."},"rank":{"type":"integer","description":"Position on the netUsd ranking for this window, 1 = highest. Ties share a rank."}}},"all":{"type":["null","object"],"properties":{"netUsd":{"type":"number","description":"Quote received on sells minus quote paid on buys across the account's FOMO trades in the window, USD. Cash flow, not realized profit: an account that only bought shows negative whatever it holds."},"returnPct":{"type":["null","number"],"description":"netUsd as a percentage of what was paid on buys in the window. Null when nothing was bought."},"volumeUsd":{"type":"number","description":"Bought plus sold in the window, USD."},"trades":{"type":"integer","description":"Swaps in the window."},"rank":{"type":"integer","description":"Position on the netUsd ranking for this window, 1 = highest. Ties share a rank."}}}}}}},"description":"One entry per handle we hold, in the order requested, each shaped as GET /v2/user/handle/{handle}/pnl answers."}}}}}}}}},"/v2/thesis":{"get":{"summary":"Every thesis, newest first — the unfiltered feed","tags":["Thesis Feed"],"description":"Every thesis on the platform, newest first, 20 to a page — no token filter,\nno author filter.\n\n- **Live:** poll with no `before` and dedupe on each item’s `id`.\n\nNarrow before you poll if you can: `/v2/thesis/token/{tokenAddress}` and\n`/v2/thesis/user/{id}` answer the same question about one subject, so\npolling this one and filtering client-side buys nothing.\n\n**Price:** 200 CU per 20 requested rows (`limit`, up to 100). An empty page costs the same as a full one.","parameters":[{"schema":{"type":"string"},"in":"query","name":"before","required":false,"description":"The `id` of the last thesis you saw — the previous page’s `nextBefore`. Returns theses older than it. Omit for the newest 20."},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"in":"query","name":"limit","required":false,"description":"Rows per page, 1..100. Priced per started block of 20 rows on the REQUESTED limit."}],"security":[{"b2bApiKey":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["count","hasMore","nextBefore","updatedAt","items"],"properties":{"count":{"type":"integer","description":"Items in this page (0..20)."},"hasMore":{"type":"boolean","description":"Whether older theses exist behind this page."},"nextBefore":{"type":["null","string"],"description":"The OLDEST item’s `id`. Send back as `?before=` for the next page while `hasMore` is true. Null on the last page."},"updatedAt":{"type":["null","integer"],"description":"Post time of the NEWEST thesis in this page, epoch millis."},"items":{"type":"array","items":{"type":"object","required":["id","authorHandle","thesis","fomoCreatedAt"],"properties":{"id":{"type":"string","description":"Thesis id. Dedupe on this, and send it back as `?before=` to paginate. Not related to a user `id`."},"tokenAddress":{"type":["null","string"],"description":"The token this thesis is about. Present on every item, including the narrowed feeds, so one item shape works everywhere."},"tokenNetwork":{"type":["null","string"],"description":"Chain name (`sol`, `eth`, `base`, …)."},"tokenSymbol":{"type":["null","string"],"description":"Ticker."},"authorId":{"type":["null","string"],"description":"The author’s `id`, the same value a user record carries. `/v2/user/id/{id}` returns their profile and `/v2/thesis/user/{id}` everything else they have posted."},"authorHandle":{"type":["null","string"],"description":"Author’s handle. Display it; to look the author up prefer `authorId`, which does not change when they rename."},"authorName":{"type":["null","string"],"description":"Author display name."},"authorIsDev":{"type":["null","boolean"],"description":"Author is the token’s dev."},"thesis":{"type":["null","string"],"description":"The thesis text."},"segments":{"type":["null","array"],"description":"Rich-text runs of the thesis text (text + optional link).","items":{"type":"object","additionalProperties":true}},"likeCount":{"type":["null","integer"]},"holdingsUsd":{"type":["null","number"],"description":"Author’s position value in USD at post time."},"authorTradeUsd":{"type":["null","number"],"description":"USD size of the trade behind the thesis."},"pnl":{"type":["null","number"],"description":"Single PnL figure in USD: realized, falling back to unrealized."},"realizedPnlUsd":{"type":["null","number"],"description":"Realized PnL in USD."},"unrealizedPnlUsd":{"type":["null","number"],"description":"Unrealized PnL in USD."},"percentageRealizedPnl":{"type":["null","number"],"description":"Realized PnL as a percentage."},"percentageUnrealizedPnl":{"type":["null","number"],"description":"Unrealized PnL as a percentage."},"tokenAmount":{"type":["null","number"],"description":"Author’s token balance behind the thesis."},"closedAt":{"type":["null","integer"],"description":"When the author’s position closed, epoch millis. Null while open — the PnL above is then a running figure, not a final one."},"fomoCreatedAt":{"type":["null","integer"],"description":"Post time, epoch milliseconds."},"updatedAt":{"type":["null","integer"],"description":"When we last wrote this record, epoch milliseconds. It can move without any field changing."}}}}}}}}}}}},"/v2/thesis/token/{tokenAddress}":{"get":{"summary":"Theses for a token, newest first — poll this for a live feed","tags":["Thesis Feed"],"description":"The 20 most recent theses for one token, newest first by post time.\n\n- **Live:** call with no `before` on a timer; dedupe on `id`.\n- `before` is a thesis **`id`** — the last thesis you saw — not a timestamp.\n  An id positions the walk exactly, including inside a group of theses\n  posted in the same millisecond, which a timestamp cannot.\n- An unknown `before` is a **400**.\n- Poll on a sensible timer rather than in a tight loop.\n\nA page can come back empty. Ask again on your normal polling interval.\n\n**Price:** 200 CU per 20 requested rows (`limit`, up to 100). An empty page costs the same as a full one.","parameters":[{"schema":{"type":"string"},"in":"query","name":"before","required":false,"description":"The `id` of the last thesis you saw — the previous page’s `nextBefore`. Returns theses older than it. Omit for the newest 20."},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"in":"query","name":"limit","required":false,"description":"Rows per page, 1..100. Priced per started block of 20 rows on the REQUESTED limit."},{"schema":{"type":"string"},"example":"So11111111111111111111111111111111111111112","in":"path","name":"tokenAddress","required":true,"description":"Mint / contract address. Case-sensitive for Solana base58; EVM `0x…` is lower-cased for you."}],"security":[{"b2bApiKey":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["tokenAddress","tokenNetwork","symbol","updatedAt","count","hasMore","nextBefore","items"],"properties":{"tokenAddress":{"type":"string","description":"Normalised (EVM lower-cased)."},"tokenNetwork":{"type":["null","string"],"description":"Chain name (`sol`, `eth`, `base`, …). Null when the page is empty."},"symbol":{"type":["null","string"],"description":"Ticker. Null when the page is empty."},"updatedAt":{"type":["null","integer"],"description":"Post time of the NEWEST thesis in this page, epoch millis."},"count":{"type":"integer","description":"Items in this page (0..20)."},"hasMore":{"type":"boolean","description":"Whether older theses exist behind this page."},"nextBefore":{"type":["null","string"],"description":"The OLDEST item’s `id`. Send back as `?before=` for the next page while `hasMore` is true. Null on the last page."},"items":{"type":"array","items":{"type":"object","required":["id","authorHandle","thesis","fomoCreatedAt"],"properties":{"id":{"type":"string","description":"Thesis id. Dedupe on this, and send it back as `?before=` to paginate. Not related to a user `id`."},"tokenAddress":{"type":["null","string"],"description":"The token this thesis is about. Present on every item, including the narrowed feeds, so one item shape works everywhere."},"tokenNetwork":{"type":["null","string"],"description":"Chain name (`sol`, `eth`, `base`, …)."},"tokenSymbol":{"type":["null","string"],"description":"Ticker."},"authorId":{"type":["null","string"],"description":"The author’s `id`, the same value a user record carries. `/v2/user/id/{id}` returns their profile and `/v2/thesis/user/{id}` everything else they have posted."},"authorHandle":{"type":["null","string"],"description":"Author’s handle. Display it; to look the author up prefer `authorId`, which does not change when they rename."},"authorName":{"type":["null","string"],"description":"Author display name."},"authorIsDev":{"type":["null","boolean"],"description":"Author is the token’s dev."},"thesis":{"type":["null","string"],"description":"The thesis text."},"segments":{"type":["null","array"],"description":"Rich-text runs of the thesis text (text + optional link).","items":{"type":"object","additionalProperties":true}},"likeCount":{"type":["null","integer"]},"holdingsUsd":{"type":["null","number"],"description":"Author’s position value in USD at post time."},"authorTradeUsd":{"type":["null","number"],"description":"USD size of the trade behind the thesis."},"pnl":{"type":["null","number"],"description":"Single PnL figure in USD: realized, falling back to unrealized."},"realizedPnlUsd":{"type":["null","number"],"description":"Realized PnL in USD."},"unrealizedPnlUsd":{"type":["null","number"],"description":"Unrealized PnL in USD."},"percentageRealizedPnl":{"type":["null","number"],"description":"Realized PnL as a percentage."},"percentageUnrealizedPnl":{"type":["null","number"],"description":"Unrealized PnL as a percentage."},"tokenAmount":{"type":["null","number"],"description":"Author’s token balance behind the thesis."},"closedAt":{"type":["null","integer"],"description":"When the author’s position closed, epoch millis. Null while open — the PnL above is then a running figure, not a final one."},"fomoCreatedAt":{"type":["null","integer"],"description":"Post time, epoch milliseconds."},"updatedAt":{"type":["null","integer"],"description":"When we last wrote this record, epoch milliseconds. It can move without any field changing."}}}}}}}}}}}},"/v2/thesis/user/{id}":{"get":{"summary":"Theses by a user, newest first — poll this for their feed","tags":["Thesis Feed"],"description":"Every thesis this user has posted, newest first, 20 to a page.\n\nThe `id` is the one carried on any user record.\n\n- **Live**: poll with no `before` and dedupe on each item’s `id`.\n\nAn empty page means the user has posted nothing we hold.\n\n**Price:** 200 CU per 20 requested rows (`limit`, up to 100). An empty page costs the same as a full one.","parameters":[{"schema":{"type":"string"},"in":"query","name":"before","required":false,"description":"The `id` of the last thesis you saw — the previous page’s `nextBefore`. Returns theses older than it. Omit for the newest 20."},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"in":"query","name":"limit","required":false,"description":"Rows per page, 1..100. Priced per started block of 20 rows on the REQUESTED limit."},{"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-0000-0000-000000000000","in":"path","name":"id","required":true,"description":"The author’s `id`, as carried on any user record."}],"security":[{"b2bApiKey":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["userId","tokenAddress","count","hasMore","nextBefore","updatedAt","items"],"properties":{"userId":{"type":"string","description":"The author, echoed back — the same `id` a user record carries."},"tokenAddress":{"type":["null","string"],"description":"The token this page was narrowed to, normalised. Null on the unfiltered feed."},"count":{"type":"integer","description":"Items in this page (0..20)."},"hasMore":{"type":"boolean","description":"Whether older theses exist behind this page."},"nextBefore":{"type":["null","string"],"description":"The OLDEST item’s `id`. Send back as `?before=` for the next page while `hasMore` is true. Null on the last page."},"updatedAt":{"type":["null","integer"],"description":"Post time of the NEWEST thesis in this page, epoch millis."},"items":{"type":"array","items":{"type":"object","required":["id","authorHandle","thesis","fomoCreatedAt"],"properties":{"id":{"type":"string","description":"Thesis id. Dedupe on this, and send it back as `?before=` to paginate. Not related to a user `id`."},"tokenAddress":{"type":["null","string"],"description":"The token this thesis is about. Present on every item, including the narrowed feeds, so one item shape works everywhere."},"tokenNetwork":{"type":["null","string"],"description":"Chain name (`sol`, `eth`, `base`, …)."},"tokenSymbol":{"type":["null","string"],"description":"Ticker."},"authorId":{"type":["null","string"],"description":"The author’s `id`, the same value a user record carries. `/v2/user/id/{id}` returns their profile and `/v2/thesis/user/{id}` everything else they have posted."},"authorHandle":{"type":["null","string"],"description":"Author’s handle. Display it; to look the author up prefer `authorId`, which does not change when they rename."},"authorName":{"type":["null","string"],"description":"Author display name."},"authorIsDev":{"type":["null","boolean"],"description":"Author is the token’s dev."},"thesis":{"type":["null","string"],"description":"The thesis text."},"segments":{"type":["null","array"],"description":"Rich-text runs of the thesis text (text + optional link).","items":{"type":"object","additionalProperties":true}},"likeCount":{"type":["null","integer"]},"holdingsUsd":{"type":["null","number"],"description":"Author’s position value in USD at post time."},"authorTradeUsd":{"type":["null","number"],"description":"USD size of the trade behind the thesis."},"pnl":{"type":["null","number"],"description":"Single PnL figure in USD: realized, falling back to unrealized."},"realizedPnlUsd":{"type":["null","number"],"description":"Realized PnL in USD."},"unrealizedPnlUsd":{"type":["null","number"],"description":"Unrealized PnL in USD."},"percentageRealizedPnl":{"type":["null","number"],"description":"Realized PnL as a percentage."},"percentageUnrealizedPnl":{"type":["null","number"],"description":"Unrealized PnL as a percentage."},"tokenAmount":{"type":["null","number"],"description":"Author’s token balance behind the thesis."},"closedAt":{"type":["null","integer"],"description":"When the author’s position closed, epoch millis. Null while open — the PnL above is then a running figure, not a final one."},"fomoCreatedAt":{"type":["null","integer"],"description":"Post time, epoch milliseconds."},"updatedAt":{"type":["null","integer"],"description":"When we last wrote this record, epoch milliseconds. It can move without any field changing."}}}}}}}}}}}},"/v2/thesis/user/{id}/token/{tokenAddress}":{"get":{"summary":"Theses by a user about one token","tags":["Thesis Feed"],"description":"Everything one user has posted about one token, newest first.\n\nThe intersection of the two walls above. Same page size, same `?before=`\ncursor, same item shape — only the filter is narrower.\n\nAn empty page means this user has said nothing we hold about this token. It\ndoes NOT mean the token is unknown to us: ask `/v2/thesis/token/{tokenAddress}`\nfor that.\n\n**Price:** 200 CU per 20 requested rows (`limit`, up to 100). An empty page costs the same as a full one.","parameters":[{"schema":{"type":"string"},"in":"query","name":"before","required":false,"description":"The `id` of the last thesis you saw — the previous page’s `nextBefore`. Returns theses older than it. Omit for the newest 20."},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"in":"query","name":"limit","required":false,"description":"Rows per page, 1..100. Priced per started block of 20 rows on the REQUESTED limit."},{"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-0000-0000-000000000000","in":"path","name":"id","required":true,"description":"The author’s `id`, as carried on any user record."},{"schema":{"type":"string"},"example":"So11111111111111111111111111111111111111112","in":"path","name":"tokenAddress","required":true,"description":"Mint / contract address. Case-sensitive for Solana base58; EVM `0x…` is lower-cased for you."}],"security":[{"b2bApiKey":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["userId","tokenAddress","count","hasMore","nextBefore","updatedAt","items"],"properties":{"userId":{"type":"string","description":"The author, echoed back — the same `id` a user record carries."},"tokenAddress":{"type":["null","string"],"description":"The token this page was narrowed to, normalised. Null on the unfiltered feed."},"count":{"type":"integer","description":"Items in this page (0..20)."},"hasMore":{"type":"boolean","description":"Whether older theses exist behind this page."},"nextBefore":{"type":["null","string"],"description":"The OLDEST item’s `id`. Send back as `?before=` for the next page while `hasMore` is true. Null on the last page."},"updatedAt":{"type":["null","integer"],"description":"Post time of the NEWEST thesis in this page, epoch millis."},"items":{"type":"array","items":{"type":"object","required":["id","authorHandle","thesis","fomoCreatedAt"],"properties":{"id":{"type":"string","description":"Thesis id. Dedupe on this, and send it back as `?before=` to paginate. Not related to a user `id`."},"tokenAddress":{"type":["null","string"],"description":"The token this thesis is about. Present on every item, including the narrowed feeds, so one item shape works everywhere."},"tokenNetwork":{"type":["null","string"],"description":"Chain name (`sol`, `eth`, `base`, …)."},"tokenSymbol":{"type":["null","string"],"description":"Ticker."},"authorId":{"type":["null","string"],"description":"The author’s `id`, the same value a user record carries. `/v2/user/id/{id}` returns their profile and `/v2/thesis/user/{id}` everything else they have posted."},"authorHandle":{"type":["null","string"],"description":"Author’s handle. Display it; to look the author up prefer `authorId`, which does not change when they rename."},"authorName":{"type":["null","string"],"description":"Author display name."},"authorIsDev":{"type":["null","boolean"],"description":"Author is the token’s dev."},"thesis":{"type":["null","string"],"description":"The thesis text."},"segments":{"type":["null","array"],"description":"Rich-text runs of the thesis text (text + optional link).","items":{"type":"object","additionalProperties":true}},"likeCount":{"type":["null","integer"]},"holdingsUsd":{"type":["null","number"],"description":"Author’s position value in USD at post time."},"authorTradeUsd":{"type":["null","number"],"description":"USD size of the trade behind the thesis."},"pnl":{"type":["null","number"],"description":"Single PnL figure in USD: realized, falling back to unrealized."},"realizedPnlUsd":{"type":["null","number"],"description":"Realized PnL in USD."},"unrealizedPnlUsd":{"type":["null","number"],"description":"Unrealized PnL in USD."},"percentageRealizedPnl":{"type":["null","number"],"description":"Realized PnL as a percentage."},"percentageUnrealizedPnl":{"type":["null","number"],"description":"Unrealized PnL as a percentage."},"tokenAmount":{"type":["null","number"],"description":"Author’s token balance behind the thesis."},"closedAt":{"type":["null","integer"],"description":"When the author’s position closed, epoch millis. Null while open — the PnL above is then a running figure, not a final one."},"fomoCreatedAt":{"type":["null","integer"],"description":"Post time, epoch milliseconds."},"updatedAt":{"type":["null","integer"],"description":"When we last wrote this record, epoch milliseconds. It can move without any field changing."}}}}}}}}}}}},"/v2/me":{"get":{"summary":"Introspect the calling API key","tags":["Account"],"description":"Returns the account, plan, scopes, entitlement and current usage for\nthe presented API key.\n\n- Requires any valid API key (no specific scope).\n- Not metered.\n- `usage.period` is the current UTC month, `YYYY-MM`. `usage.unitsRemaining` never goes below 0.\n- `usage.additionalUnits` never expires and is spent only once the month’s grant cannot cover a call.\n- `usage.revealsUsed` counts the responses that returned a wallet this period, forward lookups included.\n- `entitlement.unmetered` is true on a key that is never refused for quota. Calls are still counted, so `usage.unitsUsed` climbs as always, and `monthlyUnits` still reports the plan’s grant without acting as a limit.\n- `usage.unitsRemaining` and `usage.revealsRemaining` are `null`, not `0`,\n  on a key with no cap to count down.","security":[{"b2bApiKey":[]}],"responses":{"401":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/def-0"}}}},"429":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/def-0"}}}},"503":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/def-0"}}}}}}},"/v2/pump/user/wallet/{wallet}":{"get":{"summary":"A pump.fun user by wallet","tags":["Pump"],"description":"The pump.fun profile for a wallet: handle, bio, follower counts, linked X handle.\n\n- On pump.fun the **wallet is the account**, so this is a read, not a resolution.\n- **404** when the wallet has no pump.fun user.\n\n**Price:** 10 CU per call.","parameters":[{"schema":{"type":"string","minLength":1,"maxLength":128},"in":"path","name":"wallet","required":true}],"security":[{"b2bApiKey":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"wallet":{"type":"string"},"username":{"type":["null","string"]},"bio":{"type":["null","string"]},"profileImage":{"type":["null","string"]},"xUsername":{"type":["null","string"],"description":"Linked X handle."},"isVerified":{"type":["null","boolean"]},"isPumpUser":{"type":["null","boolean"],"description":"False for a wallet that traded without creating an account."},"followers":{"type":["null","integer"]},"following":{"type":["null","integer"]},"groupBadges":{"type":"array","items":{"type":"string"}}}}}}}}}},"/v2/pump/thesis":{"get":{"summary":"Every pump.fun callout, newest first","tags":["Pump"],"description":"The 25 most recent pump.fun callouts across ALL coins. The global\nthesis feed pump.fun itself does not expose.\n\n- **Live:** poll with no `before`; dedupe on `id`.\n- `before` is a callout **`id`**; an unknown one is a **400**.\n- `hasMore` is true while older callouts remain; `nextBefore` is where they start.\n\n**Price:** 10 CU per call.","parameters":[{"schema":{"type":"string"},"in":"query","name":"before","required":false,"description":"Previous page’s `nextBefore`."}],"security":[{"b2bApiKey":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["count","hasMore","nextBefore","items"],"properties":{"count":{"type":"integer","description":"Items in this page (0..25)."},"hasMore":{"type":"boolean","description":"True when older callouts sit behind this page."},"nextBefore":{"type":["null","string"],"description":"Oldest item's `id`; send as `?before=` to continue. Null on the last page."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"wallet":{"type":"string","description":"The author. On pump.fun the wallet is the identity."},"userName":{"type":["null","string"]},"xUsername":{"type":["null","string"]},"isVerified":{"type":["null","boolean"]},"coinMint":{"type":"string"},"chain":{"type":["null","string"]},"coinSymbol":{"type":["null","string"]},"coinName":{"type":["null","string"]},"thesis":{"type":["null","string"]},"mediaUrl":{"type":["null","string"]},"calledOutAtMcap":{"type":["null","number"],"description":"Market cap (USD) when the callout was posted."},"multiple":{"type":["null","number"],"description":"Price move since the callout, ×."},"maxMultiplier":{"type":["null","number"]},"createdAt":{"type":["null","integer"],"description":"Post time, epoch ms."}}}}}}}}}}}},"/v2/pump/thesis/token/{mint}":{"get":{"summary":"A coin's callout wall, newest first","tags":["Pump"],"description":"The 25 most recent pump.fun callouts (their theses) for a coin.\n\n- **Live:** poll with no `before`; dedupe on `id`.\n- `before` is a callout **`id`**; an unknown one is a **400**.\n- `hasMore` is true while older callouts remain; `nextBefore` is where they start.\n\n**Price:** 10 CU per call.","parameters":[{"schema":{"type":"string"},"in":"query","name":"before","required":false,"description":"Previous page’s `nextBefore`."},{"schema":{"type":"string","minLength":1,"maxLength":128},"in":"path","name":"mint","required":true}],"security":[{"b2bApiKey":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["count","hasMore","nextBefore","items"],"properties":{"count":{"type":"integer","description":"Items in this page (0..25)."},"hasMore":{"type":"boolean","description":"True when older callouts sit behind this page."},"nextBefore":{"type":["null","string"],"description":"Oldest item's `id`; send as `?before=` to continue. Null on the last page."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"wallet":{"type":"string","description":"The author. On pump.fun the wallet is the identity."},"userName":{"type":["null","string"]},"xUsername":{"type":["null","string"]},"isVerified":{"type":["null","boolean"]},"coinMint":{"type":"string"},"chain":{"type":["null","string"]},"coinSymbol":{"type":["null","string"]},"coinName":{"type":["null","string"]},"thesis":{"type":["null","string"]},"mediaUrl":{"type":["null","string"]},"calledOutAtMcap":{"type":["null","number"],"description":"Market cap (USD) when the callout was posted."},"multiple":{"type":["null","number"],"description":"Price move since the callout, ×."},"maxMultiplier":{"type":["null","number"]},"createdAt":{"type":["null","integer"],"description":"Post time, epoch ms."}}}}}}}}}}}},"/v2/pump/thesis/wallet/{wallet}":{"get":{"summary":"A wallet's callouts, newest first","tags":["Pump"],"description":"The 25 most recent callouts posted by one wallet. Same paging as\nthe token wall.\n\n- **Live:** poll with no `before`; dedupe on `id`.\n- `before` is a callout **`id`**; an unknown one is a **400**.\n- `hasMore` is true while older callouts remain; `nextBefore` is where they start.\n\n**Price:** 10 CU per call.","parameters":[{"schema":{"type":"string"},"in":"query","name":"before","required":false,"description":"Previous page’s `nextBefore`."},{"schema":{"type":"string","minLength":1,"maxLength":128},"in":"path","name":"wallet","required":true}],"security":[{"b2bApiKey":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["count","hasMore","nextBefore","items"],"properties":{"count":{"type":"integer","description":"Items in this page (0..25)."},"hasMore":{"type":"boolean","description":"True when older callouts sit behind this page."},"nextBefore":{"type":["null","string"],"description":"Oldest item's `id`; send as `?before=` to continue. Null on the last page."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"wallet":{"type":"string","description":"The author. On pump.fun the wallet is the identity."},"userName":{"type":["null","string"]},"xUsername":{"type":["null","string"]},"isVerified":{"type":["null","boolean"]},"coinMint":{"type":"string"},"chain":{"type":["null","string"]},"coinSymbol":{"type":["null","string"]},"coinName":{"type":["null","string"]},"thesis":{"type":["null","string"]},"mediaUrl":{"type":["null","string"]},"calledOutAtMcap":{"type":["null","number"],"description":"Market cap (USD) when the callout was posted."},"multiple":{"type":["null","number"],"description":"Price move since the callout, ×."},"maxMultiplier":{"type":["null","number"]},"createdAt":{"type":["null","integer"],"description":"Post time, epoch ms."}}}}}}}}}}}},"/v2/pump/leaderboard/traders":{"get":{"summary":"The pump.fun PnL leaderboard","tags":["Pump"],"description":"pump.fun's top 100 traders by realized+unrealized PnL, as a snapshot.\n\n- `period` is `daily`, `weekly` (default) or `monthly`.\n- `capturedAt` is the time of the snapshot.\n- **Point-in-time:** `?at=` (epoch ms or ISO) returns the latest snapshot at or\n  before that instant.\n\n**Price:** 10 CU per call.","parameters":[{"schema":{"type":"string","enum":["daily","weekly","monthly"],"default":"weekly"},"in":"query","name":"period","required":false},{"schema":{"type":"string"},"in":"query","name":"at","required":false,"description":"Epoch ms or ISO timestamp."}],"security":[{"b2bApiKey":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["period","capturedAt","count","entries"],"properties":{"period":{"type":"string"},"capturedAt":{"type":["null","integer"],"description":"Snapshot time, epoch ms."},"count":{"type":"integer"},"entries":{"type":"array","items":{"type":"object","properties":{"rank":{"type":"integer"},"wallet":{"type":"string"},"username":{"type":["null","string"]},"isVerified":{"type":["null","boolean"]},"pnlSol":{"type":["null","number"]},"pnlUsd":{"type":["null","number"]},"pnlPercent":{"type":["null","number"]},"realizedPnlUsd":{"type":["null","number"]},"unrealizedPnlUsd":{"type":["null","number"]}}}}}}}}}}}},"/v2/ws":{"get":{"tags":["WebSocket"],"summary":"Live theses, the firehose or a token list (WebSocket)","description":"One WebSocket for the thesis feed. Attach once, then declare what you want\n— the firehose or a list of tokens — and change it at any time without\nreconnecting.\n\n**This path is an upgrade, not a request.** A plain `GET` returns `404`;\nonly a request carrying the WebSocket handshake headers is served.\n\n**The key cannot come from a browser.** Authentication is the same\n`authorization: Bearer <key>` header as every other endpoint, and the\nbrowser `WebSocket` constructor cannot set headers. Hold the socket in your\nbackend and relay to your front end from there.\n\nA key that lacks the scope for this path is refused during the handshake\nwith a `403`, before the upgrade, so you read it as an HTTP status rather\nthan a dropped socket.\n\n### Subscribing\n\nA connection holds **one** subscription. It is one of two shapes:\n\n```json\n{ \"type\": \"subscribe\", \"subscription\": { \"type\": \"all\" } }\n{ \"type\": \"subscribe\", \"subscription\": { \"type\": \"tokens\", \"tokens\": [\"So1111…\", \"0xabc…\"] } }\n```\n\nA `subscribe` **replaces** whatever you had before — it does not add to it.\nTo change your watchlist, send the new list in full. To stop receiving:\n\n```json\n{ \"type\": \"unsubscribe\" }\n```\n\nThat is the one thing here likely to catch you out, so we say it out loud\non the wire too — see the `replaced` frame below.\n\nYou attach unsubscribed and receive nothing until you ask. A `tokens`\nsubscription may name up to **50** addresses; past that, use `all` — it is\none subscription and it already carries every token.\n\n### Frames you receive\n\nOn attach:\n\n```json\n{ \"type\": \"ready\", \"connectionId\": \"4f9c…\" }\n```\n\nAfter every accepted frame, your current subscription — the whole of it, so\nthere is nothing to reconcile (`null` once you unsubscribe):\n\n```json\n{ \"type\": \"subscription\", \"subscription\": { \"type\": \"tokens\", \"tokens\": [\"So1111…\"] } }\n```\n\nAnd, when a `subscribe` tore down an earlier subscription, one frame ahead\nof it saying what stopped:\n\n```json\n{ \"type\": \"replaced\", \"previous\": { \"type\": \"tokens\", \"tokens\": [\"EPjF…\"] } }\n```\n\nThe two always arrive in that order, so a client applying frames as they\nland never ends up holding the dead subscription. A rejected `subscribe`\nproduces neither — nothing was torn down.\n\nThen one frame per matching thesis:\n\n```json\n{ \"type\": \"thesis\", \"data\": { \"id\": \"…\", \"tokenAddress\": \"…\", \"tokenNetwork\": \"sol\", … } }\n```\n\n`data` is the **same object** `GET /v2/thesis/token/{tokenAddress}` returns\nin `items` — same field names, same `id`, same epoch-millisecond\ntimestamps — plus `authorAvatarUrl` and `tokenImageUrl`, which a live\nclient needs at the moment a thesis lands. It is not a second shape to code\nagainst. Read `data.tokenAddress` to route a frame back to its token.\n\nA rejected frame is answered, does not close the socket, and does **not**\nchange what you are subscribed to — so a typo costs you nothing:\n\n```json\n{ \"type\": \"error\", \"error\": \"too many addresses: 91 named, 50 is the cap\" }\n```\n\n### What you have to know before you build on it\n\n- **There is no replay.** You hear what arrives after you subscribe,\n  nothing before it. Take a snapshot from the polling endpoint and\n  reconcile on `id`, which is stable and is the same id the polling\n  endpoint returns. If the socket drops,\n  poll to close the gap, then reattach and resubscribe.\n- **Subscriptions do not survive a reconnect.** A new socket starts empty.\n- **A thesis is sent once.** It is never re-sent on the same socket.\n- **The socket carries recent theses.** Anything outside that window is on\n  the polling endpoint instead.\n- **Frames are not ordered by `fomoCreatedAt`.** Sort client-side if order\n  matters.\n- **`null` means the value was not observed.** An absent `likeCount` is not\n  a zero.\n- **The pong is mandatory.** The server pings, and terminates any socket\n  that has not ponged by the next ping. Browser and Node `ws` clients\n  answer automatically; a hand-rolled client must reply itself. A socket\n  killed mid-path by a proxy stays open and silent at both ends, and the\n  pong is the only thing that detects it.\n\n### Close codes\n\n| code | meaning |\n|---|---|\n| `1008` | the key is out of quota |\n\n### Billing\n\nThis path is metered by the minute held open rather than by the call. The\nmeter stops when the socket closes. Rates are published at\n`GET /portal/plans`; see `GET /v2/me` for your remaining balance.\n\nThe price is **per socket, not per token**: one address, fifty, or the whole\nfirehose all read the same on the meter.\n\n**Price:** 20,000 CU per minute held open.","security":[{"b2bApiKey":[]}],"responses":{"101":{"description":"Switching Protocols — the socket is open."},"401":{"description":"Missing or invalid API key."},"404":{"description":"The request carried no WebSocket upgrade."}}}}},"components":{"securitySchemes":{"b2bApiKey":{"type":"http","scheme":"bearer","description":"B2B API key (`fsk_live_…` / `fsk_test_…`), issued by FomoScan. Also accepted via `X-Api-Key`."}},"schemas":{"ErrorBody":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","description":"Stable, lower-snake-case error code.","enum":["BAD_REQUEST","B2B_DISABLED","CONFLICT","FORBIDDEN","FORBIDDEN_SCOPE","FREE_TIER_DISABLED","INTERNAL_ERROR","NOT_FOUND","NOT_OBSERVED","OVERLOADED","QUOTA_EXCEEDED","RATE_LIMITED","REVEAL_LIMIT_REACHED","TIMEOUT","UNAUTHORIZED","VALIDATION_ERROR"]},"message":{"type":"string"},"retryAfter":{"type":"integer","description":"Seconds; only on RATE_LIMITED."},"addUrl":{"type":"string","description":"Hint URL, present on some NOT_FOUND responses."}}}}},"def-0":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","description":"Stable, lower-snake-case error code.","enum":["BAD_REQUEST","B2B_DISABLED","CONFLICT","FORBIDDEN","FORBIDDEN_SCOPE","FREE_TIER_DISABLED","INTERNAL_ERROR","NOT_FOUND","NOT_OBSERVED","OVERLOADED","QUOTA_EXCEEDED","RATE_LIMITED","REVEAL_LIMIT_REACHED","TIMEOUT","UNAUTHORIZED","VALIDATION_ERROR"]},"message":{"type":"string"},"retryAfter":{"type":"integer","description":"Seconds; only on RATE_LIMITED."},"addUrl":{"type":"string","description":"Hint URL, present on some NOT_FOUND responses."}}}},"title":"ErrorBody"}}}}