InfiniteOcean.io

Append-only event routing for everyone

Post events. Stream them in realtime.
No signup. No database. Cryptographic keys are identity.

One endpoint Free Open CORS SSE + JSON 3 dependencies

Concepts

Drop

An immutable event. Has a hierarchical route like app/user-123/logs, a payload (any string), and a source key. Stored forever as a JSON file.

Stream

An ephemeral view over a route prefix. Materializes on demand, replays history from disk, delivers new drops in realtime via SSE, evaporates when idle.

Route

Hierarchical path like deploy/prod/eu. Wildcards at the end: deploy/* catches everything below. The route is the filesystem path.

Key

Ed25519 keypair. Auto-generated on first request if you don't provide one. Your public key is your identity. No accounts, no signup.

Base URL

https://api.infiniteocean.io    # CORS: * — call from anywhere

API

POST /drop Write an event
# Post a drop
curl -X POST https://api.infiniteocean.io/drop \
  -H "Content-Type: application/json" \
  -H "X-Ocean-Key: YOUR_PUBLIC_KEY" \
  -d '{
    "route": "myapp/events/signup",
    "payload": "user signed up",
    "keep": 86400
  }'
FieldDescription
routeHierarchical path. No wildcards. 1-10 segments. a-z A-Z 0-9 - _ .
payloadAny string up to 1MB. Encrypt client-side if needed.
keepOptional. Seconds until auto-delete. Omit for permanent.
signatureOptional. Reserved for future signature verification.

Header: X-Ocean-Key — your public key. Omit it and a keypair is auto-generated and returned once. Save the private key.

// Response (200 with key, 201 without — includes generated keypair)
{
  "drop_id": "a1b2c3d4-...",
  "route": "myapp/events/signup",
  "source": "base64-public-key",
  "created_at": "2026-02-06T12:00:00.000Z",
  "keypair": {                          // only if no key was sent
    "public": "base64-ed25519-public",
    "private": "base64-ed25519-private"  // save this!
  }
}
GET /stream/:prefix Replay + realtime
# Stream live (SSE)
curl -N https://api.infiniteocean.io/stream/myapp/*?last=100

# Pull as JSON
curl https://api.infiniteocean.io/stream/myapp/*?last=50 \
  -H "Accept: application/json"

Prefix examples:

PrefixMatches
myapp/*Everything under myapp/
myapp/events/*All events for myapp
myapp/events/signupExact route only
*Everything (use with caution)

Query params:

ParamDescription
last=NReturn last N matching drops, then go live
from=0Replay all history, then go live
from=<ISO>Replay from timestamp, then go live
from=latestLive only, no replay (default)
limit=NClose connection after N drops (pull mode)

SSE stream:

data: {"drop_id":"...","route":"...","payload":"...","created_at":"..."}

data: {"drop_id":"...","route":"...","payload":"...","created_at":"..."}

event: caught-up
data: {"timestamp":"...","replayed":2}

data: {"drop_id":"...","route":"...","payload":"...","created_at":"..."}  ← live

JSON pull (send Accept: application/json):

{
  "drops": [...],
  "cursor": "2026-02-06T12:00:03.000Z",
  "has_more": true
}
GET /health Server status

Try it live

Hit the API from this page

These buttons call the real API. Open your browser console to see the requests.

// Click a button above...

JavaScript — 30 seconds

// Post a drop
const res = await fetch("https://api.infiniteocean.io/drop", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    route: "myapp/events/click",
    payload: JSON.stringify({ button: "signup", ts: Date.now() })
  })
});
const drop = await res.json();
console.log(drop.source);  // your auto-generated public key

// Listen for realtime events
const events = new EventSource(
  "https://api.infiniteocean.io/stream/myapp/*?last=10"
);
events.onmessage = (e) => {
  const drop = JSON.parse(e.data);
  console.log(drop.route, drop.payload);
};
events.addEventListener("caught-up", () => {
  console.log("history replayed, now live");
});

curl — quick start

# 1. Post your first drop (keypair auto-generated)
curl -X POST https://api.infiniteocean.io/drop \
  -H "Content-Type: application/json" \
  -d '{"route":"hello/world","payload":"hi"}'

# 2. Stream everything under hello/ (SSE, live)
curl -N https://api.infiniteocean.io/stream/hello/*?from=0

# 3. Pull last 5 as JSON
curl https://api.infiniteocean.io/stream/hello/*?last=5 \
  -H "Accept: application/json"

What people build with it

Webhooks & events

Route: deploy/myapp/prod. Push deploys, errors, alerts. Stream them from anywhere.

IoT data streams

Route: sensor/building-3/floor-2. Append readings. Replay history. No database needed.

Agent-to-agent comms

Route: agent/task-abc/result. AI agents post structured results. Others listen.

Audit logs

Route: org/acme/audit. Immutable, append-only, replayable. Inspect files with cat.

Error codes

SituationCodeStatus
Missing route on POST /dropROUTE_REQUIRED400
Invalid route formatINVALID_ROUTE400
Invalid stream prefixINVALID_PREFIX400
Payload over 1MBPAYLOAD_TOO_LARGE413
Rate limitedRATE_LIMITED429
Server errorINTERNAL_ERROR500

How it works

POST /drop { route: "app/events/click" }
  → validate route
  → atomic file write: ocean/app/events/click/{ts}-{id}.json
  → append to 3 manifest indexes (leaf, segment, root)
  → Redis PUBLISH to ocean:route:app
  → return drop_id

GET /stream/app/*?last=50
  → read ocean/app/.manifest
  → binary search → last 50 entries
  → read files, stream as SSE
  → send caught-up
  → subscribe to Redis ocean:route:app
  → live: new drops arrive → trie match → push to client

No listeners for 5 minutes?
  → net evaporates from memory
  → next request rebuilds from manifest
  → zero permanent state beyond files on disk