Events
The events resource is the durable, queryable history of everything that has happened on your ThrustLab account that could trigger a webhook. Events fire even when no webhook endpoint is subscribed; webhooks are forward-looking; events are pull-anytime.
If you missed a webhook delivery window (downtime, misconfigured endpoint, late integration), pull from /v1/events directly. The shape of the event objects returned here is identical to the body of webhook deliveries.
Resource
GET /v1/events — list events for the authenticated principal, newest first, cursor-paginated.
GET /v1/events/{id} — retrieve a single event by evt_<ksuid> ID.
Each event has the form:
{
"id": "evt_2lz...",
"object": "event",
"type": "simulation.completed",
"created_at": "2026-04-25T18:42:11Z",
"api_version": "beta",
"data": { "object": { ... resource-specific payload ... } }
}
The same canonical bytes (sorted keys, no whitespace) used here are what gets HMAC-signed for webhook delivery — see webhooks for verification details.
Filters
GET /v1/events accepts the following query parameters:
| Parameter | Type | Description |
|---|---|---|
type | string | Exact match on event type (e.g. simulation.completed). |
resource_id | string | Exact match on the prefixed resource ID the event refers to (e.g. sim_2lz..., swp_2lz...). |
created_at[gte] | ISO-8601 | Inclusive lower bound on created_at. |
created_at[lt] | ISO-8601 | Exclusive upper bound on created_at. |
limit | int (1–100) | Page size. Default 25. |
cursor | string | Opaque pagination cursor from a prior response's next_cursor. |
Examples
All simulation.completed events:
curl "https://thrustlab.com/v1/events?type=simulation.completed" \
-H "Authorization: Bearer key_..."
All events for one resource:
curl "https://thrustlab.com/v1/events?resource_id=sim_2lz..." \
-H "Authorization: Bearer key_..."
Events from a 24-hour window:
curl "https://thrustlab.com/v1/events?created_at[gte]=2026-04-24T00:00:00Z&created_at[lt]=2026-04-25T00:00:00Z" \
-H "Authorization: Bearer key_..."
Combine filters freely — they AND together. Pagination cursors encode the last seen (created_at, id) and remain valid as long as the underlying events have not been pruned by retention.
Retention
Events are retained for 30 days and then deleted by a daily background sweep. Events outside the retention window are not recoverable.
If you need durable beyond 30 days, ingest events into your own storage — either by subscribing a webhook endpoint and persisting deliveries, or by polling /v1/events periodically and checkpointing on the latest id you've seen.
Retention only deletes events that have already been processed by the webhook fan-out pass (or were never eligible for fan-out). In practice this means everything older than 30 days is fair game.
Relationship to webhooks
Events and webhooks are independent surfaces over the same data:
- Events fire even with zero subscribers. Every meaningful state change writes a row to
eventsregardless of whether any webhook endpoint exists. Registering an endpoint later does not retroactively deliver past events — webhook subscriptions are forward-looking. - Webhooks are push, events are pull. Webhooks deliver in real time with backoff retries and at-least-once semantics. The events resource is queryable on demand with
created_atfiltering and cursor pagination. - Same payload shape. The
data.objectbody in an event is byte-identical to what gets signed and POSTed for the corresponding webhook delivery (same canonical JSON: sorted keys, compact separators).
Use webhooks for low-latency reaction to state changes. Use the events resource for replay, backfill, and any case where polling is acceptable. Combining the two — webhooks for real-time, events for gap-recovery — is a robust pattern.