Event streaming over HTTP

HTTP-native event streams

Durable, ordered streams you talk to with plain HTTP. Publish a batch with POST, subscribe with a long-lived GET. No WebSocket upgrade, no custom wire protocol, no broker to run.

subscribe from your terminal
curl -N https://runnev.dev/v1/streams/DQCXqM5x6cySlmtvACNZIm \
  -H "Accept: text/event-stream" \
  -H "Authorization: Bearer rnv_test_2f8c41a6d90b47e3ba15c7e08d3f6a24"

The whole model in three requests

A stream is an ordered, durable log addressed by a base62 id. Publishers append batches at a sequence number. Subscribers hold one HTTP response open and receive batches as server-sent events, each tagged with its sequence so they can resume exactly where they left off.

There is no broker to operate and nothing to install on the server side of your infrastructure. If it can make an HTTP request, it can use Runnev.

How streams work →

1. create a stream
curl https://runnev.dev/v1/streams \
  -H "Authorization: Bearer $RUNNEV_API_KEY" \
  -d '{"name":"orders-eu","retention_seconds":86400}'
2. publish a batch at sequence 41823
curl https://runnev.dev/v1/streams/cBczepiZSW8GJaCae0xIj7/41823 \
  -H "Authorization: Bearer $RUNNEV_API_KEY" \
  -d '{"events":[{"type":"order.paid","id":"o_5521","amount":1999}]}'
# 202  {"seq":41823,"accepted":1,"cursor":41823,"duplicate":false}
3. subscribe and resume from a cursor
curl -N "https://runnev.dev/v1/streams/cBczepiZSW8GJaCae0xIj7?cursor=41800" \
  -H "Accept: text/event-stream" \
  -H "Authorization: Bearer $RUNNEV_API_KEY"

A live stream, right now

This is the public demo stream: a read-only feed of synthetic order events that our own test harness publishes around the clock. The connection below is a single long-lived GET held open in your browser, reconnecting from its last cursor if it drops.

connecting 0 events
  • 41802 11:02:07.114 128 events order.paid eu-west
  • 41803 11:02:09.881 116 events order.created us-east
  • 41804 11:02:12.640 131 events order.paid ap-south
  • 41805 11:02:15.402 124 events order.refunded eu-west
  • 41806 11:02:18.219 119 events order.created eu-central

The demo key is public and rate limited to 60 requests per minute per IP. It can only read this one stream. See Subscribing for the wire format.

Why not WebSockets

WebSockets are a good fit when you control both ends and the network between them. Event delivery to the open internet is a different problem, and the upgrade handshake is the part that breaks.

Intermediaries drop upgrades

Corporate forward proxies, some enterprise firewalls, and a few CDN configurations refuse or mishandle the Upgrade: websocket handshake. A plain HTTP request passes through the same hops untouched.

Serverless can't hold a socket

Function runtimes bill and time out on wall-clock duration and were never meant to pin a raw socket open. They can, however, stream an HTTP response body, which is all a subscriber needs.

Mobile radios kill idle sockets

Carriers reap idle connections aggressively to save radio power. A stream with a periodic keepalive frame and cheap cursor-based resume survives a flaky link far more gracefully than a socket that must be renegotiated from scratch.

HTTP/2 multiplexing is free

Over HTTP/2 and HTTP/3, many concurrent streams share one connection with header compression and flow control you did not have to build. One subscriber to forty streams is forty logical streams on a single socket.

This is the steady state, by design

A healthy Runnev subscriber holds a single response open for hours or days, and a busy publisher sends thousands of small POSTs a minute. Both are normal, supported operating modes. The platform, the SDKs, and the docs are built around long-lived connections and high write rates rather than treating them as edge cases.

What you get

Ordered, durable streams

Every batch has a monotonic sequence. Streams are retained for a window you configure, in time and in bytes.

Cursor resume & replay

Reconnect with ?cursor=N and continue exactly after sequence N. Replay any single batch by sequence.

Raw binary batches

Publish application/octet-stream and we never look inside. Bring protobuf, msgpack, Avro, or your own framing.

Idempotent publishes

Writes are keyed on (stream, seq). Retry a publish and the second attempt returns duplicate: true instead of a second copy.

HTTP/2 and HTTP/3

Delivered over modern HTTP on the edge, with the older HTTP/1.1 streaming path kept working for clients that need it.

Three SDKs, no broker

Zero-dependency clients for JavaScript, Python, and Go. Nothing to deploy, no queue to babysit, no ZooKeeper.

What Runnev is not

Naming the limits up front saves everyone a support ticket. Runnev is a stream, not a work queue.

  • No per-consumer acknowledgement. Subscribers track their own cursor. There is no server-side "this consumer processed batch N" and no redelivery to a specific consumer.
  • No cross-stream ordering. Order is guaranteed within a single stream. Two events on two different streams have no defined relative order.
  • No exactly-once. Delivery is at-least-once. Because publishes are idempotent on (stream, seq), deduplication on the read side is a one-line check, and we document exactly how to do it.
  • Batches cap at 8 MiB. A single publish body over 8 MiB is rejected with 413. Split large payloads across sequences.

The full set of guarantees →

Questions

Do I need to run a broker or an agent?

No. Runnev is a hosted HTTP API. Your publishers make POST requests and your subscribers make one long GET. There is nothing to install on your side beyond an optional SDK, and the SDKs are thin wrappers over the same HTTP calls.

How is this different from server-sent events on my own server?

The subscribe side is server-sent events; that is deliberate, because SSE is plain HTTP and travels everywhere. What Runnev adds is the durable, ordered log behind it: sequence numbers, cursor resume, replay, retention, and idempotent writes, so a subscriber that disconnects for an hour catches up instead of missing everything.

What happens when a subscriber falls behind?

Nothing happens to the publisher. Batches are buffered in the stream up to its retention window. A slow subscriber reads at its own pace; if it disconnects it resumes from its cursor. If it falls behind the retention window it skips the evicted batches, and the gap is visible as a jump in sequence numbers.

Can I publish binary data?

Yes. Create the stream in raw mode and publish application/octet-stream bodies. We store and deliver the bytes verbatim and never parse them. See Publishing.

Are open subscribe connections billed?

No. Billing is on published events and egress bytes. Holding a subscription open, even for days, does not cost anything by itself. See Pricing.

Which languages are supported?

Any language with an HTTP client. We publish first-party SDKs for JavaScript, Python, and Go, and the API reference is complete enough to write your own client in an afternoon.