Skip to main content

What is Converger?

Converger is a self-hosted, multi-tenant channel hub written in Elixir on Phoenix, Ecto/Postgres and Oban. It connects communication channels (WebSocket clients, generic HTTP webhooks, WhatsApp through Meta or Infobip, and more to come) to each other. A message that enters through any channel is stored once as an activity in a conversation, given a strictly increasing per-conversation sequence number, and delivered to every channel that should receive it. Each delivery is tracked, retried and, when retries run out, dead-lettered.

The model in one paragraph​

A tenant owns channels. Each channel has a type (its adapter: webhook, websocket, whatsapp_meta, whatsapp_infobip, slack, telegram, email, sms_twilio, sms_vonage, echo) and a mode (inbound, outbound or duplex). Messages arrive through the REST API, the WebSocket sockets or a channel's inbound webhook. They are written as activities in a conversation that belongs to one channel. Inbound messages from providers that never send a Converger conversation id are matched to a conversation through the external participant, such as a WhatsApp phone number or a Slack thread. Each activity gets a seq (1, 2, 3, ...) that is allocated under a row lock on the conversation. In the same database transaction Converger enqueues one delivery job per target channel: the conversation's own channel, if it can send, plus the targets of any enabled routing rules. Each delivery passes through the target channel's middleware chain (transformations) and is then handed to the adapter. It ends as sent, delivered or read, or as failed once its retries run out.

See Concepts for every entity, and Architecture for how the processes fit together.

High-level flow​

Design goals​

WebSocket-first, with its own protocol​

WebSocket is meant to be Converger's primary, first-class channel. Two socket stacks exist today:

  • /socket/converger (ConvergerSocket, topics converger:conversation:<id> and, for agent consoles, converger:channel:<id>), the client API inspired by Bot Framework Direct Line, authenticated with a Converger token. On join it replays activities after an opaque watermark, clients send activities on it with postActivity and acknowledge deliveries with ack. It is the single client socket stack (#23).
  • /socket (UserSocket, topic conversation:<id>), authenticated with a conversation token. Deprecated: new clients use /socket/converger; see migrating from the legacy surfaces.

Both receive the same canonical activity payload as REST (see ADR-0004). The direction is to merge them into one documented wire protocol, the Converger Protocol v1 (spec in progress, #21, #63). It will be wire-compatible with mekik/1 (ADR-0024) and will add client message ids with server acks, receipts, typing and presence. That work is tracked in the v3.0 epic #58. The websocket channel type is a duplex channel adapter: clients send over the socket through the same inbound path as webhooks, and deliveries to the channel are tracked, can be routing rule targets and wait for a client while none is connected (#22, ADR-0033).

Zero data loss​

An acknowledged message must never be lost. These mechanisms are in place:

MechanismWhat it guaranteesWhere
Transactional outboxThe activity row, its seq and its Oban delivery jobs commit in one database transaction. A crash cannot leave a committed activity without its deliveries. If enqueueing fails, the activity is rolled back and the client gets 503.ADR-0001, activities.ex
Single delivery pathEvery external delivery, whatever its origin (REST, WebSocket, inbound), goes through the pipeline. That means middleware, the adapter and a delivery record.ADR-0003
IdempotencyAn x-idempotency-key header (REST) or the provider message id (inbound) is unique per conversation. A retried request returns the existing activity instead of creating a second one. Inbound batches are idempotent per message.ADR-0015
Per-conversation seqStrict, gap-free ordering that does not depend on clocks, and opaque watermarks for resuming.ADR-0006
Retries with backoffPer-channel retry policy (max_attempts, backoff, base_ms, max_ms, timeout_ms). A provider Retry-After is honored. Oban Lifeline rescues jobs orphaned by a crashed node.ADR-0019
Dead lettersA delivery that runs out of attempts, gets a permanent provider error, or is halted by middleware is marked failed with last_error, and telemetry fires.Deliveries

Broadway (Converger.Pipeline.Broadway) and inline (Converger.Pipeline.Inline) pipeline backends also exist, for throughput experiments and for tests. Only the default Oban backend is durable (ADR-0002).

What Converger is​

  • A message router and store for conversations that span channels, with per-tenant isolation (API keys, channel secrets encrypted at rest, per-tenant rate limits).
  • A delivery tracker: every outbound message has a delivery record with attempts, errors and provider receipts (sent, delivered, read).
  • An integration surface: a server-to-server REST API (tenant API key), a client API with short-lived tokens and WebSocket streaming, inbound webhooks for providers, an admin panel (/admin) and a tenant portal (/portal).
  • Operable: an Elixir release with separate migrations, Prometheus metrics, OpenTelemetry traces, audit logs and channel health checks.

What Converger is not​

  • Not a bot framework or AI agent runtime. It carries messages to and from bots. It does not decide what to answer. The echo channel is a test helper, not a bot.
  • Not a chat UI. The admin and portal show transcripts for operators. End-user widgets connect over the WebSocket or REST client API.
  • Not a general-purpose message broker. Activities are conversation-scoped and stored in Postgres. Kafka, RabbitMQ, NATS JetStream, Redis Streams and MQTT can be broker channels: integration endpoints, not the storage of conversations.
  • Not finished. A management API (#51) and the bot/agent SDKs (#67) are on the roadmap. The headless TypeScript client @converger/client (#46) and the server-side SDKs for Python, Go and Elixir (Client SDKs, #47) exist.

Where to go next​

License​

Converger is open source under the MIT License (ADR-0073). Contributions are welcome: see Contributing.