# Ivy: One write, every protocol. Rules-as-code, in your repo.

Ivy *Transform your data infra for builders and AI*
[Sign up](https://ivy.conduktor.io) [Read the docs](https://docs.ivy.conduktor.io)

Use your operational data without building internal plumbing. Capture it from anywhere, then process and expose the same data over HTTP, SQL, and Kafka, with governance enforced once at the boundary.

## Operational data is what your business is running on. Why keep it trapped?

We built Ivy, a multi-protocol data platform, so every app, team, and agent can read and write in their own protocol, from one source of truth. No plumbing, no glue.

01 · **primitive**
One write, every protocol
Access means plumbing. Each protocol needs its own connector and internal service just to expose data that already exists. Teams spend their year maintaining glue code instead of shipping product.
With Ivy
One record in Ivy. Read it as **HTTP, SQL, MQTT, Kafka, or MCP**. Same schema, same security, and same audit.

02 · **real-time**
No ETL
Every new consumer is another pipeline to design, build, schedule, monitor, and fix. The same data gets copied over and over, storage bloats, definitions drift, and no one trusts which version is right.
With Ivy
Operational data is processed and activated **the moment it's produced**. No ETL, no warehouse round-trip. The data stays where it was born.

03 · **agents**
Build faster, plug in agents
Agents and next-generation builders expect data to be there, in their protocol, on day one. When it isn't, AI agents stay stuck in POC and the products that should exist never get built.
With Ivy
Your data is **actionable the moment it's created**. Every source becomes an agent-callable tool, governed and audited.

## Capture · Process · Activate.

Three primitives, one binary. Connect a source, write a rule, and expose the result. The rest is governance.

01 · captureConnect any data sourceMulti-protocol ingestion, HTTP, MQTT, Kafka, Postgres, CDC, and SaaS webhooks. Schema inference.
02 · processWrite rules in codeFilter, map, join, and correlate across sources. Stateful by default. Pattern matching, time windows, and no DB to operate.
03 · activateExpose to anythingSQL, HTTP, Kafka, MCP, outbound webhook, and embeddable. Native protocols, governance applied at the boundary.

Kafka
AMQP
HTTP
MQTT

kcatkafka-console-producerkafkajsconfluent-kafkago / confluent-kafka-goCopy

kcat -P -b kafka.demo.ivy.conduktor.io:9094 -t mystream \
  -X security.protocol=SASL_SSL \
  -X sasl.mechanism=SCRAM-SHA-256 \
  -X sasl.username=tok_V8WkorRDLT6NYxg3CPpUKQ \
  -X sasl.password=ipk_hGg8uEBnIPi7bDHszUrAZ3RAjTLfz2KeEH8YD6BTUmM \
  <<< '{"id":"550e8400-e29b-41d4-a716-446655440000","data":"example","time":"2026-04-29T14:00:00Z","type":"example","source":"example"}'
echo '{"id":"550e8400-e29b-41d4-a716-446655440000","data":"example","time":"2026-04-29T14:00:00Z","type":"example","source":"example"}' | kafka-console-producer \
  --bootstrap-server kafka.demo.ivy.conduktor.io:9094 \
  --topic mystream \
  --producer-property security.protocol=SASL_SSL \
  --producer-property sasl.mechanism=SCRAM-SHA-256 \
  --producer-property sasl.jaas.config='org.apache.kafka.common.security.scram.ScramLoginModule required username="tok_V8WkorRDLT6NYxg3CPpUKQ" password="ipk_hGg8uEBnIPi7bDHszUrAZ3RAjTLfz2KeEH8YD6BTUmM";'
import { Kafka } from "kafkajs";

const kafka = new Kafka({
  brokers: ["kafka.demo.ivy.conduktor.io:9094"],
  ssl: true,
  sasl: { mechanism: "scram-sha-256", username: "tok_V8WkorRDLT6NYxg3CPpUKQ", password: "ipk_hGg8uEBnIPi7bDHszUrAZ3RAjTLfz2KeEH8YD6BTUmM" },
});
const producer = kafka.producer();
await producer.connect();
await producer.send({
  topic: "mystream",
  messages: [{ value: JSON.stringify({"id":"550e8400-e29b-41d4-a716-446655440000","data":"example","time":"2026-04-29T14:00:00Z","type":"example","source":"example"}) }],
});
from confluent_kafka import Producer

p = Producer({
    "bootstrap.servers": "kafka.demo.ivy.conduktor.io:9094",
    "security.protocol": "SASL_SSL",
    "sasl.mechanism": "SCRAM-SHA-256",
    "sasl.username": "tok_V8WkorRDLT6NYxg3CPpUKQ",
    "sasl.password": "ipk_hGg8uEBnIPi7bDHszUrAZ3RAjTLfz2KeEH8YD6BTUmM",
})
p.produce("mystream", '{"id":"550e8400-e29b-41d4-a716-446655440000","data":"example","time":"2026-04-29T14:00:00Z","type":"example","source":"example"}')
p.flush()
import "github.com/confluentinc/confluent-kafka-go/v2/kafka"

p, _ := kafka.NewProducer(&kafka.ConfigMap{
    "bootstrap.servers": "kafka.demo.ivy.conduktor.io:9094",
    "security.protocol": "SASL_SSL",
    "sasl.mechanism":    "SCRAM-SHA-256",
    "sasl.username":     "tok_V8WkorRDLT6NYxg3CPpUKQ",
    "sasl.password":     "ipk_hGg8uEBnIPi7bDHszUrAZ3RAjTLfz2KeEH8YD6BTUmM",
})
topic := "mystream"
p.Produce(&kafka.Message{
    TopicPartition: kafka.TopicPartition{Topic: &topic, Partition: kafka.PartitionAny},
    Value:          []byte(`{"id":"550e8400-e29b-41d4-a716-446655440000","data":"example","time":"2026-04-29T14:00:00Z","type":"example","source":"example"}`),
}, nil)
p.Flush(5000)

pikaamqplibgo / amqp091-goCopy

import pika, ssl

ctx = ssl.create_default_context()
params = pika.URLParameters("amqps://tok_V8WkorRDLT6NYxg3CPpUKQ:ipk_hGg8uEBnIPi7bDHszUrAZ3RAjTLfz2KeEH8YD6BTUmM@amqp.demo.ivy.conduktor.io:5671/%2F")
params.ssl_options = pika.SSLOptions(ctx)
conn = pika.BlockingConnection(params)
ch = conn.channel()
ch.basic_publish(
    exchange="ivy.mystream",
    routing_key="mystream",
    body='{"id":"550e8400-e29b-41d4-a716-446655440000","data":"example","time":"2026-04-29T14:00:00Z","type":"example","source":"example"}',
)
import amqp from "amqplib";

const conn = await amqp.connect("amqps://tok_V8WkorRDLT6NYxg3CPpUKQ:ipk_hGg8uEBnIPi7bDHszUrAZ3RAjTLfz2KeEH8YD6BTUmM@amqp.demo.ivy.conduktor.io:5671/");
const ch = await conn.createChannel();
await ch.assertExchange("ivy.mystream", "topic", { durable: true });
ch.publish("ivy.mystream", "mystream",
  Buffer.from(JSON.stringify({"id":"550e8400-e29b-41d4-a716-446655440000","data":"example","time":"2026-04-29T14:00:00Z","type":"example","source":"example"})));
import amqp "github.com/rabbitmq/amqp091-go"

conn, _ := amqp.DialTLS("amqps://tok_V8WkorRDLT6NYxg3CPpUKQ:ipk_hGg8uEBnIPi7bDHszUrAZ3RAjTLfz2KeEH8YD6BTUmM@amqp.demo.ivy.conduktor.io:5671/", nil)
ch, _ := conn.Channel()
ch.PublishWithContext(ctx, "ivy.mystream", "mystream", false, false,
    amqp.Publishing{ContentType: "application/json",
        Body: []byte(`{"id":"550e8400-e29b-41d4-a716-446655440000","data":"example","time":"2026-04-29T14:00:00Z","type":"example","source":"example"}`)})

curlnode / fetchPython requestsgo / net/httpCopy

curl -X POST https://http.demo.ivy.conduktor.io/topics/mystream \
  -H "Authorization: Bearer tok_V8WkorRDLT6NYxg3CPpUKQ.ipk_hGg8uEBnIPi7bDHszUrAZ3RAjTLfz2KeEH8YD6BTUmM" \
  -H "Content-Type: application/json" \
  -d '{"id":"550e8400-e29b-41d4-a716-446655440000","data":"example","time":"2026-04-29T14:00:00Z","type":"example","source":"example"}'
await fetch("https://http.demo.ivy.conduktor.io/topics/mystream", {
  method: "POST",
  headers: {
    Authorization: "Bearer tok_V8WkorRDLT6NYxg3CPpUKQ.ipk_hGg8uEBnIPi7bDHszUrAZ3RAjTLfz2KeEH8YD6BTUmM",
    "Content-Type": "application/json",
  },
  // Body shape mirrors the schema you authored in the wizard. Replace literal
  // values with your runtime data when you wire this into your app.
  body: JSON.stringify({"id":"550e8400-e29b-41d4-a716-446655440000","data":"example","time":"2026-04-29T14:00:00Z","type":"example","source":"example"}),
});
import json, requests

requests.post(
    "https://http.demo.ivy.conduktor.io/topics/mystream",
    headers={"Authorization": "Bearer tok_V8WkorRDLT6NYxg3CPpUKQ.ipk_hGg8uEBnIPi7bDHszUrAZ3RAjTLfz2KeEH8YD6BTUmM", "Content-Type": "application/json"},
    data=json.dumps(json.loads('{"id":"550e8400-e29b-41d4-a716-446655440000","data":"example","time":"2026-04-29T14:00:00Z","type":"example","source":"example"}')),
)
package main

import (
    "bytes"
    "net/http"
)

func main() {
    body := []byte(`{"id":"550e8400-e29b-41d4-a716-446655440000","data":"example","time":"2026-04-29T14:00:00Z","type":"example","source":"example"}`)
    req, _ := http.NewRequest("POST", "https://http.demo.ivy.conduktor.io/topics/mystream", bytes.NewReader(body))
    req.Header.Set("Authorization", "Bearer tok_V8WkorRDLT6NYxg3CPpUKQ.ipk_hGg8uEBnIPi7bDHszUrAZ3RAjTLfz2KeEH8YD6BTUmM")
    req.Header.Set("Content-Type", "application/json")
    http.DefaultClient.Do(req)
}

mosquitto_pubmqtt.jspaho-mqttgo / paho.mqtt.golangCopy

mosquitto_pub -h mqtt.demo.ivy.conduktor.io -p 8883 \
  -u tok_V8WkorRDLT6NYxg3CPpUKQ -P "ipk_hGg8uEBnIPi7bDHszUrAZ3RAjTLfz2KeEH8YD6BTUmM" \
  -t "mystream" -q 1 \
  -m '{"id":"550e8400-e29b-41d4-a716-446655440000","data":"example","time":"2026-04-29T14:00:00Z","type":"example","source":"example"}'
import mqtt from "mqtt";

const c = mqtt.connect("mqtts://mqtt.demo.ivy.conduktor.io:8883", {
  username: "tok_V8WkorRDLT6NYxg3CPpUKQ",
  password: "ipk_hGg8uEBnIPi7bDHszUrAZ3RAjTLfz2KeEH8YD6BTUmM",
});
c.on("connect", () => {
  c.publish("mystream", JSON.stringify({"id":"550e8400-e29b-41d4-a716-446655440000","data":"example","time":"2026-04-29T14:00:00Z","type":"example","source":"example"}), { qos: 1 });
});
import paho.mqtt.client as mqtt, ssl

c = mqtt.Client()
c.username_pw_set("tok_V8WkorRDLT6NYxg3CPpUKQ", "ipk_hGg8uEBnIPi7bDHszUrAZ3RAjTLfz2KeEH8YD6BTUmM")
c.tls_set(cert_reqs=ssl.CERT_REQUIRED)
c.connect("mqtt.demo.ivy.conduktor.io", 8883, 60)
c.publish("mystream", payload='{"id":"550e8400-e29b-41d4-a716-446655440000","data":"example","time":"2026-04-29T14:00:00Z","type":"example","source":"example"}', qos=1)
import mqtt "github.com/eclipse/paho.mqtt.golang"

opts := mqtt.NewClientOptions().
    AddBroker("tls://mqtt.demo.ivy.conduktor.io:8883").
    SetUsername("tok_V8WkorRDLT6NYxg3CPpUKQ").
    SetPassword("ipk_hGg8uEBnIPi7bDHszUrAZ3RAjTLfz2KeEH8YD6BTUmM")
c := mqtt.NewClient(opts)
c.Connect().Wait()
c.Publish("mystream", 1, false, `{"id":"550e8400-e29b-41d4-a716-446655440000","data":"example","time":"2026-04-29T14:00:00Z","type":"example","source":"example"}`).Wait()

Kafka
AMQP
HTTP
WS
MQTT

kcatkafka-console-consumerkafkajsconfluent-kafkago / confluent-kafka-goCopy

kcat -C -b kafka.demo.ivy.conduktor.io:9094 -t mystream -o beginning -e \
  -X security.protocol=SASL_SSL \
  -X sasl.mechanism=SCRAM-SHA-256 \
  -X sasl.username=tok_V8WkorRDLT6NYxg3CPpUKQ \
  -X sasl.password=ipk_hGg8uEBnIPi7bDHszUrAZ3RAjTLfz2KeEH8YD6BTUmM
kafka-console-consumer \
  --bootstrap-server kafka.demo.ivy.conduktor.io:9094 \
  --topic mystream \
  --from-beginning \
  --consumer-property security.protocol=SASL_SSL \
  --consumer-property sasl.mechanism=SCRAM-SHA-256 \
  --consumer-property sasl.jaas.config='org.apache.kafka.common.security.scram.ScramLoginModule required username="tok_V8WkorRDLT6NYxg3CPpUKQ" password="ipk_hGg8uEBnIPi7bDHszUrAZ3RAjTLfz2KeEH8YD6BTUmM";'
import { Kafka } from "kafkajs";

const kafka = new Kafka({
  brokers: ["kafka.demo.ivy.conduktor.io:9094"],
  ssl: true,
  sasl: { mechanism: "scram-sha-256", username: "tok_V8WkorRDLT6NYxg3CPpUKQ", password: "ipk_hGg8uEBnIPi7bDHszUrAZ3RAjTLfz2KeEH8YD6BTUmM" },
});

const consumer = kafka.consumer({ groupId: "my-app" });
await consumer.connect();
await consumer.subscribe({ topic: "mystream", fromBeginning: true });
await consumer.run({
  eachMessage: async ({ message }) => console.log(message.value?.toString()),
});
from confluent_kafka import Consumer

c = Consumer({
    "bootstrap.servers": "kafka.demo.ivy.conduktor.io:9094",
    "security.protocol": "SASL_SSL",
    "sasl.mechanism": "SCRAM-SHA-256",
    "sasl.username": "tok_V8WkorRDLT6NYxg3CPpUKQ",
    "sasl.password": "ipk_hGg8uEBnIPi7bDHszUrAZ3RAjTLfz2KeEH8YD6BTUmM",
    "group.id": "my-app",
    "auto.offset.reset": "earliest",
})
c.subscribe(["mystream"])
while True:
    msg = c.poll(1.0)
    if msg and not msg.error():
        print(msg.value().decode())
import "github.com/confluentinc/confluent-kafka-go/v2/kafka"

c, _ := kafka.NewConsumer(&kafka.ConfigMap{
    "bootstrap.servers": "kafka.demo.ivy.conduktor.io:9094",
    "security.protocol": "SASL_SSL",
    "sasl.mechanism":    "SCRAM-SHA-256",
    "sasl.username":     "tok_V8WkorRDLT6NYxg3CPpUKQ",
    "sasl.password":     "ipk_hGg8uEBnIPi7bDHszUrAZ3RAjTLfz2KeEH8YD6BTUmM",
    "group.id":          "my-app",
    "auto.offset.reset": "earliest",
})
c.Subscribe("mystream", nil)
for {
    msg, err := c.ReadMessage(-1)
    if err == nil {
        println(string(msg.Value))
    }
}

pikaamqplibgo / amqp091-goCopy

import pika, ssl

ctx = ssl.create_default_context()
params = pika.URLParameters("amqps://tok_V8WkorRDLT6NYxg3CPpUKQ:ipk_hGg8uEBnIPi7bDHszUrAZ3RAjTLfz2KeEH8YD6BTUmM@amqp.demo.ivy.conduktor.io:5671/%2F")
params.ssl_options = pika.SSLOptions(ctx)
conn = pika.BlockingConnection(params)
ch = conn.channel()
ch.queue_declare("mystream", durable=True)
for method, props, body in ch.consume("mystream", auto_ack=True):
    print(body.decode())
import amqp from "amqplib";

const conn = await amqp.connect("amqps://tok_V8WkorRDLT6NYxg3CPpUKQ:ipk_hGg8uEBnIPi7bDHszUrAZ3RAjTLfz2KeEH8YD6BTUmM@amqp.demo.ivy.conduktor.io:5671/");
const ch = await conn.createChannel();
await ch.assertQueue("mystream", { durable: true });
ch.consume("mystream", (msg) => {
  if (msg) {
    console.log(msg.content.toString());
    ch.ack(msg);
  }
});
import amqp "github.com/rabbitmq/amqp091-go"

conn, _ := amqp.DialTLS("amqps://tok_V8WkorRDLT6NYxg3CPpUKQ:ipk_hGg8uEBnIPi7bDHszUrAZ3RAjTLfz2KeEH8YD6BTUmM@amqp.demo.ivy.conduktor.io:5671/", nil)
ch, _ := conn.Channel()

msgs, _ := ch.Consume("mystream", "", true, false, false, false, nil)
for msg := range msgs {
    println(string(msg.Body))
}

curlnode / fetchPython requestsgo / net/httpCopy

curl -N "https://http.demo.ivy.conduktor.io/topics/mystream/stream?from=earliest" \
  -H "Authorization: Bearer tok_V8WkorRDLT6NYxg3CPpUKQ.ipk_hGg8uEBnIPi7bDHszUrAZ3RAjTLfz2KeEH8YD6BTUmM" \
  -H "Accept: text/event-stream"
const res = await fetch("https://http.demo.ivy.conduktor.io/topics/mystream/stream?from=earliest", {
  headers: {
    Authorization: "Bearer tok_V8WkorRDLT6NYxg3CPpUKQ.ipk_hGg8uEBnIPi7bDHszUrAZ3RAjTLfz2KeEH8YD6BTUmM",
    Accept: "text/event-stream",
  },
});
for await (const chunk of res.body) {
  console.log(new TextDecoder().decode(chunk));
}
import requests

with requests.get(
    "https://http.demo.ivy.conduktor.io/topics/mystream/stream?from=earliest",
    headers={"Authorization": "Bearer tok_V8WkorRDLT6NYxg3CPpUKQ.ipk_hGg8uEBnIPi7bDHszUrAZ3RAjTLfz2KeEH8YD6BTUmM", "Accept": "text/event-stream"},
    stream=True,
) as r:
    for line in r.iter_lines():
        if line:
            print(line.decode())
package main

import (
    "bufio"
    "net/http"
)

func main() {
    req, _ := http.NewRequest("GET", "https://http.demo.ivy.conduktor.io/topics/mystream/stream?from=earliest", nil)
    req.Header.Set("Authorization", "Bearer tok_V8WkorRDLT6NYxg3CPpUKQ.ipk_hGg8uEBnIPi7bDHszUrAZ3RAjTLfz2KeEH8YD6BTUmM")
    req.Header.Set("Accept", "text/event-stream")
    resp, _ := http.DefaultClient.Do(req)
    defer resp.Body.Close()
    s := bufio.NewScanner(resp.Body)
    for s.Scan() {
        println(s.Text())
    }
}

wscatChrome browserwebsocketsgo / gorillaCopy

wscat -c "wss://http.demo.ivy.conduktor.io/ws/topics/mystream" -H "Authorization: Bearer tok_V8WkorRDLT6NYxg3CPpUKQ.ipk_hGg8uEBnIPi7bDHszUrAZ3RAjTLfz2KeEH8YD6BTUmM"
const ws = new WebSocket("wss://http.demo.ivy.conduktor.io/ws/topics/mystream", ["bearer.tok_V8WkorRDLT6NYxg3CPpUKQ.ipk_hGg8uEBnIPi7bDHszUrAZ3RAjTLfz2KeEH8YD6BTUmM"]);
ws.onmessage = (e) => console.log(JSON.parse(e.data));
import asyncio, websockets

async def main():
    async with websockets.connect(
        "wss://http.demo.ivy.conduktor.io/ws/topics/mystream",
        extra_headers={"Authorization": "Bearer tok_V8WkorRDLT6NYxg3CPpUKQ.ipk_hGg8uEBnIPi7bDHszUrAZ3RAjTLfz2KeEH8YD6BTUmM"},
    ) as ws:
        async for msg in ws:
            print(msg)

asyncio.run(main())
import "github.com/gorilla/websocket"

h := http.Header{"Authorization": []string{"Bearer tok_V8WkorRDLT6NYxg3CPpUKQ.ipk_hGg8uEBnIPi7bDHszUrAZ3RAjTLfz2KeEH8YD6BTUmM"}}
c, _, _ := websocket.DefaultDialer.Dial("wss://http.demo.ivy.conduktor.io/ws/topics/mystream", h)
for {
    _, msg, err := c.ReadMessage()
    if err != nil { break }
    println(string(msg))
}

mosquitto_submqtt.jspaho-mqttgo / paho.mqtt.golangCopy

mosquitto_sub -h mqtt.demo.ivy.conduktor.io -p 8883 \
  -u tok_V8WkorRDLT6NYxg3CPpUKQ -P "ipk_hGg8uEBnIPi7bDHszUrAZ3RAjTLfz2KeEH8YD6BTUmM" \
  -t "mystream" -q 1 -v
import mqtt from "mqtt";

const c = mqtt.connect("mqtts://mqtt.demo.ivy.conduktor.io:8883", {
  username: "tok_V8WkorRDLT6NYxg3CPpUKQ",
  password: "ipk_hGg8uEBnIPi7bDHszUrAZ3RAjTLfz2KeEH8YD6BTUmM",
});
c.on("connect", () => c.subscribe("mystream", { qos: 1 }));
c.on("message", (topic, payload) => console.log(payload.toString()));
import paho.mqtt.client as mqtt, ssl

def on_message(client, userdata, msg):
    print(msg.payload.decode())

c = mqtt.Client()
c.username_pw_set("tok_V8WkorRDLT6NYxg3CPpUKQ", "ipk_hGg8uEBnIPi7bDHszUrAZ3RAjTLfz2KeEH8YD6BTUmM")
c.tls_set(cert_reqs=ssl.CERT_REQUIRED)
c.on_message = on_message
c.connect("mqtt.demo.ivy.conduktor.io", 8883, 60)
c.subscribe("mystream", qos=1)
c.loop_forever()
import mqtt "github.com/eclipse/paho.mqtt.golang"

opts := mqtt.NewClientOptions().
    AddBroker("tls://mqtt.demo.ivy.conduktor.io:8883").
    SetUsername("tok_V8WkorRDLT6NYxg3CPpUKQ").
    SetPassword("ipk_hGg8uEBnIPi7bDHszUrAZ3RAjTLfz2KeEH8YD6BTUmM")
c := mqtt.NewClient(opts)
c.Connect().Wait()
c.Subscribe("mystream", 1, func(_ mqtt.Client, m mqtt.Message) {
    println(string(m.Payload()))
}).Wait()

## On the edge, or as the backend.

Plug Ivy into the data you already produce, or write to it directly and use it as the backend. Either way, every consumer reads in its native protocol.

Ivy on the edge
Your existing Kafka topics or any other protocol sync to Ivy. Operational data becomes shareable and usable in the protocol they wish, without any ETL.
**Unblock every team:** everyone self-serves in the protocol they already know.

Ivy as a messaging infra
Your app writes records to Ivy. Your team queries them. Your agent reads them. Each in their own protocol. Ivy is the backend.
**Everything you build** is instantly consumable by every team, app, and agent.

Capabilities
Built in, not bolted on. The full broker, plus the parts you'd otherwise wire up yourself: Connect, Schema Registry, an auth proxy, a state store, and the audit pipeline.

Multi-protocol I/OHTTP, MQTT, WebSockets, Kafka, SaaS webhooks, and Postgres CDC. Native ingest and egress. No Connect cluster to operate separately.
Native pub/subConsumer groups, ordered partitions, fan-out, fan-in, DLQ, and replay. Kafka-protocol compatible. Your existing producers and consumers keep working.
Stateful processingPattern matching, tumbling and sliding windows, cross-stream joins, and exactly-once outputs. No RocksDB or Redis to operate.
Schema catalogTopics, schemas, versions, owners, ACLs, and lineage. Queryable over HTTP, the SDK, or exposed as MCP resources.
Unified governanceSSO, RBAC, field-level masking, schema enforcement, and full audit log. Applied once at ingest, not duplicated per consumer.
Replay & point-in-timeRead from any offset or timestamp. Bounded retention, configurable per stream. Debug a rule, redo a deploy, and audit a chain.
MCP server, built inAgents browse the catalog, subscribe to topics, and trigger rules. Every call token-scoped, every call audited.
Postgres-wire SQLQuery live event streams with psql, dbt, or any BI tool. Point-in-time and bounded-history queries within the retention window, no warehouse round-trip.

## Any protocol in. Any protocol out. No pipeline in between.

One platform speaks every language and governs all of them. Protocol-agnostic by design. Not Kafka-first, not Flink-first.

Produce in…
HTTPPOST events from your app
MQTTSensors, edge devices
KafkaExisting topics, native
WSWebSocket streams
SaaSStripe, HubSpot, Shopify…

Ivy
**auth · rbac · audit**enforced once, at the boundary

Consume in…
SQLLive queries, BI, dbt
HTTPHTTP APIs, OpenAPI auto-gen
KafkaStream into downstream
MCPAgents · governed tool calls
HOOKOutbound webhooks, Slack

## Start leveraging your operational data.

One install. One source. One rule. Every protocol.

[Sign up](https://ivy.conduktor.io) [Read the docs →](https://docs.ivy.conduktor.io)
