vike

API reference

Every endpoint of the Vike Data API, grouped by namespace, with the base URL, the WebSocket that no OpenAPI document describes, and the conventions every namespace page assumes.

The Vike Data API is the 106 operations of its OpenAPI document, plus the archive's files, the schema views and four WebSockets, grouped into namespaces. This page carries the rules that hold across all of them — where they live, how you authenticate, how they are metered, how they page — and then hands off. It lists no endpoints itself; each namespace page does that, and each endpoint has a page of its own.

The base URL

https://data.vike.io

That is what the live OpenAPI document's own servers array declares, and it is the only host that answers the /v1 namespaces. The same /v1 path under https://vike.io returns 404 — measured, not inferred.

The WebSockets are not OpenAPI operations, and they have their own host

The event streams are on a different host, wss://stream.vike.io/v1/stream/hl (and /hl-cohorts, /onchain and /polymarket on the same host). They are not in the OpenAPI document, so no generated client carries them; they take the same credential and spend no hourly counter, unlike everything else under /v1; see Event streams close codes, errors and resuming and Event stream channels and filters. Closed Hyperliquid candles are the channel hl.candles there. The old addresses on data.vike.io, wss://data.vike.io/v1/stream/hl and the candle stream wss://data.vike.io/v1/stream (moved), answer HTTP 410.

Authentication

Every endpoint on this reference is credential-gated. There is no keyless tier and no query-string form on REST — the credential travels in a header. The WebSockets also accept ?token=, for browsers, which cannot set headers on one (see Authenticating the handshake).

cURL
curl -H "X-API-Key: $VIKE_API_KEY" \
  "https://data.vike.io/v1/onchain/tokens/search?q=USDC&limit=3"

Two credential types are accepted, and either alone is enough:

  • API key — X-API-KEY: vk_.... Header names are case-insensitive, so X-API-Key and X-API-KEY are the same header.
  • OAuth 2.1 bearer — Authorization: Bearer vk_oat_....

One implementation validates both credentials on every surface. It tries the bearer first and falls through to the API-key header if the bearer is invalid, so a request may carry either or both. Both reach the same account.

The exception to "credential-gated" is two archive paths served outside the gate — /archive/manifest.json and /archive/samples/. Those are on Archive. The Hyperliquid archive has its own open folder, /archive/hl-samples/: Free samples. A Hyperliquid download link (Cloudflare R2, valid 7 days) takes no key either: the link is the credential, and the key goes on the /archive/url call that issues it. The OpenAPI document has a keyless copy too, off this host: Schema and spec.

Key creation, the OAuth discovery document, and the caching window that makes revocation take a few seconds: Authentication.

Metering

One hourly counter per credential, shared by every metered surface. MCP calls and REST calls draw from the same budget — the usage labels separate your analytics, not your allowance. There is one value, and it is stated once, on Rate limits, rather than copied here where it would rot.

Two properties worth carrying before you get there:

  • Archive downloads are authenticated and recorded but do not spend the budget (since 2026-09-02). Every other endpoint on this reference costs one unit per HTTP request.
  • The counter is per key, not per account. A second API key is a legitimate way to keep a bulk job from starving an interactive client. OAuth works the other way round: every OAuth token you own shares one pooled counter.

Errors

Branch on the status code, not the body. Every /v1 route maps errors the same way, and that mapping is fixed: caller input the API rejected is a 400, an upstream failure is a 503 — deliberately never a 200 with an empty body, because a silent empty list is indistinguishable from "no data".

The full table of status codes, the JSON envelope, and how /mcp reports a failure: Errors.

A parameter out of range is a 422, not a 400

Parameter bounds are declared on the route itself — a limit ceiling and its siblings — so on onchain, hyperliquid and hl-cohorts an out-of-range or malformed parameter is a 422 from validation before the query runs, not the 400 an engine rejection produces. Its body keeps the framework's detail list and adds one readable error line per failing parameter: 422. Polymarket reads its parameters as text and never answers 422. The two validation types are also why the published spec's components.schemas holds HTTPValidationError and ValidationError.

Pagination

⚠ There is no single convention. The difference is not cosmetic — a client written against one will silently truncate against another. Verified endpoint by endpoint:

