API reference
The complete, normative reference for the Runnev HTTP API. Base URL
https://runnev.dev/v1. Every endpoint, its parameters, its responses, and
a working example.
Conventions
- Base URL.
https://runnev.dev/v1. HTTP/2 and HTTP/3 are supported; HTTP/1.1 works for streaming too. - Content type. Requests and responses are JSON
(
application/json) except the subscribe stream (text/event-stream) and raw publish/replay (application/octet-stream). - Timestamps are RFC 3339 in UTC with millisecond precision,
e.g.
2026-08-04T11:02:13.418Z. - Ids are bare base62 (22 chars), e.g.
cBczepiZSW8GJaCae0xIj7. No prefixes. - Sequences are non-negative integers. A stream's cursor is the sequence of its newest batch, starting at 0 when empty.
- Caching. Every
/v1response sendscache-control: no-store. - Unknown query parameters are ignored, never rejected. See Forward compatibility.
- Authentication.
Authorization: Bearer <key>on every endpoint except/v1/health,/v1/version, and the demo stream. See Authentication.
Universal response headers
Every /v1 response carries:
| Header | Example | Meaning |
|---|---|---|
x-request-id | req_0Kj2wq8ULn4mAe1s | Unique per request; quote it in support. |
x-ratelimit-limit | 1000 | Requests allowed in the current window. |
x-ratelimit-remaining | 998 | Requests left in the window. |
x-ratelimit-reset | 1785931200 | Unix time when the window resets. |
cache-control | no-store | Never cache API responses. |
server | runnev | Service identifier. |
A 429 additionally sends retry-after in seconds. Publish
responses add x-runnev-cursor.
Pagination
List endpoints accept ?limit= (1-100, default 20) and a
?cursor= pagination token. The response includes
has_more and, when there is more, a next_cursor to pass back.
This pagination cursor is an opaque token and is unrelated to a stream's sequence
cursor.
Endpoints
Liveness probe. No authentication.
curl https://runnev.dev/v1/health{"status":"ok","uptime_s":1843302}{"version":"1.6.2","commit":"9d3c1af","built":"2026-07-15T08:14:02Z"}Create a stream. Requires auth.
Body
| Field | Type | Notes |
|---|---|---|
name required | string | 1-128 chars. Not required to be unique. |
retention_seconds | integer | 60-2592000. Default 86400. |
max_bytes | integer | 1 MiB - 4 GiB. Default 268435456. |
mode | string | json (default) or raw. |
id | string | Optional client-supplied base62 id for idempotent creation. |
curl https://runnev.dev/v1/streams \
-H "Authorization: Bearer $RUNNEV_API_KEY" \
-d '{"name":"orders-eu","retention_seconds":86400}'{
"id": "cBczepiZSW8GJaCae0xIj7",
"name": "orders-eu",
"created_at": "2026-06-11T09:22:31Z",
"retention_seconds": 86400,
"max_bytes": 268435456,
"cursor": 0,
"bytes_stored": 0,
"mode": "json"
}Errors: 400 invalid_request_error (bad body),
409 stream_name_taken (supplied id already exists),
422 retention_out_of_range, 403 stream_limit_reached.
List streams in the project. Query: limit, cursor.
{
"data": [
{"id":"cBczepiZSW8GJaCae0xIj7","name":"orders-eu","cursor":41823,"mode":"json","created_at":"2026-06-11T09:22:31Z","retention_seconds":86400,"max_bytes":268435456,"bytes_stored":118293011}
],
"has_more": false,
"next_cursor": null
}Dual-mode on the Accept header.
- With
Accept: text/event-stream→ subscribe (SSE). Query:cursor(head,0, or an integer). See Subscribing. - Otherwise → return the stream metadata object (same shape as create).
curl -N "https://runnev.dev/v1/streams/cBczepiZSW8GJaCae0xIj7?cursor=head" \
-H "Accept: text/event-stream" -H "Authorization: Bearer $RUNNEV_API_KEY"Errors: 404 stream_not_found,
400 invalid_stream_id, 403 project_forbidden.
Delete a stream and all its batches. Open subscribers receive
event: end. Returns 204 with no body.
curl -X DELETE https://runnev.dev/v1/streams/cBczepiZSW8GJaCae0xIj7 \
-H "Authorization: Bearer $RUNNEV_API_KEY" # 204The primary write path. seq is a non-negative integer, at most 1024
ahead of the cursor. Idempotent on (id, seq). Accepts
application/json ({"events":[...]}) or, for
raw streams, application/octet-stream. Max body 8 MiB.
curl https://runnev.dev/v1/streams/cBczepiZSW8GJaCae0xIj7/41823 \
-H "Authorization: Bearer $RUNNEV_API_KEY" \
-d '{"events":[{"type":"order.paid","id":"o_5521"}]}'{"stream_id":"cBczepiZSW8GJaCae0xIj7","seq":41823,"accepted":1,"cursor":41823,"duplicate":false}Extra response header: x-runnev-cursor: 41823. A repeat of a stored
sequence returns 200 with "duplicate": true.
Errors: 413 payload_too_large,
422 sequence_too_far_ahead, 409 invalid_sequence,
415 unsupported_media_type, 429 rate_limited.
Append at the next sequence, chosen by the server. Not idempotent unless you send
an Idempotency-Key header. Same body and limits as above.
{"stream_id":"cBczepiZSW8GJaCae0xIj7","seq":41824,"accepted":1,"cursor":41824,"duplicate":false}{"cursor":41823,"updated_at":"2026-08-04T11:02:13.418Z"}Fetch a single batch by sequence. For json streams the response is
the batch object; for raw streams it is the stored bytes with their
original content type.
{"seq":41823,"ts":"2026-08-04T11:02:13.418Z","events":[{"type":"order.paid","id":"o_5521"}]}Errors: 404 stream_not_found or a 404
when the sequence has been evicted or never existed.
Forward compatibility
Unknown query parameters are ignored on every endpoint. Appending, say,
?trace=abc&shard=3 to any Runnev URL changes nothing about how the
request is handled. This is a permanent guarantee so that clients can safely add their
own tracing, sharding, or cache-busting parameters; new API behaviour is always
introduced through parameters we define, and never by making a previously ignored
parameter into an error.