vike

TWAP orders

The status changes of Hyperliquid TWAP orders across all wallets, newest first: activated, waiting for a trigger, finished, terminated, stopped or rejected, with the amount executed so far on each row.

GET https://data.vike.io/v1/hyperliquid/twaps

The status changes of Hyperliquid TWAP orders, for every wallet at once. A TWAP is one order the venue works off in slices over duration_minutes; this feed has one row each time that order changes state, not one row per slice. Newest first by default, and order=asc follows the feed forward. For one wallet use /wallets/{address}/twaps.

cURL
# the newest TWAP status changes across all wallets (last 24 hours, rejected placements left out)
curl -s "https://data.vike.io/v1/hyperliquid/twaps?limit=3" \
  -H "X-API-KEY: $VIKE_API_KEY"

# next page of the call just above: NEXT is its nextCursor, passed back verbatim
curl -s "https://data.vike.io/v1/hyperliquid/twaps?limit=3&cursor=$NEXT" \
  -H "X-API-KEY: $VIKE_API_KEY"

# one TWAP from placement to its end, oldest first
curl -s "https://data.vike.io/v1/hyperliquid/twaps?twap_id=2420636&order=asc" \
  -H "X-API-KEY: $VIKE_API_KEY"

# TWAPs that ran to the end on one market
curl -s "https://data.vike.io/v1/hyperliquid/twaps?symbol=WLD&status=finished&limit=100" \
  -H "X-API-KEY: $VIKE_API_KEY"

# placements the venue rejected (left out unless asked for)
curl -s "https://data.vike.io/v1/hyperliquid/twaps?status=error&limit=100" \
  -H "X-API-KEY: $VIKE_API_KEY"

# follow the feed: everything since a moment, oldest first
curl -s "https://data.vike.io/v1/hyperliquid/twaps?order=asc&start=2026-10-27T12:00:00Z&limit=500" \
  -H "X-API-KEY: $VIKE_API_KEY"
walletqueryoptional
One wallet, 0x plus 40 hex, any case
twap_idqueryoptional
One TWAP id: every status line of that TWAP
symbolqueryoptional
HL ticker, e.g. BTC or xyz:AAPL
statusqueryoptional
One of activated, waitingForTrigger, finished, terminated, stopped, error. Default: every status except error, a rejected placement rather than an order; status=error shows those rows
startqueryoptional
ISO-8601 UTC. Default: the 24 hours before end (before now when end is empty), unless wallet or twap_id is given. Resuming an order=asc cursor starts from the cursor instead; a desc cursor keeps the 24-hour floor
endqueryoptional
ISO-8601 UTC. Default: now. A window wider than 31 days is a 400 unless wallet or twap_id is given
orderqueryoptional
asc | desc. Default desc, newest first. order=asc returns the oldest events first and is the mode for following a feed: pass each nextCursor back verbatim. It orders by key, so a row the writer inserts late with an older key is not seen by a poller already past it: re-read a small overlap. An asc page with rows always carries a cursor; an empty one returns the cursor you sent, or on a first call with no start or wallet or twap_id, a cursor at the lower bound of the default window (null when one of them already pins the place). So stop on an empty page, not on a null cursor. A desc page that comes back short carries no cursor. Anything else is a 400
limitqueryoptional
Default 100, max 5000
cursorqueryoptional
nextCursor from the previous page, verbatim. It pins the call that returned it: the feed, order, every filter and the start and end you sent. Changing or dropping any of them, start included, is a 400. Without wallet or twap_id, an asc cursor more than 31 days before end (before now when end is empty) is a 400 too: restart with start. /twaps?wallet= and the per-wallet TWAP route are one feed: with the same parameters their cursors are interchangeable
Example response
{
  "items": [
    {
      "ts": "2026-10-27T12:28:26.259687+00:00",
      "twap_id": 2420789,
      "wallet": "0xfd4f218b62f35eb5140d43e9e37ec6e1557ad852",
      "symbol": "DOGE",
      "side": "sell",
      "status": "activated",
      "size": 2000.0,
      "executed_size": 0.0,
      "executed_notional_usd": 0.0,
      "duration_minutes": 5,
      "reduce_only": false,
      "randomize": false,
      "placed_at": "2026-10-27T12:28:26.259000+00:00",
      "trigger_px": null,
      "trigger_above": null,
      "stop_px": null,
      "error": null
    },
    {
      "ts": "2026-10-27T12:28:22.866363+00:00",
      "twap_id": 2420788,
      "wallet": "0x20a608d30b77773936a3ab3529d339b61dd7cd3d",
      "symbol": "ENA",
      "side": "buy",
      "status": "activated",
      "size": 500.0,
      "executed_size": 0.0,
      "executed_notional_usd": 0.0,
      "duration_minutes": 10,
      "reduce_only": false,
      "randomize": false,
      "placed_at": "2026-10-27T12:28:22.866000+00:00",
      "trigger_px": null,
      "trigger_above": null,
      "stop_px": null,
      "error": null
    },
    {
      "ts": "2026-10-27T12:28:22.110279+00:00",
      "twap_id": 2420787,
      "wallet": "0xb68336848cca3fb5feb9a29432215abb02308b92",
      "symbol": "HYPE",
      "side": "buy",
      "status": "activated",
      "size": 200.0,
      "executed_size": 0.0,
      "executed_notional_usd": 0.0,
      "duration_minutes": 5,
      "reduce_only": false,
      "randomize": false,
      "placed_at": "2026-10-27T12:28:22.110000+00:00",
      "trigger_px": null,
      "trigger_above": null,
      "stop_px": null,
      "error": null
    }
  ],
  "nextCursor": "<opaque cursor>"
}

