Event Sinks API
An event sink streams the platform event taxonomy — the samemessage.*, call.*, … events the per-event webhooks fan out — to infrastructure you already run. Instead of standing up an HTTP receiver per webhook, point a sink at your own Kafka topic or a batch HTTP collector and consume every subscribed event from one place.
Two transports are available, addressed by kind:
kafka— once delivery ships, events will be produced to a topic on your brokers. Each event will carry a deterministic partition key, so every event for one contact or conversation lands on the same partition and stays ordered.http_batch— once delivery ships, events will be POSTed to your HTTPS collector as a JSON array, flushed at a configurable batch size.
/api/v1/developer/event-sinks
Authentication: API key (X-API-Key) or session JWT. Requires an owner, admin, or developer role.
{kind} is kafka or http_batch. Any other value returns 404.
The credential is write-only
The secret credential — a Kafka SASL password or an HTTP bearer token — is encrypted at rest and is never returned. A read surfaces acredentials_configured boolean instead. To set or rotate it, PATCH a credentials value; to clear it, PATCH credentials: "".
Read a sink
Response fields
The
last_* fields are run status only — they are read-only and ignored if sent in a PATCH. Until the delivery worker ships they always read null, as in the example above.
Decoded redaction — credentials_configured
Reads never return the stored secret — not credentials, not credentials_encrypted, nothing. The credentials_configured boolean is the only signal you get. A successful read of a sink whose credential is stored decodes to exactly this shape:
credentials_configured: false as “this sink cannot deliver even when the worker ships”; treat true as proof the secret round-tripped — without ever seeing the secret itself.
Read via the SDKs
The typed SDK surface has no event-sink helper yet, so the same read goes through the SDK’s genericrequest() helper:
client.request() escape hatch above. See the Python SDK.
request() attaches your API key, retries 429/5xx with backoff, and returns the same { data, meta } envelope a raw call returns. Raw curl works identically.
Define — then verify with a read (write-then-read)
A sink config write returns the resulting config, so checking its state inline is cheap — but aGET is the reliable way to confirm what is actually stored. Below, each PATCH is answered with the state a follow-up GET returns.
Kafka sink — write
Kafka sink — read after the write
credentials_configured: true is your confirmation it round-tripped.
HTTP-batch sink — write
HTTP-batch sink — read after the write
url must be https and resolve to a public host — private and metadata addresses are rejected. Once delivery ships, the sink will POST a JSON array of event envelopes (up to max_batch_size per request) with Content-Type: application/json.
PATCH is a merge: only the fields you send are written, so you can flip enabled or rotate credentials without resending the whole config. The destination.kind must equal the path {kind} — a Kafka topic config cannot be stored under http_batch. The response is the resulting config in the same shape as a read.
Delivery envelope — shape when the worker ships
The delivery worker has not shipped, so a configured sink receives nothing today. But the record it will produce is already defined — every event is serialized byte-identically to the webhooks envelope, so a consumer you write against that shape works unchanged once the worker ships:- Kafka — one JSON record per event. The partition key resolves from your
partition_key_path(falls back to the eventid, then to a hash of the payload); headers carry the envelope flattened (x-orbit-event-type, plus any customheadersyou configured). - HTTP batch — the flushed body is a JSON array of these envelopes, up to
max_batch_sizeper POST.
See also
- Webhooks — per-event HTTP push of the same taxonomy, live today
- Events API — read or live-stream a bounded recent-event window