> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fomoscan.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# Resolve a handle to its wallets (temporarily unavailable)

> **Temporarily unavailable.** Live resolution is paused.

- A handle we already hold a wallet for is answered from our data: **200** with the
  ordinary user record and `x-fomoscan-resolve: cached`, at the usual hit price.
- A request for a handle we do not already hold answers **202**
  `{ pending: true, reason: "unavailable", retryable: false }` and is not charged.
- This paused response includes a `message` explaining that no job was queued and cached wallet lookups remain available.

When live resolution runs, it returns the wallet we hold for this handle, and looks for
one when we hold none:

- **200** returns the ordinary user record.
- **202** `{ pending: true, reason }` means the answer is not ready, not that the call
  failed. `retryAfterSeconds` says when to ask again. Asking again does not start a
  second resolve, it joins the one already running.
- **404** when no such FOMO user exists, as opposed to a 202, which means we could not
  answer yet.
- A live answer can take several seconds, so allow for it in your client timeout.
- `x-fomoscan-resolve: cached` on a response answered from a wallet we already held, `live` when we went and looked.
- Refused with **402** before any work starts when the key cannot pay for a hit.
- Rate limited to **10/minute** per IP, separately from your plan rate.

A response that carries a wallet counts as one of the plan’s monthly reveals.

**Price:** 30,000 CU on a hit, 200 CU on a 202 or a 404. A paused lookup (202 with reason unavailable and retryable false) is not charged.



## OpenAPI

