Event streams are a beta. A team owner or admin enrolls the team on the
project’s API Keys page in the Console by accepting the beta terms. Without
enrollment, opening a stream returns
403 with the feature_unavailable code.Before you start
You need:- a team key (
pmfa_…) or a project credential (pmfa_pt_…) with theevents:listenpermission. A project credential can stream only its own project. Client tokens cannot open a stream. - the project ID.
Open a stream
event name,
a JSON data field, and, for events, an id:
ready. sequence counts messages on this
connection and starts again at 1 on every connection. Use cursor, not
sequence, to track your position.
Filter event types
Passtypes as a comma-separated list, or repeat the parameter. A trailing *
matches a prefix:
types to receive every event type. You can send up to 32 filters. The
ready message lists the filters the stream applied.
Read an event
Theevent object in each event message has the same fields as a project
event from the event history API: id, type, source,
environment, createdAt, payloadAvailability, replayableUntil,
metadataExpiresAt, and payload.
When payloadAvailability is available, payload.data is the base64 of the
exact webhook body for that event. Decode it to read the same JSON your webhook
endpoint receives.
The body is present only when all of these are true:
- hosted message storage is enabled for the number that produced the event;
- the body is within the storage size limit; and
- that storage is still enabled, and the number is connected, when the stream sends the event.
payload is null and payloadAvailability explains why:
Use the event
id to deduplicate. The same event has the same id on the
stream, in webhooks, and in event history.
Resume after a disconnect
Everyevent message carries a cursor, also sent as the message id. To
continue where you stopped, reconnect with the last cursor you processed, either
as the Last-Event-ID header or as the cursor query parameter:
Last-Event-ID automatically when they
reconnect. The stream then delivers the events after that cursor.
A cursor:
- is valid for 24 hours after its event;
- works only with the same team, project, and
typesfilter; and - must not be modified.
400 stream_cursor_invalid. An
older cursor returns 410 stream_cursor_expired: reconnect without a cursor and
read what you missed from event history.
If events after your cursor are no longer kept, the stream sends one gap
message with reason: "retention_exceeded", then continues with the next
available event. The message includes missedEvents when Polymorfa can count
the missing events; without missedEvents, some events may be missing and
their number is unknown. Read the missing events from event history.
Acknowledge events
By default (ack=auto) the stream releases each event as soon as it is written
to the connection. Save the cursor after you process each event, and resume from
it after a disconnect.
To have the stream wait for your processing, open it with ack=manual. The
stream then keeps at most maxInFlight unacknowledged events outstanding.
Acknowledge everything up to a message with its cursor and sequence, using
the same credential that opened the stream:
checkpoint message with the acknowledged cursor. If an event stays
unacknowledged for 30 seconds, the stream sends backpressure; if it is still
unacknowledged 30 seconds later, the stream sends dropped and closes. Reconnect
from the last acknowledged cursor.
Keep the connection healthy
The stream checks your credential, project, and beta enrollment at every
heartbeat, so revocation takes effect within one heartbeat interval.
In
ack=auto mode, a client that stops reading for 30 seconds is disconnected.
Reconnect with exponential backoff and jitter, starting at one second and
capping at 30 seconds.
Limits
- A team can have 10 open event streams at once. Another connection returns
429 stream_connection_limit_reachedwithRetry-After. - Opening streams counts toward a per-credential rate limit. Exceeding it
returns
429 rate_limit_exceededwithRetry-After.