Ivy Transform your data infra for builders and AI

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.
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.
One record in Ivy. Read it as HTTP, SQL, MQTT, Kafka, or MCP. Same schema, same security, and same audit.
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.
Operational data is processed and activated the moment it's produced. No ETL, no warehouse round-trip. The data stays where it was born.
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.
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.
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) 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"}`)}) 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_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() 
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))
}
} 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))
} 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())
}
} 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_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.

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.
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/O
HTTP, MQTT, WebSockets, Kafka, SaaS webhooks, and Postgres CDC. Native ingest and egress. No Connect cluster to operate separately.
Native pub/sub
Consumer groups, ordered partitions, fan-out, fan-in, DLQ, and replay. Kafka-protocol compatible. Your existing producers and consumers keep working.
Stateful processing
Pattern matching, tumbling and sliding windows, cross-stream joins, and exactly-once outputs. No RocksDB or Redis to operate.
Schema catalog
Topics, schemas, versions, owners, ACLs, and lineage. Queryable over HTTP, the SDK, or exposed as MCP resources.
Unified governance
SSO, RBAC, field-level masking, schema enforcement, and full audit log. Applied once at ingest, not duplicated per consumer.
Replay & point-in-time
Read from any offset or timestamp. Bounded retention, configurable per stream. Debug a rule, redo a deploy, and audit a chain.
MCP server, built in
Agents browse the catalog, subscribe to topics, and trigger rules. Every call token-scoped, every call audited.
Postgres-wire SQL
Query 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.
Start leveraging your operational data.
One install. One source. One rule. Every protocol.