````yaml https://api.fomoscan.sh/openapi.json post /v2/user/handle/{handle}/resolve
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

    any wallet back to the traders behind it. Every returned address is a

    verified match.


    ## Authentication

    Send your API key as `Authorization: Bearer fsk_live_…` (or the

    `X-Api-Key` header). Enter it under Authentication at the top of this

    page to call any endpoint live.


    ```bash

    curl -s -H "Authorization: Bearer $KEY" \
      "https://api.fomoscan.sh/v2/user/handle/tradername"
    ```


    ## Response format

    A successful response is the record itself, as flat JSON. There is no

    wrapper to unwrap. Timestamps on thesis and PnL records are epoch

    milliseconds.


    ## Billing

    - A lookup that finds nothing is still charged, at the miss price stated on
    the endpoint.

    - `GET /v2/me` is free and reports your remaining units.

    - Errors that are our fault or your client’s (`401`, `403`, `429`, `5xx`)
    are not billed.

    - When the allowance is spent, calls return `402 QUOTA_EXCEEDED` until the
    counter resets.


    ## Free keys

    A free key reveals wallets for the sample set below and nobody else.

    Sample lookups cost no credits. Outside the set, a wallet lookup, or a

    handle or id lookup whose answer carries a wallet, returns

    `403 SAMPLE_SET_ONLY`. Profiles without a wallet and misses answer as

    they do for any key. A self-serve free key cannot open the WebSocket.


    - Handles: `frankdegods`, `unipcs`, `pointfarmcap`, `orangie`, `theveeman`

    - Wallets: `498g1rVnFcnjBjpfw1xyqA1WvgQXUU8RWuELjxkjAayQ`,
    `0x696d1265c8fc4f14797abebfae3c43ebfa9d8e28`,
    `2heJbC32Tpfcb3nbUb5ER61K11FGZVfVGtVnDm6LDogF`,
    `Beqv6dzTcjV2eodo8RRXCiCcnSYrS1vkQKhfqwHXqeit`,
    `83b2LMf12aLec92kur3duRA8VvUkLaXUtML31aCcZNCM`,
    `F5hkYsi8JxjyA2JHN5CA7MbnnhWubkXB2ZQB7Gkaxqs6`


    ## 404 NOT_FOUND

    A lookup that finds nothing answers `404` with the code `NOT_FOUND`. On

    a handle or id lookup it means we hold no user under that handle or id.

    On a wallet lookup it means we hold no verified link from that address

    to a trader. Treat it as "no answer today", cache the negative briefly

    and ask again later. A user we hold without a verified wallet answers

    `200` with both addresses `null`.


    ## Errors

    Every error uses one shape: `{ "error": { "code": "…", "message": "…" } }`.


    | HTTP | Code | Meaning |

    |---|---|---|

    | 400 | `VALIDATION_ERROR` | A malformed handle, address or query parameter.
    |

    | 400 | `BAD_REQUEST` | The request cannot be served as sent. |

    | 401 | `UNAUTHORIZED` | Missing or invalid API key. |

    | 402 | `QUOTA_EXCEEDED` | Out of credits. |

    | 402 | `REVEAL_LIMIT_REACHED` | The key’s reveal limit is reached. |

    | 403 | `FORBIDDEN` | The key may not perform this action. |

    | 403 | `FORBIDDEN_SCOPE` | The key is not provisioned for this endpoint. |

    | 403 | `FREE_TIER_DISABLED` | The key has no allowance. |

    | 403 | `SAMPLE_SET_ONLY` | A free key asked for a wallet outside the sample
    set. |

    | 403 | `WEBSOCKET_PLAN_REQUIRED` | The key’s plan has no WebSocket. It is
    included from Growth ($899), and legacy plans keep it. |

    | 404 | `NOT_FOUND` | No answer for the handle, id or wallet you asked
    about, or no such route. See the section above. |

    | 409 | `CONFLICT` | The request conflicts with one already accepted. |

    | 429 | `RATE_LIMITED` | Per-minute limit exceeded. Retry after `retryAfter`
    seconds. |

    | 500 | `INTERNAL_ERROR` | Our fault. Retry. If it persists, contact support
    with the path and the time. |

    | 503 | `OVERLOADED` | We are shedding load. Retry. |

    | 503 | `B2B_DISABLED` | The API is switched off on this deployment. |

    | 504 | `TIMEOUT` | The answer did not arrive in time. Retry. |


    A `429` also carries `retryAfter`, in seconds.


    ## Rate limits

    Each key has one per-minute request limit across every endpoint,

    readable from `GET /v2/me` as `ratePerMinute`. A per-IP burst ceiling

    sits behind it. Exceeding either returns `429 RATE_LIMITED`.


    ## Pricing

    Paid plans reach every REST endpoint. Plans differ in credits, request rate,

    wallet reveals and the WebSocket. Credits and CU are the same unit.


    | Plan | Free | Starter | Builder | Growth | Scale | Enterprise |

    | --- | --- | --- | --- | --- | --- | --- |

    | Price per month | $0 | $99 | $299 | $899 | $2,499 | Set in the contract |

    | Credits | 25,000 once, for 30 days | 1,000,000 a month | 5,000,000 a month
    | 20,000,000 a month | 75,000,000 a month | Set in the contract |

    | Requests per minute | 60 | 150 | 300 | 600 | 1,200 | Set in the contract |

    | Wallet reveals per month | Sample set only | 150 | 500 | 1,500 | 4,000 |
    No cap |

    | Price per 30,000-credit reveal | $0 on the sample set | $2.97 | $1.79 |
    $1.35 | $1.00 | Set in the contract |

    | WebSocket | No | No | No | Included | Included | Included |


    Keys on legacy plans keep the WebSocket access they already have.


    ### Wallet reveals

    A wallet reveal is an answer that returns a verified wallet. Each reveal
    counts

    against the plan’s wallet reveals for the month. It costs the credits of the

    endpoint that returned it:


    | Reveal endpoint | Credits per reveal |

    | --- | --- |

    | `GET /v2/user/handle/{handle}` | 100 |

    | `GET /v2/user/wallet/{address}` | 30,000 |

    | `GET /v2/user/id/{id}` | 100 |

    | `POST /v2/user/handle/{handle}/resolve` | 30,000 |

    | `GET /v2/user/handle/{handle}/pnl` | 30,000 |

    | `POST /v2/user/handles/pnl` | 30,000 per handle revealed |


    The price per 30,000-credit reveal in the plan table is what 30,000 credits

    cost on the plan. It applies to `GET /v2/user/wallet/{address}`, `POST
    /v2/user/handle/{handle}/resolve`, `GET /v2/user/handle/{handle}/pnl`, `POST
    /v2/user/handles/pnl`.

    A reveal on another endpoint costs that endpoint’s credits.


    ### Credit cost per endpoint


    | Endpoint | Credits |

    | --- | --- |

    | `GET /v2/user/handle/{handle}` | 100 CU on a hit, 200 CU on a 404. |

    | `GET /v2/user/wallet/{address}` | 30,000 CU on a hit, 200 CU on a 404. |

    | `GET /v2/user/id/{id}` | 100 CU on a hit, 200 CU on a 404. |

    | `POST /v2/user/handle/{handle}/resolve` | 30,000 CU on a hit, 200 CU on a
    202 or a 404. A paused lookup (202 with reason unavailable and retryable
    false) is not charged. |

    | `GET /v2/user/handle/{handle}/pnl` | 30,000 CU on a hit, 200 CU on any
    answer that is not ready, and on a 404. |

    | `POST /v2/user/handles/pnl` | 30,000 CU per entry answered ready, 200 CU
    per entry not ready and per handle in `missing`. |

    | `GET /v2/thesis` | 200 CU per 20 requested rows (`limit`, up to 100). An
    empty page costs the same as a full one. |

    | `GET /v2/thesis/token/{tokenAddress}` | 200 CU per 20 requested rows
    (`limit`, up to 100). An empty page costs the same as a full one. |

    | `GET /v2/thesis/user/{id}` | 200 CU per 20 requested rows (`limit`, up to
    100). An empty page costs the same as a full one. |

    | `GET /v2/thesis/user/{id}/token/{tokenAddress}` | 200 CU per 20 requested
    rows (`limit`, up to 100). An empty page costs the same as a full one. |

    | `GET /v2/me` | Free. |

    | `GET /v2/pump/user/wallet/{wallet}` | 10 CU per call. |

    | `GET /v2/pump/thesis` | 10 CU per call. |

    | `GET /v2/pump/thesis/token/{mint}` | 10 CU per call. |

    | `GET /v2/pump/thesis/wallet/{wallet}` | 10 CU per call. |

    | `GET /v2/pump/leaderboard/traders` | 10 CU per call. |

    | `GET /v2/pump/user/wallet/{wallet}/pnl` | 500 CU per call. |

    | `GET /v2/ws` | 20,000 CU per minute held open. |

    | `GET /v2/ws/pump` | 20,000 CU per minute held open. |


    ### Credit packs

    A pack adds credits on top of a plan. Pack credits do not expire, and they
    are

    spent after the plan’s monthly credits run out.


    | Pack | Price |

    | --- | --- |

    | 250,000 credits | $29 |

    | 1,000,000 credits | $115 |

    | 5,000,000 credits | $349 |

    | 20,000,000 credits | $1,049 |

    | 75,000,000 credits | $2,899 |


    ### Payment

    Plans are paid by card, and Apple Pay counts as a card. Credit packs are
    paid

    in crypto only, with no surcharge.


    ## Chains

    Wallet lookups take a Solana address or an EVM address. A verified EVM
    address

    is the same address on every EVM chain.


    Theses carry their token’s chain in `tokenNetwork`. This table shows the
    value

    the API returns for each chain we serve. Some chains arrive as a short name
    and

    some as a numeric chain id. Match on the exact value in the table.


    | Chain | `tokenNetwork` |

    | --- | --- |

    | Solana | `sol` |

    | Base | `base` |

    | BNB Chain | `bsc` |

    | Robinhood Chain | `robinhood` |

    | Ethereum | `eth` |

    | Arc | `5042` |

    | Monad | `143` |


    A thesis on a chain outside this table arrives as a short name or a numeric
    chain id.


    ## Breaking changes

    A breaking change removes or renames an endpoint, a field or an error code,
    or

    changes what a field means. We announce each one at least 3 days before it

    ships. The notice goes out on the changelog, on the Telegram announcements

    channel (https://t.me/scanfomo) and on every other channel we run.


    New fields can appear without notice. Ignore fields you do not recognise.
  contact:
    name: FomoScan
    url: https://fomoscan.sh
    email: fomoscan-support@proton.me
servers:
  - url: https://api.fomoscan.sh
    description: Production
security: []
tags:
  - name: Identities
    description: Resolve handles ↔ wallets.
  - name: Thesis Feed
    description: >-
      Trader "thesis" posts, newest first, by token, by author, or both. Ask
      with no `before` for the newest page. 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}/resolve:
    post:
      tags:
        - Identities
      summary: Resolve a handle to its wallets (temporarily unavailable)
      description: >-
        **Temporarily unavailable.** Live resolution is paused.


        - A handle we already hold a wallet for is answered from our data:
        **200** with the
          ordinary user record and `x-fomoscan-resolve: cached`, at the usual hit price.
        - A request for a handle we do not already hold answers **202**
          `{ pending: true, reason: "unavailable", retryable: false }` and is not charged.
        - This paused response includes a `message` explaining that no job was
        queued and cached wallet lookups remain available.


        When live resolution runs, it returns the wallet we hold for this
        handle, and looks for

        one when we hold none:


        - **200** returns the ordinary user record.

        - **202** `{ pending: true, reason }` means the answer is not ready, not
        that the call
          failed. `retryAfterSeconds` says when to ask again. Asking again does not start a
          second resolve, it joins the one already running.
        - **404** when no such FOMO user exists, as opposed to a 202, which
        means we could not
          answer yet.
        - A live answer can take several seconds, so allow for it in your client
        timeout.

        - `x-fomoscan-resolve: cached` on a response answered from a wallet we
        already held, `live` when we went and looked.

        - Refused with **402** before any work starts when the key cannot pay
        for a hit.

        - Rate limited to **10/minute** per IP, separately from your plan rate.


        A response that carries a wallet counts as one of the plan’s monthly
        reveals.


        **Price:** 30,000 CU on a hit, 200 CU on a 202 or a 404. A paused lookup
        (202 with reason unavailable and retryable false) is not charged.
      parameters:
        - schema:
            type: string
            minLength: 1
            maxLength: 64
          example: tradername
          in: path
          name: handle
          required: true
          description: FOMO handle (case-insensitive; leading @ is stripped).
      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 on our image host, or null. The path is
                      `/a/<key>.webp`. A new picture gets a new URL. A picture
                      added in the last few minutes can show a neutral
                      placeholder until it is ready.
                  profilePicture:
                    type:
                      - 'null'
                      - string
                    description: >-
                      Avatar URL on our image host, or null. The path is
                      `/a/<key>.webp`. A new picture gets a new URL. A picture
                      added in the last few minutes can show a neutral
                      placeholder until it is ready.
                  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: >-
                            Platform-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
                  message:
                    type: string
                  reason:
                    type: string
                    enum:
                      - queued
                      - timeout
                      - unavailable
                      - rate_limited
                      - no_preview
                      - not_ingested
                    description: >-
                      `queued` — accepted. The answer is not ready yet.

                      `timeout` — the answer did not arrive in time. Ask again.

                      `unavailable` — no answer can be produced right now.

                      `rate_limited` — the request was not accepted. Ask again
                      later.

                      `no_preview` — no wallet can be attested for this user.
                      Retrying rarely helps.

                      `not_ingested` — the record is not readable yet. Ask again
                      shortly.
                  retryable:
                    type: boolean
                    description: >-
                      False for `no_preview`, where a prompt retry is wasted
                      effort, and for `unavailable` while live resolution is
                      paused.
                  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'
      security:
        - b2bApiKey: []
components:
  schemas:
    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
                - OVERLOADED
                - QUOTA_EXCEEDED
                - RATE_LIMITED
                - REVEAL_LIMIT_REACHED
                - SAMPLE_SET_ONLY
                - TIMEOUT
                - UNAUTHORIZED
                - VALIDATION_ERROR
                - WEBSOCKET_PLAN_REQUIRED
            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
  securitySchemes:
    b2bApiKey:
      type: http
      scheme: bearer
      description: >-
        B2B API key (`fsk_live_…` / `fsk_test_…`), issued by FomoScan. Also
        accepted via `X-Api-Key`.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.