Post events. Stream them in realtime.
No signup. No database. Cryptographic keys are identity.
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.
An ephemeral view over a route prefix. Materializes on demand, replays history from disk, delivers new drops in realtime via SSE, evaporates when idle.
Hierarchical path like deploy/prod/eu. Wildcards at the end: deploy/* catches everything below. The route is the filesystem path.
Ed25519 keypair. Auto-generated on first request if you don't provide one. Your public key is your identity. No accounts, no signup.
https://api.infiniteocean.io # CORS: * — call from anywhere
# 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 }'
| Field | Description |
|---|---|
| route | Hierarchical path. No wildcards. 1-10 segments. a-z A-Z 0-9 - _ . |
| payload | Any string up to 1MB. Encrypt client-side if needed. |
| keep | Optional. Seconds until auto-delete. Omit for permanent. |
| signature | Optional. 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! } }
# 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:
| Prefix | Matches |
|---|---|
| myapp/* | Everything under myapp/ |
| myapp/events/* | All events for myapp |
| myapp/events/signup | Exact route only |
| * | Everything (use with caution) |
Query params:
| Param | Description |
|---|---|
| last=N | Return last N matching drops, then go live |
| from=0 | Replay all history, then go live |
| from=<ISO> | Replay from timestamp, then go live |
| from=latest | Live only, no replay (default) |
| limit=N | Close 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
}
These buttons call the real API. Open your browser console to see the requests.
// Click a button above...
// 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"); });
# 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"
Route: deploy/myapp/prod. Push deploys, errors, alerts. Stream them from anywhere.
Route: sensor/building-3/floor-2. Append readings. Replay history. No database needed.
Route: agent/task-abc/result. AI agents post structured results. Others listen.
Route: org/acme/audit. Immutable, append-only, replayable. Inspect files with cat.
| Situation | Code | Status |
|---|---|---|
| Missing route on POST /drop | ROUTE_REQUIRED | 400 |
| Invalid route format | INVALID_ROUTE | 400 |
| Invalid stream prefix | INVALID_PREFIX | 400 |
| Payload over 1MB | PAYLOAD_TOO_LARGE | 413 |
| Rate limited | RATE_LIMITED | 429 |
| Server error | INTERNAL_ERROR | 500 |
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