Events
Everything that happens to an order is emitted as an event: pushed to your notify_url or queue as a webhook, and replayable on demand. One envelope, both directions.
The event envelope
Every event shares this envelope, whichever direction it travels and however it is delivered. The canonical object reference is the order event.
| Field | Type | Description |
|---|---|---|
event_type required | string | What happened. See event types. |
order_id required | string | Platform order id. |
external_order_id required | string | The buyer's idempotency key, echoed on every event for the order. |
seq required | integer | Per-order sequence number, strictly increasing. Retries reuse the same value. |
status required | enum | Order status after the transition. See order status. |
substatus | string | Finer-grained progress marker; null unless the status carries one. |
units[] | array of object | Per-unit results; present on terminal events and partial results. Each entry carries unit_id, status (see unit status), num_requested, num_accepted, and reason. |
artifact | object | Attached payload when the transition produced one: parsed_io, validation_result, plan_proposal, placement_receipt, or delivery_post. |
error | object | Structured error on failed and rejected events; null otherwise. See Errors. |
occurred_at required | ISO datetime | When the transition happened. UTC, like every timestamp on the platform. |
{
"event_type": "order.status_changed",
"order_id": "ord_9f3a12c4b7e1",
"external_order_id": "q4-campaign-042",
"seq": 5,
"status": "placed",
"substatus": null,
"units": [
{
"unit_id": "u-0001",
"status": "accepted",
"num_requested": 10,
"num_accepted": 10,
"reason": null
}
],
"artifact": {
"name": "placement_receipt",
"seller_order_id": "ACME-77120",
"daylocks": [
{
"unit_id": "u-0001",
"date": "2026-10-05",
"units": 4
},
{
"unit_id": "u-0001",
"date": "2026-10-07",
"units": 3
},
{
"unit_id": "u-0001",
"date": "2026-10-09",
"units": 3
},
{
"unit_id": "u-0002",
"date": "2026-10-14",
"units": 10
}
],
"placed_at": "2026-10-02T14:41:09Z"
},
"error": null,
"occurred_at": "2026-10-02T14:41:09Z"
}
seq is per-order and strictly increasing, and retries reuse the same seq: dedup on (order_id, seq). Events are hints, not truth. If deliveries are missed, recovery is the order snapshot plus replay, never guesswork.Webhook deliveries are signed (X-Signature) and numbered (X-Delivery-Attempt); see verifying the signature.
Event types
Buyers receive order lifecycle events; sellers receive review, cancellation, negotiation, and catalog-integrity events. Same envelope, same rules.
| Event type | Sent to | When |
|---|---|---|
order.status_changed | Buyer | Every status transition on your orders; seller counters surface here as negotiating with countered units |
catalog.stale_rate_card | Buyer | A rate card update changed lines on your in-flight orders |
catalog.window_opened | Buyer (subscribed) | A discounted near-air window opened (remnant or opportunistic) with a signal payload |
avails.answered | Buyer | An on-request avails answer landed; carries the avails_request_id to correlate with the poll resource. Body also reports declined or expired |
order.needs_review | Seller | An order entered your seller_review queue, including a proposal order awaiting a plan |
order.canceled | Seller | The buyer canceled an order you had not yet approved |
negotiation.offer | Seller | The buyer responded in a negotiation round; your turn to respond |
catalog.integrity_failed | Seller | A catalog or rate-card update was rejected; conflict report attached |
settlement.invoice_issued | Buyer + Seller | An invoice was generated on a cleared trade |
GET /v1/events: replay
GET/v1/eventsorders:write
Replay an order's event history: the recovery path when webhook deliveries are missed. The order snapshot carries last_seq; replay everything after your high-water mark and the loop is closed.
Query parameters
| Field | Type | Description |
|---|---|---|
order required | string | The order_id to replay events for. |
after_seq | integer | Return events with seq greater than this value; 0 replays the full history. Default: 0. |
Response
Events in seq order, each carrying the envelope minus the order identifiers, plus the order's current last_seq so you know when you are caught up.
200 Response
{
"order_id": "ord_9f3a12c4b7e1",
"events": [
{
"event_type": "order.status_changed",
"seq": 1,
"status": "submitted",
"substatus": null,
"artifact": null,
"error": null,
"occurred_at": "2026-10-01T14:02:11Z"
},
{
"event_type": "order.status_changed",
"seq": 5,
"status": "placed",
"substatus": null,
"artifact": {
"name": "placement_receipt",
"seller_order_id": "ACME-77120",
"daylocks": [
{
"unit_id": "u-0001",
"date": "2026-10-05",
"units": 4
},
{
"unit_id": "u-0001",
"date": "2026-10-07",
"units": 3
},
{
"unit_id": "u-0001",
"date": "2026-10-09",
"units": 3
},
{
"unit_id": "u-0002",
"date": "2026-10-14",
"units": 10
}
],
"placed_at": "2026-10-02T14:41:09Z"
},
"error": null,
"occurred_at": "2026-10-02T14:41:09Z"
}
],
"last_seq": 5
}
Errors
| Status | Code | When |
|---|---|---|
| 404 | NOT_FOUND | order does not exist within your scope. |
| 422 | INVALID_INPUT | order is missing, or after_seq is not a non-negative integer. |