Get Trade Events
GET /api/v1/trades/{tradeID}/eventsScope: 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
| Event | Recorded when |
|---|---|
maker_fill | A maker order filled (partial or full) |
hedge_sent | The 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_filled | The 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_outcome | Final outcome of a hedge attempt (including retries/rejections) |
hedge_timeout | A 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_completed | chunk_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_completed | A replacement worker finished reconciling after a crash/restart |
hl_action_budget_exhausted | A 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_hold | Hyperliquid 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_applied | An 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_correction | What 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:
| Field | Type | Meaning |
|---|---|---|
action | string | hedge, flatten, complete_maker, reduce_hedge, reconcile, or skipped — see the table below |
fallback_from | string, optional | Present 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 |
exchange | string, optional | Venue the corrective order went to |
market | string | Trade market |
side, size, price | strings, optional | The corrective order (decimal strings) |
order_id, client_order_id | strings, optional | The corrective order's ids |
placed | boolean | Whether the corrective order was actually placed. false with action other than skipped means the corrective failed and exposure remains |
reason | string, optional | Why this corrective was chosen, or the venue error when it failed |
maker_exposure, hedged, residual | strings, optional | Maker filled minus already flattened, hedged size, and the residual the corrective addressed, at the decision |
timestamp_ms | integer | Unix milliseconds |
action | When | Legs afterwards |
|---|---|---|
hedge | on_cancel_fill: "hedge" and the hedge venue accepted a market order for the residual | balanced |
flatten | Default policy, or the fallback when the hedge could not be placed (fallback_from: "hedge") | balanced if placed: true; exposure remains if placed: false |
complete_maker | The hedge leg was ahead of the maker (pre-hedged remainder); the maker leg was completed at market | balanced if placed: true |
reduce_hedge | The hedge leg was ahead and reducible; a reduce-only order trimmed it | balanced |
reconcile | Both 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 itself | as the next record says |
skipped | on_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 placed | exposure 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}/eventsevents = 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', {})}")