Guides
HTTP API
For a web app or desktop frontend, run oceanln-httpd instead of shelling out to the CLI.
It's a thin loopback HTTP transport over the same oceanln-common core, so a UI can drive payout / offer / init over 127.0.0.1.
Run the server
oceanln-httpd --seed-file ./seed.txt --allow-origin http://localhost:5173
# oceanln-httpd listening on http://127.0.0.1:7762
# bearer token: <64 hex chars> # printed once unless you pass --token The seed never crosses the HTTP boundary: the server reads the 24 words from --seed-file per request, signs in-process, and never echoes them back. Seed generation stays a human-witnessed CLI operation and is deliberately not exposed over HTTP.
Security model
Because a browser is a supported client, the loopback port is guarded:
- binds a loopback address only (refuses a routable
--bind); - requires
Authorization: Bearer <token>on every endpoint except/health(token auto-generated and printed, or set with--token); - enforces an Origin allowlist (
--allow-origin, repeatable) — blocks cross-origin browser calls and DNS-rebinding; - validates the
Hostheader is loopback; - the Lexe sidecar URL/credentials are server-side config (
--sidecar-url/--sidecar-credentials), never taken from a request body (no SSRF).
oceanln-httpd --seed-file ./seed.txt \
--sidecar-url http://127.0.0.1:5393 --sidecar-credentials <token> Endpoints
All JSON; all but /health need the bearer token.
| Method + path | Body | Returns |
|---|---|---|
GET /health | — | {"status":"ok"} |
POST /generate | — | {mnemonic, mining_address} |
POST /import | {mnemonic, force?} | {mining_address} |
POST /payout | {message, offer?, description?, min_amount?, path?} | {address, offer, message, signature} |
POST /offer | {description?, min_amount?} | {offer} |
POST /init | {path?} | {mining_address, provisioned} |
/generate and /import are the deliberate exceptions to "the seed never
crosses the wire": /generate creates a fresh phrase, persists it, and reveals it exactly once so the user can back it up; /import accepts an existing
phrase. Both refuse with 409 if a seed file already exists. Replacing a wallet must go
through /import with {"force":true}.
Example: sign for an existing offer
/payout mirrors the CLI: pass offer to sign for an existing offer fully
offline (it must be embedded in message), or omit it to have the configured sidecar create
one first.
curl -s http://127.0.0.1:7762/payout \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"message":"<exact OCEAN message embedding the offer>","offer":"lno1..."}'