What a row is. status is activated when a TWAP starts and waitingForTrigger when it has a trigger price (trigger_px, trigger_above) that the market has not reached yet. A TWAP ends with finished, terminated or stopped, which are the venue's own words for how it ended; stop_px is the TWAP's stop price when it has one. A row with status error is a placement the venue refused, and the error field carries its reason; the field is null on every other row, as are the three trigger and stop fields when the TWAP has none. Those three fields did not exist before August 2026: on every row older than that they are null, whether or not the TWAP had a trigger or a stop. executed_size and executed_notional_usd are running totals at that row: an activated row reads 0 and the closing row carries the total, so executed_notional_usd / executed_size is the average execution price. Count TWAPs by twap_id, not by rows: a TWAP that started and ended inside the window has two or more (a TWAP with a trigger price has a waitingForTrigger row first).

Units. size and executed_size are in the market's own units (coins), executed_notional_usd in USD. placed_at is when the TWAP was placed and ts when this status was recorded, both UTC with microsecond precision on ts. side is buy or sell. symbol is the market's ticker (BTC), with the dex prefix for a builder-dex market (xyz:CL). A spot TWAP carries the raw spot index (@182), as /ohlcv/latest does for spot, and the symbol filter takes the same index: a token name such as HYPE selects the perp of that name, not the spot pair.

Choose the window. Without wallet or twap_id, a call with no start covers the 24 hours before end (before now by default). That floor slides with the clock, and a newest-first cursor without start stops at it, so pass start to read further back. A window of more than 31 days is a 400: from start to end (or now), from an order=asc cursor to end (or now), or from start to a newest-first cursor. An order=asc cursor replaces start as the window's lower edge (keep sending the same start and end: they are pinned in the cursor), so one more than 31 days old is a 400 too: restart with start (ISO 8601, UTC) and read a longer span in slices. Naming a wallet or a twap_id removes all of these rules and reads back through all history, which starts on 2026-04-05 and holds every status line since then: about 1.4 million rows on 2026-10-27, with all six statuses. limit takes 1 to 5000 and defaults to 100; a value above 5000 is a 422. An unknown status or order is a 400 that lists the accepted values. A call costs 1 credit (Rate limits).

Page and follow. Newest first is the default, and nextCursor is null once a page holds fewer rows than limit. With order=asc the feed runs oldest first from start (or from your cursor), which is how to follow it: keep the last nextCursor and send it back with the same filters. In this mode nextCursor is never null once you hold a cursor, so stop a walk at the first empty page, not at a null; an empty page returns the cursor you sent, so a poller keeps its place. An empty first page with no start and no wallet or twap_id returns a cursor at the lower edge of the 24-hour window, and with a start, a wallet or a twap_id it returns null: poll again with the same parameters. A poller that moves forward by cursor never sees a row added late with an older key, nor one that lands in the same microsecond as its cursor row but sorts before it: if you must not miss one, re-read a small overlap with start and drop what you already hold, by ts, twap_id and status. Following a feed has the rules, and Freshness says how far behind the venue a row arrives.

A TWAP line is a status change, not a fill

A row says a TWAP changed state, and its amounts are running totals. There is no row for each slice and no row when a slice executes, so a TWAP in progress shows only its activated row until it ends. The slices are ordinary fills of the wallet; they carry no TWAP id in this API, so they cannot be listed per TWAP.

Rejected placements are hidden by default

Without status, rows with status=error are left out. On 2026-10-26 about a third of all TWAP lines were rejections, almost all from one wallet retrying an order its margin could not cover. An error row is a placement the venue refused, not a TWAP that ran. Pass status=error to read them; any other status returns only that status.

Example response
{  "items": [    {      "ts": "2026-10-27T12:28:26.259687+00:00",      "twap_id": 2420789,      "wallet": "0xfd4f218b62f35eb5140d43e9e37ec6e1557ad852",      "symbol": "DOGE",      "side": "sell",      "status": "activated",      "size": 2000.0,      "executed_size": 0.0,      "executed_notional_usd": 0.0,      "duration_minutes": 5,      "reduce_only": false,      "randomize": false,      "placed_at": "2026-10-27T12:28:26.259000+00:00",      "trigger_px": null,      "trigger_above": null,      "stop_px": null,      "error": null    },    {      "ts": "2026-10-27T12:28:22.866363+00:00",      "twap_id": 2420788,      "wallet": "0x20a608d30b77773936a3ab3529d339b61dd7cd3d",      "symbol": "ENA",      "side": "buy",      "status": "activated",      "size": 500.0,      "executed_size": 0.0,      "executed_notional_usd": 0.0,      "duration_minutes": 10,      "reduce_only": false,      "randomize": false,      "placed_at": "2026-10-27T12:28:22.866000+00:00",      "trigger_px": null,      "trigger_above": null,      "stop_px": null,      "error": null    },    {      "ts": "2026-10-27T12:28:22.110279+00:00",      "twap_id": 2420787,      "wallet": "0xb68336848cca3fb5feb9a29432215abb02308b92",      "symbol": "HYPE",      "side": "buy",      "status": "activated",      "size": 200.0,      "executed_size": 0.0,      "executed_notional_usd": 0.0,      "duration_minutes": 5,      "reduce_only": false,      "randomize": false,      "placed_at": "2026-10-27T12:28:22.110000+00:00",      "trigger_px": null,      "trigger_above": null,      "stop_px": null,      "error": null    }  ],  "nextCursor": "<opaque cursor>"}