HTTP API reference
The stoka API surface is small. Every route is either:
- Paid — returns 402 first, expects a signed
X-PAYMENTretry. - Wallet-signed — free, but requires an
Authorization: Stellar …header computed from a server-issued challenge. - Public — no payment, no auth; safe to poll.
Base URLs
| Env | Base URL |
|---|---|
| Mainnet | https://api.stoka.space |
| Testnet | https://test.api.stoka.space |
Routes
GET /.well-known/stoka.json
Public. Manifest: service identity, pricing table, x402 configuration, feature flags. Used by the client libraries for automatic discovery.
POST /v1/store
Paid. Create a new blob. Headers:
| Header | Required | Purpose |
|---|---|---|
X-Stoka-Key | yes | Key under which the blob is stored. |
X-Stoka-TTL-Seconds | no | Lifetime in seconds. Default: 30 days. Clamped to server minimum (1 hour) and maximum (90 days). |
Content-Type | yes | application/octet-stream. |
X-PAYMENT | yes (retry) | Base64 x402 payment header from the 402 challenge. |
Response: 201 with JSON (owner_pubkey, key, expires_at, ttl_seconds, charged_atomic).
PUT /v1/object/{key}
Paid. Overwrite a blob owned by the signing wallet. 404 if the key is not yours. Same headers as POST /v1/store minus X-Stoka-Key.
GET /v1/retrieve/{key}
Paid. Fetch a blob. Headers:
| Header | Required | Purpose |
|---|---|---|
X-Stoka-Owner | no | Hints the owner so the 402 price is exact. Defaults to caller's wallet. |
X-PAYMENT | yes (retry) | Base64 x402 payment header. |
Response: 200 with the raw bytes and headers:
X-Stoka-Owner-Pubkey— G-address of the blob ownerX-Stoka-Expires-At— RFC 3339 timestamp
DELETE /v1/object/{key}
Wallet-signed. Free. Idempotent: deleting a missing or non-owned key still returns 204. Headers:
| Header | Required | Purpose |
|---|---|---|
Authorization | yes | Stellar <G-addr>:<challenge-id>:<hex-sig> |
POST /v1/auth/challenge
Public. Request a single-use message to sign for a given audience (delete, usage, profile). Body:
{ "audience": "delete" }Response: { "challenge_id": "…", "message": "…" }. The message is what you sign with your wallet's Ed25519 key (hex-encoded signature).
GET /v1/me/usage
Wallet-signed. Free. Returns per-UTC-day USDC spend counters for the signing wallet. Query param days=N (clamped 1..90).
Response shapes
- Paid success — the route's native body (JSON for writes, raw bytes for
retrieve). - 402 challenge —
{ x402Version, accepts: PaymentRequirements[], error? }. Auto-paying clients readaccepts[0]and retry. - Non-2xx —
{ "error": "…" }for server-generated errors. Facilitator / RPC errors from the payment flow come back as a second 402 with an informativeerrorstring.
Error codes the clients surface
| Client symbol | HTTP status | Meaning |
|---|---|---|
StokaError(400) | 400 | Malformed request (bad key, missing header). |
StokaError(404) | 404 | Key not found or not owned. |
StokaError(5xx) | 5xx | Server issue; retry with backoff. |
PaymentRequired | 402 | Auto-pay failed: no signer, unfunded wallet, missing trustline, unknown asset. |