Skip to main content

Event Sinks API

Delivery is not live yet. You can create and store an event sink configuration today — the credential is encrypted at rest and the config round-trips through GET/PATCH — but the worker that produces events to Kafka or POSTs them to an HTTP collector has not shipped. No events are delivered to a configured sink, and the run-status fields (last_run_at, last_run_status, last_produced_count, consecutive_failures) stay null until it does. Do not configure a sink expecting live delivery. To receive events now, use per-event webhooks. This page documents the configuration surface; we’ll announce here when delivery goes live.
An event sink streams the platform event taxonomy — the same message.*, 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.
Base path: /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 a credentials_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:
Treat 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 generic request() helper:
Python (same call via the SDK’s escape hatch):
The Python SDK is core-scope — it wraps the 8 core resources (messaging, voice, contacts, campaigns, verify, numbers) and reaches everything else through the generic 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 a GET 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

The secret you patched never appears — credentials_configured: true is your confirmation it round-tripped.

HTTP-batch sink — write

HTTP-batch sink — read after the write

The collector 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:
Transport differences hit only the framing:
  • Kafka — one JSON record per event. The partition key resolves from your partition_key_path (falls back to the event id, then to a hash of the payload); headers carry the envelope flattened (x-orbit-event-type, plus any custom headers you configured).
  • HTTP batch — the flushed body is a JSON array of these envelopes, up to max_batch_size per POST.
Write your consumer against this shape now, and gate the whole flow on webhooks until delivery goes live — the envelope is the same either way. When the worker ships we will announce it in the warning block at the top of this page.

See also

  • Webhooks — per-event HTTP push of the same taxonomy, live today
  • Events API — read or live-stream a bounded recent-event window