The Gateway is the single API origin for your org: api.{org}.local. Every SDK call and every nuble command goes through it — it authenticates your API key and forwards the request to the right internal service. You configure it once and then mostly forget it exists.
Get up and running
You don’t write code against the Gateway itself:
- You never call it directly. The SDKs and the CLI construct, authenticate, and route every request for you.
- You need exactly two things: the gateway URL (
http://api.{org}.local) and an API key (nbl_…) issued in the Console when your app was created. - Point everything at the one URL. Each SDK takes the gateway base URL and routes internally:
import { createVaultClient } from "@nublestation/vault";
import { createBlazeClient } from "@nublestation/blaze";
import { createIdentityClient } from "@nublestation/identity";
const vault = createVaultClient({ url: "http://api.clinic.local", apiKey });
const { db } = createBlazeClient({ baseUrl: "http://api.clinic.local", apiKey, schema });
const identity = createIdentityClient({ url: "http://api.clinic.local", identityUrl, app });
The unified @nublestation/client package wraps all three under a single client — see the SDK overview.
Everyday usage
What a request looks like
If you ever inspect traffic (or use curl), every authenticated request carries your API key:
POST http://api.clinic.local/v1/blaze/tasks
Authorization: Bearer nbl_<key_id>.<secret>
How paths map to services
The first segment after /v1/ picks the service:
| Path prefix | Goes to | Auth |
|---|---|---|
/v1/auth/* | Identity | Session cookie (no API key) |
/v1/blaze/* (legacy /v1/db/*) | Blaze | API key |
/v1/vault/* | Vault | API key (+ session cookie for per-user access) |
/v1/orbit/* | Orbit | API key |
/vault/* (top-level) | Vault public files | None — Vault checks is_public |
What gateway errors mean
When the Gateway itself rejects a request (rather than the service behind it):
| Status | Body error | Meaning |
|---|---|---|
401 | unauthorized | API key missing, malformed, wrong secret, revoked, or expired. Always generic — the Gateway never tells you which. |
404 | unknown_service | The path prefix doesn’t match any service. Check the path. |
502 | upstream_unavailable | The internal service didn’t respond. Check container health with nuble server status. |
Any other status code comes from the target service, passed through unchanged.
Checking it’s up
nuble status # pings the gateway for every configured profile
GET /healthz → 200 OK (liveness)
GET /readyz → 200 OK (readiness)
Reference
| Method | Path | One-liner |
|---|---|---|
ALL | /v1/auth/* | Forwarded to Identity verbatim, cookies relayed both ways |
ALL | /v1/blaze/* | Database operations (also accepts legacy /v1/db/*) |
ALL | /v1/vault/* | Authenticated file operations |
ALL | /v1/orbit/* | Deploy and rollback |
GET | /vault/{app_slug}/{collection}/{filename} | Public file fetch, no credentials |
GET | /healthz | Liveness probe |
GET | /readyz | Readiness probe |
Limits & gotchas
- Rate limiting is not shipped yet. Per-app requests-per-minute caps (returning
429) are planned for Phase 6. - 401 is intentionally uninformative. Wrong key, revoked key, and expired key all look identical — by design, to prevent enumeration. If you get a 401, re-check the full
nbl_<key_id>.<secret>string from the Console. - You can’t bypass it. Internal services (Blaze, Vault, Orbit, Identity) have no LAN-exposed ports. Calling them directly from your machine will simply fail to connect.
- One origin, no CORS hell. Everything lives at
api.{org}.local— don’t hardcode per-service URLs anywhere.
Go deeper
How the Gateway resolves keys (Redis cache, Argon2id verification) and how it cryptographically signs forwarded requests is covered in the concepts and security sections: