View as Markdown

Stream Events

GET/v2/events

Open the realtime event stream of your workspace (text/event-stream): notifications, credit balance changes, subscription and integration changes. Authenticate with your API key in the x-api-key header; a credential in the query string (api_key, apiKey, jwtToken) is refused with 401 credential_in_query. Every message is one data: line holding a JSON EventFrame; there is no event: line, so dispatch on data.type, and ignore a type you do not know (the catalog only grows). Lines starting with : are heartbeat comments, every 25 seconds. retry comes in the first message only; id is for logs, and nothing is replayed: on every (re)connect the first event is stream.ready, after which re-read the state you show. The server ends the stream after 30 minutes; reconnect. Session events never reach an API key. At most 20 open streams per user (429 too_many_streams). Free: no credits. The first bytes of a stream:

retry: 5000
id: r7-1
data: {"type":"stream.ready","created_at":"2026-10-05T09:00:00.512Z","data":{"connection_id":"r7-1","heartbeat_seconds":25,"expires_at":"2026-10-05T09:30:00.512Z","scope":{"workspace_id":830159,"user_id":"64f1a2b3c4d5e6f7a8b9c0d1"}}}

: ping

id: r7-2
data: {"type":"credits.updated","created_at":"2026-10-05T09:00:00.512Z","data":{"credit_type":"email_search","available":48}}

id: r7-3
data: {"type":"notification.created","created_at":"2026-10-05T09:00:00.512Z","data":{"id":"6ac35b5ffe3fe40ea209b07e","workspace_id":830159,"type":"export","status":"done","title":"Export completed","body":"Your export of 1,250 people is ready.","body_format":"text","link":{"url":"https://files.example.com/exports/6ac35b5ffe3fe40ea209b07d/people-2026-10-05.csv","label":"Click here to download.","kind":"file","file_name":null},"subject_id":"6ac35b5ffe3fe40ea209b07d","read":false,"read_at":null,"created_at":"2026-10-05T08:10:07.385Z"}}

How are credits spent?

The stream is free and consumes no credits. It only tells you that something changed; read the details with the matching endpoint.

Event types

Every event is { "type", "created_at", "data" }. Dispatch on type and ignore any type you do not recognize: new types are added over time, and existing types and fields are never removed.

  • stream.ready - the first event of every connection. Re-read the state you display (credit balances, notifications) after it: events sent while you were disconnected are not replayed.
  • notification.created - a new in-app notification of your workspace, for example a finished export or CSV enrichment. data is the notification itself.
  • credits.updated - a credit balance changed. data.credit_type names the balance and data.available is its new value. Call Get Credit Balances for the full picture.
  • subscription.updated - the workspace subscription changed; data.status is its new status.
  • integration.updated - the connection status of a CRM integration of the workspace changed; data.integration names it and data.status is its new status.
  • workspace.member_removed and workspace.members_removed - one or all other members were removed from the workspace.

session.refresh_required and session.revoked are sent to signed-in app sessions only. A stream opened with an API key never receives them; if the key's owner leaves the workspace, the stream closes.

Staying connected

The server ends every stream after 30 minutes, and network hops can drop it sooner. Reconnect whenever it ends - the same request again - and treat the stream.ready that follows as your cue to refresh. A comment line (: ping) arrives every 25 seconds, so a connection silent for much longer than that is dead. One user can hold up to 20 open streams at a time.

For server-to-server integrations that must not miss an event, poll the relevant endpoint after each stream.ready rather than relying on the stream alone.

Responses

  • 200 The stream (text/event-stream). Each message is an EventStreamMessage whose data: line is a JSON-encoded EventFrame; lines starting with : are heartbeat comments.
  • 401 Missing, unknown or inactive credentials (UNAUTHORIZED), before the stream opens; payload.code credential_in_query (send the credential in a header) or token_expired (refresh the token).
  • 403 A job token (FORBIDDEN, payload.code: session_required).
  • 429 Too many open streams for this user (RATE_LIMIT, payload.code: too_many_streams).
  • 500 Unexpected server error.

For error handling see Errors.