Every request that sends a body uses Content-Type: application/json; every authenticated request carries one Authorization header. /healthz, /readyz, and /metrics are always open. With no auth configured at all (local dev), the API is open.
| Project API key recommended for services | Created in the portal under a project (vk_… + vs_… secret, shown once). Authorization: Bearer <key>:<secret> (or headers x-api-key / x-api-secret). The key is pinned to its project: every name resolves inside it, other projects are unreachable, and the admin surface is refused. |
| Static token VARISAI_TOKENS | Configured server-side as token:scope+scope. Scopes: read (all GETs — any valid token has it), publish, consume, manage (create/change streams, subscriptions, projects, keys; redrive, seek, pause), admin (implies everything). Authorization: Bearer <token>. |
| Dashboard session people | Browser calls carry the sign-in cookie. What a person can do is their team role's policy — the same five permissions, assigned on Admin → Team. A 403 names the missing permission and the caller's role. |
# Auth: create an API key under your project in the portal, then
AUTH='Authorization: Bearer vk_yourkey:vs_yoursecret' # omit on an open dev instance
# 1. a subscription with a declared retry policy (project comes from the key)
curl -X POST localhost:7700/v1/subscriptions -H "$AUTH" -d '{
"name": "billing-worker", "stream": "orders",
"retry": { "max_attempts": 5, "strategy": "exponential_jitter",
"initial_backoff": "10s", "max_backoff": "1h" }
}'
# 2. publish — the stream is created implicitly in your project
# (same key = strict order; different keys = full parallelism)
curl -X POST localhost:7700/v1/streams/orders/messages -H "$AUTH" \
-d '{"key":"tenant_42","payload":{"order_id":8891},"idempotency_key":"order-8891"}'
# 3. consume: lease -> work -> ack (or nack, and the retry policy takes over)
curl -X POST localhost:7700/v1/subscriptions/billing-worker/receive -H "$AUTH" \
-d '{"max_messages":10,"wait_seconds":20,"consumer":"worker-1"}'
curl -X POST localhost:7700/v1/subscriptions/billing-worker/ack -H "$AUTH" \
-d '{"delivery_ids":["dlv_..."]}'
# Without an API key, name the project explicitly:
curl -X POST 'localhost:7700/v1/streams/orders/messages?project=payments' -d '...'Prefer a client? The zero-dependency Node SDK (sdk/js) wraps all of this — new Varisai({ project: "payments" }) scopes every call, and its consume loop makes resolve = ack, throw = nack.
The message envelope — what GETs, receive, and traces return for a message:
{
"id": "msg_1m1b9kb5qvvcqn0tc334f",
"stream": "orders", "project": "payments",
"key": "tenant_42",
"payload": { "order_id": 8891 },
"headers": { "region": "in" },
"idempotency_key": "order-8891-created",
"deliver_at": null, "expires_at": null,
"published_at": "2026-08-31T10:15:00.000Z",
"offset": 41, "status": "available"
}| Streams scope: manage · reads: read | Create, configure, browse, and delete streams — named durable logs with per-stream retention and backlog caps. |
| Publish scope: publish | Publish messages one at a time or in ordered batches, with idempotency keys, headers, scheduled delivery, and expiry. |
| Consume scope: consume | Long-poll receive with per-message leases, ack, nack, and lease extension — per-key ordering enforced broker-side. |
| Subscriptions scope: manage · reads: read | Declare retry policy, rate limits, filters, and push delivery on the subscription — no retry or DLQ code in consumers. |
| Failed messages (DLQ) scope: manage · reads: read | Browse dead letters grouped by error signature, redrive them back to the queue, or discard them for good. |
| Introspection scope: read | Trace any message's full lifecycle, inspect per-key lanes, scheduled messages, retries, and node-wide stats. |
| Operations scope: manage | Operational verbs: skip a poison message, fire backing-off retries immediately, deliver a scheduled message now. |
| Projects & API keys scope: manage · reads: read | Projects namespace your streams and subscriptions; project API keys are pinned to their project and can never leave it. |
| Admin: team, roles, system scope: admin — dashboard sessions only; API keys are refused here | Team members, role policies, effective configuration, and the audit log — dashboard sessions only. |
Every error, on every endpoint, is the same shape with a meaningful status code:
{ "error": "a stream named orders already exists in project payments" }| 400 | Malformed request — the message names the field and the accepted values |
| 401 | No credentials, or an unknown API key / wrong secret |
| 403 | Authenticated but not allowed: missing scope/permission, or an API key reaching outside its project |
| 404 | No such stream / subscription / message / project in that scope |
| 409 | Conflict: the name already exists, or the state no longer allows the action |
| 413 | Payload over MAX_MESSAGE_BYTES (default 1 MB) |
| 429 | Backpressure: the stream's undelivered backlog crossed its cap — back off and retry |
| 503 | The broker could not reach MongoDB (readyz fails too) |