API reference
List events
GET/v1/events
What happened to the runs in the key’s projects, oldest first: the same events webhooks send, for a system that would rather poll.
curl --fail-with-body -sS "https://<workspace>.nightlab.io/v1/events?after=$CURSOR" \
-H "Authorization: Bearer $NIGHTLAB_API_KEY"
const res = await fetch(
`https://<workspace>.nightlab.io/v1/events?after=${cursor}`,
{
headers: {
Authorization: `Bearer ${process.env.NIGHTLAB_API_KEY}`,
},
},
);
if (!res.ok) throw new Error(await res.text());
const { events, next_cursor } = await res.json();
import os, requests
answer = requests.get(
"https://<workspace>.nightlab.io/v1/events",
params={"after": cursor},
headers={"Authorization": f"Bearer {os.environ['NIGHTLAB_API_KEY']}"},
timeout=30,
)
answer.raise_for_status()
Query
afterstringThe
next_cursorof your last answer. Without it, from the oldest event kept: 30 days back.limitinteger, 1 to 100, default 50How many in one answer.
The answer
200 with events, each an event as a webhook carries it, and next_cursor. Its timestamp is ISO 8601 in UTC with microseconds, written here with Z where a webhook writes +00:00: parse it rather than comparing it as text. Keep the cursor and pass it as after next time. When nothing new has happened, events is empty and the cursor is the one you sent, so poll with it again.
200 OK
{
"events": [
{
"id": "evt_6f1c2b9a04d84e7f9a3e5b7c1d2f8e90",
"type": "run.pr_opened",
"timestamp": "2026-11-01T10:24:00.743059Z",
"data": {
"run": {
"id": "run-42",
"project": "shop",
"issue": "SHOP-1431",
"action": "build",
"state": "running",
"outcome": null,
"no_pr_reason": null,
"pr_url": "https://github.com/acme/shop/pull/322",
"pr_state": "draft",
"external_ref": "ci-8812"
}
}
}
],
"next_cursor": "1842"
}
Refusals
422 for a cursor this API didn’t give, and 403 for a key without events:read.