Read your app's event journal
OpenAPI JSONimport os, requests, time
cursor, since = None, "2026-09-10T00:00:00Z"while True: params = {"cursor": cursor} if cursor else {"since": since, "types": "app_user.*,extension.*", "limit": 100} r = requests.get( "https://api.eu.apigami.com/events", headers={"Authorization": f"Bearer {os.environ['APIGAMI_API_KEY']}"}, params=params, ).json() for event in r["events"]: handle(event) # by event["id"], skipping the ones already seen cursor = r["next"] or cursor if not r["events"]: time.sleep(30)The journal of everything that changed for your app’s users: a user connected or disconnected, their approvals changed, a browser was attached to or detached from them, came online or went offline. Events are kept 30 days, ascending by (created_at, id). Only your app’s own events come back — the key names the app, and there is no parameter to name another one. Use it to catch up after your own deploy, to reconcile a state you doubt, or instead of a webhook endpoint if your service has no public URL. API keys only: a dashboard session, a personal access token or an OAuth token is refused with 401.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Query Parameters
Section titled “Query Parameters”An ISO 8601 timestamp. Events strictly after it. Default: 30 days ago. Ignored when cursor is given.
Example
2026-09-10T00:00:00ZThe next of a previous answer: an opaque encoding of (created_at, id). It needs no row to still exist, so a cursor kept across the 30-day purge keeps working. Wins over since.
Comma-separated list of types or <namespace>.* patterns. An unknown type matches nothing. Omitted: every type.
Example
app_user.*,extension.offlineHow many events at most. Default 100, clamped to 1000.
Responses
Section titled “Responses”A page of events, oldest first. next is the cursor of the following page, or null when there is nothing more right now.
object
One thing that happened, as your app sees it. The same body is posted to your webhook endpoints. An app_user event carries the user’s whole set of approvals, not the change alone, so a consumer replaces its copy instead of diffing.
object
Unique to your app. Two apps never share an id, and it is the idempotency key of a delivery.
One of the types of GET /events/catalogue.
The ordering key, for every type. Compare it, never arrival order.
Your app.
The user the event is about, as POST /connect/token returned it. Null on an event about no user.
The browser the event is about. Null on an event about the user as a whole, or about no browser.
Depends on the type — see GET /events/catalogue.
object
Pass it back as cursor. Keep it: it survives the purge.
Example
{ "events": [ { "id": "6f1c2d3e-4a5b-4c6d-8e9f-0a1b2c3d4e5f", "type": "app_user.updated", "created_at": "2026-09-10T10:12:31.128Z", "app_id": "2b7f6a41-0c9d-4a3e-9f21-8d5c4b3a2109", "user_ref": "usr_3f9c1a0e7b2d4c58a61e9f0b2d7c4e13", "install_ref": null, "data": { "connected_at": "2026-09-01T08:00:00.000Z", "grants": [ { "domain": "acme.com", "granted": false, "decided_at": "2026-09-10T10:12:31.128Z" }, { "domain": "example.com", "granted": true, "decided_at": "2026-09-02T09:30:00.000Z" } ], "change": { "domain": "acme.com", "decision": "denied", "was_granted": true } } } ], "next": "MjAyNi0wOS0xMFQxMDoxMjozMS4xMjhaLzZmMWM"}A query parameter could not be read.
object
Present and true when the approval window is open and the user has not answered within 45 s.
Examples
{ "error": "since must be an ISO timestamp"}{ "error": "bad cursor"}{ "error": "limit must be a number"}Missing, malformed or revoked API key — or a credential that is not one: a dashboard session, a personal access token and an OAuth token are refused here, like on /call.
object
Present and true when the approval window is open and the user has not answered within 45 s.
Example
{ "error": "bad client credentials"}