> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Event Sinks API

> Stream the platform event taxonomy (message.*, call.*, …) to your own Kafka topic or batch HTTP collector.

# Event Sinks API

<Warning>
  **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](/webhooks/overview). This page documents
  the configuration surface; we'll announce here when delivery goes live.
</Warning>

An event sink streams the platform event taxonomy — the same `message.*`, `call.*`, … events the [per-event webhooks](/webhooks/overview) 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.

| Method  | Path                                   | Purpose                              |
| ------- | -------------------------------------- | ------------------------------------ |
| `GET`   | `/api/v1/developer/event-sinks/{kind}` | Read the current config for one sink |
| `PATCH` | `/api/v1/developer/event-sinks/{kind}` | Merge a partial config into one sink |

`{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

```bash theme={null}
curl "https://api.orbit.devotel.io/api/v1/developer/event-sinks/kafka" \
  -H "X-API-Key: dv_live_sk_your_key_here"
```

```json theme={null}
{
  "data": {
    "kind": "kafka",
    "enabled": true,
    "credentials_configured": true,
    "events": ["message.*", "call.completed"],
    "destination": {
      "kind": "kafka",
      "topic": "orbit.events",
      "partition_key_path": "data.contact_id"
    },
    "brokers": ["broker-1.example.com:9092", "broker-2.example.com:9092"],
    "sasl_mechanism": "scram-sha-512",
    "sasl_username": "orbit-producer",
    "last_run_at": "2026-06-21T09:14:02.000Z",
    "last_run_status": "ok",
    "last_produced_count": 128,
    "last_error": null,
    "last_error_at": null,
    "consecutive_failures": 0
  },
  "meta": { "request_id": "req_…", "timestamp": "2026-06-21T09:15:00.000Z" }
}
```

### Response fields

| Field                    | Type           | Description                                                                                                                           |
| ------------------------ | -------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| `kind`                   | string         | `kafka` or `http_batch`.                                                                                                              |
| `enabled`                | boolean        | Whether the sink streams events.                                                                                                      |
| `credentials_configured` | boolean        | `true` when an encrypted secret is stored. The secret is never returned.                                                              |
| `events`                 | string\[]      | Event filter. Empty or a single `*` means every event; otherwise an exact type (`message.sent`) or a `<prefix>.*` glob (`message.*`). |
| `destination`            | object         | The record-shaping config — `topic` for `kafka`, `url` for `http_batch`.                                                              |
| `brokers`                | string\[]      | Kafka bootstrap brokers as `host:port` (`kafka` only).                                                                                |
| `sasl_mechanism`         | string         | `plain`, `scram-sha-256`, or `scram-sha-512` (`kafka` only).                                                                          |
| `sasl_username`          | string         | Kafka SASL username (`kafka` only).                                                                                                   |
| `last_run_at`            | string \| null | When the sink last attempted delivery.                                                                                                |
| `last_run_status`        | string \| null | `ok` or `failed`.                                                                                                                     |
| `last_produced_count`    | number \| null | Events produced on the last run.                                                                                                      |
| `last_error`             | string \| null | Last delivery error, if any.                                                                                                          |
| `last_error_at`          | string \| null | When the last error occurred.                                                                                                         |
| `consecutive_failures`   | number \| null | Consecutive failed runs.                                                                                                              |

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` (the values shown above are illustrative of the eventual shape, not live output).

## Configure a Kafka sink

```bash theme={null}
curl -X PATCH "https://api.orbit.devotel.io/api/v1/developer/event-sinks/kafka" \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "enabled": true,
    "events": ["message.*", "call.completed"],
    "destination": {
      "kind": "kafka",
      "topic": "orbit.events",
      "partition_key_path": "data.contact_id"
    },
    "brokers": ["broker-1.example.com:9092"],
    "sasl_mechanism": "scram-sha-512",
    "sasl_username": "orbit-producer",
    "credentials": "the-sasl-password"
  }'
```

## Configure an HTTP-batch sink

```bash theme={null}
curl -X PATCH "https://api.orbit.devotel.io/api/v1/developer/event-sinks/http_batch" \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "enabled": true,
    "events": ["*"],
    "destination": {
      "kind": "http_batch",
      "url": "https://collector.example.com/orbit/events",
      "max_batch_size": 200
    },
    "credentials": "a-bearer-token"
  }'
```

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.

## See also

* [Webhooks](/webhooks/overview) — per-event HTTP push of the same taxonomy
* [Events API](/api-reference/events) — read or live-stream a bounded recent-event window
