API Reference
Trades
Get Events

Get Trade Events

GET /api/v1/trades/{tradeID}/events

Scope: trades:read

Returns the trade's durable execution log — the authoritative record of every fill and hedge. This is the write-ahead log the engine itself uses, exposed read-only.

Response

200 OK

{
  "trade_id": "00000000-0000-0000-0000-000000000000",
  "events": [
    {
      "sequence": 1,
      "event_type": "maker_fill",
      "data": {
        "exchange": "lighter",
        "market": "HYPE",
        "side": "buy",
        "price": "24.50",
        "size": "1.0",
        "order_id": "123456",
        "client_order_id": "abc-1",
        "fully_filled": false,
        "timestamp_ms": 1780000000000
      },
      "worker_id": "worker-123",
      "created_at": "2026-03-12T13:07:15Z"
    },
    {
      "sequence": 2,
      "event_type": "hedge_sent",
      "data": { "exchange": "extended", "side": "sell", "size": "1.0" },
      "worker_id": "worker-123",
      "created_at": "2026-03-12T13:07:15Z"
    }
  ]
}

Event types

EventRecorded when
maker_fillA maker order filled (partial or full)
hedge_sentThe corresponding hedge order was sent to the hedger exchange. data.send_outcome_unknown: true when the venue's answer to the send was lost, so the order may have executed: the worker tracks it and reads its outcome from the venue before re-sending anything. A negative data.size is a reduce-only order that trims an over-hedge when the trade completes; its fills are hedge_filled with a negative size, and the same flag applies
hedge_filledThe hedge order confirmed filled. data.from_venue_read: true when the fill never arrived on the venue's stream and the worker read the order back from the venue instead
hedge_outcomeFinal outcome of a hedge attempt (including retries/rejections)
hedge_timeoutA hedge failed to confirm within the expected window. data.venue_filled_size is what the venue reported the order executed, when the worker could read it back before retrying: only the remainder is re-sent. It is absent when the outcome is unknown. data.send_outcome_unknown: true marks the check of a send whose answer was lost, made after a 750 ms grace rather than the configured timeout
chunk_started / chunk_completedchunk_started: the worker started executing the trade. chunk_completed: the trade reached its target size; it is not written for a trade that fails or is canceled. The names are legacy, from when trades ran in chunks
recovery_completedA replacement worker finished reconciling after a crash/restart
hl_action_budget_exhaustedA Hyperliquid maker reached the trade's action cap and stopped re-pricing (Hyperliquid action cap). data.action is cancel_entry (an entry: its order is cancelled and the trade ends with failure_code: hl_action_budget_exhausted) or finish_close (a reduce_only close: its order is moved to data.finish_price, max_slippage through the maker venue's touch, and its fills are hedged as usual). data.budget and data.budget_source (request or notional) give the cap that applied; data.used, place, modify and cancel give what the trade's legs had sent
hl_address_budget_holdHyperliquid refused a maker re-price because the wallet's address budget is spent ("Too many cumulative requests"). The maker then holds its order (data.state: "held", with the refused data.client_order_id and Hyperliquid's data.used / data.cap). The held order stays on the book and can still fill, and the trade does not fail over it. Re-pricing resumes on the first address-budget reading that shows at least 100 requests left (data.state: "resumed", with data.remaining and data.held_ms). Readings are taken every 20 s, and only one taken after the hold began counts
amend_appliedAn amend changed the running trade — data.changes[] of { "field", "old", "new" } (numeric fields compared as decimals, so a re-sent equal value is not a change)
teardown_correctionWhat the cancel-time corrective did about a naked maker delta — see below

Lifecycle events live on the WebSocket, not here. Status transitions (trade.started, trade.completed, trade.failed, trade.canceled, trade.paused, trade.resumed) are pushed in real time over the WebSocket API — they are not part of this endpoint's execution log. To reconstruct status history after the fact, poll Get Trade.

teardown_correction

Recorded once per corrective when a cancel (or a tier expiry) meets a maker fill the hedge did not cover. data:

FieldTypeMeaning
actionstringhedge, flatten, complete_maker, reduce_hedge, reconcile, or skipped — see the table below
fallback_fromstring, optionalPresent when the recorded action was a fallback: "hedge" means on_cancel_fill: "hedge" could not place on the hedge venue and the residual was flattened on the maker venue instead
exchangestring, optionalVenue the corrective order went to
marketstringTrade market
side, size, pricestrings, optionalThe corrective order (decimal strings)
order_id, client_order_idstrings, optionalThe corrective order's ids
placedbooleanWhether the corrective order was actually placed. false with action other than skipped means the corrective failed and exposure remains
reasonstring, optionalWhy this corrective was chosen, or the venue error when it failed
maker_exposure, hedged, residualstrings, optionalMaker filled minus already flattened, hedged size, and the residual the corrective addressed, at the decision
timestamp_msintegerUnix milliseconds
actionWhenLegs afterwards
hedgeon_cancel_fill: "hedge" and the hedge venue accepted a market order for the residualbalanced
flattenDefault policy, or the fallback when the hedge could not be placed (fallback_from: "hedge")balanced if placed: true; exposure remains if placed: false
complete_makerThe hedge leg was ahead of the maker (pre-hedged remainder); the maker leg was completed at marketbalanced if placed: true
reduce_hedgeThe hedge leg was ahead and reducible; a reduce-only order trimmed itbalanced
reconcileBoth legs were read from the venues before correcting, and a hedge order of unknown outcome (an IOC that timed out unconfirmed, or an over-hedge reduction at completion) turned out to have executed, or not. hedged is what the hedge venue shows; the corrective that follows, if any, is sized from it. Nothing is placed by this record itselfas the next record says
skippedon_cancel_fill: "report", or a hedge order's outcome is unknown and the venues could not settle it (a position read failed, orders were still in flight, or a leg moved more than this trade's orders explain). For an over-hedge reduction at completion, the reason starts over-hedge correction stopped and the trade is left open. Nothing was placedexposure remains; verify positions manually

The trade's terminal failure_code summarises the same outcome — see Failure codes.

Event ordering

Events are append-only, ordered by sequence. Sequence numbers are unique within a trade and monotonically increasing. You can use sequence for incremental polling — query, note the highest sequence, query again later filtering for events with sequence > last seen.

Example

curl -H "X-API-Key: sprdr_..." \
  https://api.spreadr.xyz/api/v1/trades/{tradeID}/events
events = requests.get(f"{API_URL}/trades/{trade_id}/events", headers=headers).json()
for e in events["events"]:
    print(f"[seq {e['sequence']}] {e['event_type']} — {e.get('data', {})}")