SurfacePaginationField to pass back
/v1/onchain/*none — limit only, one page—
/v1/hyperliquid/* — 29 of its 47 routeskeyset cursornextCursor
/v1/hl-cohorts/* — 3 of its 11 routeskeyset cursornextCursor
/v1/polymarket/events, /v1/polymarket/settlements/bulkcursor in an envelope {…, has_more, next_cursor}next_cursor, while has_more is true
/v1/polymarket/archive/datasets, /v1/polymarket/leaderboardoffset—

Hyperliquid pages by keyset, not offset, for two reasons: the tables behind it hold billions of rows, so OFFSET n re-reads and discards every skipped row, and a concurrent insert shifts rows across page boundaries. The cursor is a base64url-encoded JSON object — opaque; pass it back verbatim. Do not parse it, and do not construct one.

onchain does not paginate at all. The namespace declares a cursor on no route. Its routes take a limit with a per-route ceiling and return one page. If you need more than the ceiling, narrow the window — there is no second page to ask for.

Two cursor spellings share the base URL. Hyperliquid and HL Cohorts pass back nextCursor; Polymarket's /events and /settlements/bulk answer with an envelope whose next_cursor is a string only while has_more is true, and null otherwise. The two are not interchangeable, and a client that assumes one field name silently stops after the first page against the other. Page through large reads walks each kind.

Two nextCursor traps

A cursor is bound to the query that produced it. It carries that query's own mode and filters, and handing one to a different endpoint — or reusing it after changing start/end — is refused with a 400, not silently honoured. The message says which: nextCursor belongs to a different endpoint, or — when start/end moved — nextCursor belongs to a different query mode, telling you to restart pagination without a cursor. Change a filter, restart paging. The four Hyperliquid event feeds (Following a feed) give the same 400 in a third wording, nextCursor was issued for different query parameters, and also pin order and every filter in the cursor.

A non-null cursor does not mean there is more data. The cursor is emitted whenever the page came back full — exactly limit rows — so a result set that divides evenly by your limit hands you a final cursor whose next fetch returns nothing. Stop when the cursor is null or the page is empty — not on the cursor alone.

The namespaces

NamespaceEndpointsWhat it covers
onchain21Wallets, tracing, PnL and balances; token search, screening, holders and transfers; labels. Carries the only non-GET route of the four data namespaces.
hyperliquid47Per-wallet Hyperliquid perp analytics — wallets, builders, positions and open interest, standing orders, liquidations, HL candles, and the Parquet file archive (an index and a temporary download link).
hl-cohorts11Cohort positioning on Hyperliquid — the cohort ladders and segments, the coin by cohort heatmap, and per-coin series: metrics, cohort metrics, size breakdown, indices and large fills. The same paths under /v1/hyperliquid still answer.
polymarket16Prediction-market directory, per-outcome probability candles, order books, event tape, settlements one at a time or in bulk, archive discovery, and three trader routes (a wallet's profile, smart-money signals, the wallet leaderboard).
search1One route shared by the four namespaces: the vike.io search box, a name, symbol, address, ENS name or pasted link in, every product's matches out.
archive3The Polymarket bulk Parquet archive — the manifest, the free daily samples, and the gated store. Two of the three need no credential.
schema3The live OpenAPI document, Swagger UI and ReDoc. All three under /v1; the bare paths 404 by design.
event streams4Credential-gated WebSockets on their own host, stream.vike.io: /v1/stream/hl (Hyperliquid, closed candles included), /hl-cohorts, /onchain and /polymarket. They push events with a cursor to resume from, invisible to the spec: OpenAPI has no WebSocket operation to emit. The channels and filters are listed on their own page.
alerts10Your own alert rules, notification channels and webhook secrets, the events your rules produced (the feed and the webhook body) and "send again": the REST face of the alert MCP tools. They read and write the account the key belongs to, not one of the four data products.

The first four rows and search and alerts are the routes the API declares, rendered from its own OpenAPI document at build time. archive is the three archive paths; schema is the OpenAPI document plus its two rendered views; event streams are the four at wss://stream.vike.io/v1/stream/.... schema is a documentation bucket rather than a URL prefix: there is no /v1/schema/. The event streams share only the path prefix with data.vike.io: they are on a different host, and on data.vike.io the old /v1/stream/hl and the closed candle stream /v1/stream (moved to hl.candles) answer 410. Those pages group surfaces that exist; they do not name a path segment.

What this reference can and cannot do

You cannot generate a full client from the published spec

GET https://data.vike.io/v1/openapi.json is real and current, but it will not carry a code generator, for two reasons that compound:

  • It leaves out the archive, the schema views and the WebSockets. It is the framework's own document for the application that serves the /v1 routes on this reference, and it sees nothing else here — not the WebSockets, which OpenAPI has no operation to describe, and not the file-served archive.
  • It declares no response schemas. No /v1 route declares a response model, so every 200 in the document is an undeclared {}. components.schemas holds exactly two entries, and both are error types.

The spec describes parameters well and payloads not at all. Where an endpoint page states a response field, it was read from the code and a real response, and the page prints the captured example it was read from where one exists.

Reading the spec needs no key. /v1/openapi.json is behind the key gate like every /v1 path, but the same document is published keyless at https://vike.io/data/openapi.json, and every /v1 response names it in a Link header with rel="service-desc". Schema and spec says how the two copies relate.

So the reference is one page per endpoint, under one index page per namespace. Each endpoint page's request line and parameter list are rendered from the spec at build time; what the endpoint returns, when you would call it, the example and the traps are written by hand.

On this page