Concepts
The building blocks shared by every endpoint and SDK.
Authentication
Send your key on every request as the X-API-Key header (or Authorization: Bearer nv_… — both work):
curl https://api.niravi.io/api/v1/videos -H "X-API-Key: nv_..."
Keys are created and revoked in the dashboard → Settings → Developer. They are stored hashed; the plaintext is shown only once at creation.
Workspaces & scopes
A key is bound to one workspace at creation. Every call it makes is automatically scoped to that workspace’s corpus — you never pass a workspace id, and a key can’t reach another workspace’s data.
Each key carries scopes:
| Scope | Grants |
|---|---|
read | Search, recall, chat, and all read endpoints |
write | Upload and re-processing endpoints |
Calling a write endpoint with a read-only key returns 403.
The response envelope
Every response is a consistent envelope.
// success
{ "success": true, "data": { /* ... */ }, "meta": { /* request id, timing */ } }
// list (paginated)
{ "success": true, "data": [ /* ... */ ], "pagination": { "limit": 50, "offset": 0, "total": 1280, "has_more": true } }
// error
{ "success": false, "error": { "code": "forbidden", "message": "…", "status": 403 } }
The SDKs unwrap data for you and surface pagination/errors as language-native types.
Pagination
List endpoints (e.g. GET /videos) take limit (max 200) and offset, and return a pagination object with has_more. To page through everything, advance offset by the number of items until has_more is false — or let an SDK do it:
videos = client.videos(all_pages=True) # follows the cursor for you
const videos = await niravi.videos({ allPages: true });
Errors
Failures use standard HTTP status codes; the SDKs raise typed errors:
| Status | Meaning | SDK error |
|---|---|---|
| 401 / 403 | Missing/invalid key, or scope/workspace denied | AuthError |
| 404 | Resource not found | NotFoundError |
| 422 | Invalid request body | ValidationError |
| 429 | Rate limited (see Retry-After) | RateLimitError |
| 5xx | Server error | ServerError |
Rate limits
Responses carry X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers; the SDKs parse them into client.rate_limit / niravi.rateLimit after each call. On 429 the SDKs retry automatically with backoff that honours Retry-After.