Aurabase Logo
aurabasedocs
docs›Reference›REST API

REST API — Overview

Aurabase raw HTTP surface. Compatible with all languages. Base URL, authentication, response format, error codes — then details by endpoint in /docs/api/.

7 min read·Level reference·Revised on Apr 15, 2026
This English text was generated automatically from the French original and has not been reviewed yet.
#
URL

An origin, the project on the way

There is no domain per project. All traffic goes through a single origin — that of the gateway — and the project is identified by its UUID in the path. The gateway exposes two plans: the data plan (SDK and applications, :8080 locally) and the management plan (Studio and administration, :8090). The given plane surfaces are prefixed /v1/db, /v1/auth, /v1/storage, /v1/realtime, /v1/functions, /v1/notifications, /v1/ai.

exemplesbash
# AURA_URL = origin of the gateway, data plan (e.g. http://localhost:8080)
# PROJECT_ID = Project UUID

GET   $AURA_URL/v1/db/$PROJECT_ID/sensors
POST  $AURA_URL/v1/auth/$PROJECT_ID/login
GET   $AURA_URL/v1/storage/$PROJECT_ID/avatars/u_xx/file.png
POST  $AURA_URL/v1/functions/$PROJECT_ID/ocr/invoke
Attention

Two exceptions to the /v1/<service>/{project_id} pattern: the streaming routes /v1/realtime/ws and /v1/realtime/sse do not have project_id in the path — it is inferred from the query parameter ?project_id= or the prefix of ?channel={project_id}:{topic}. A URL without an identifiable project is rejected as 400 (“project_id (UUID) not found in URL to validate API key”).

#
Auth

Two keys, one JWT

  • anon_key — publishable. Serves as the API key for any request. Header apikey, X-API-Key, or parameter ?apikey= — the latter is only accepted on real-time streams (/ws, /sse, /chat/stream); elsewhere it is explicitly refused.
  • service_role_key — secret, RLS bypass. Reserved for the backend.
  • user_jwt — issued by POST /v1/auth/{project_id}/login after authentication. Header Authorization: Bearer.
headers.shbash
# Anonymous customer (guest)
-H "apikey: <ANON_KEY>"

# Authenticated client (claims user)
-H "apikey: <ANON_KEY>"
-H "Authorization: Bearer <USER_JWT>"

# Backend (RLS bypass)
-H "apikey: <SERVICE_ROLE_KEY>"
-H "Authorization: Bearer <SERVICE_ROLE_KEY>"
#
Headers

Standards applied

  • Content-Type: application/json — required on POST/PATCH/PUT (except upload storage, in multipart/form-data)
  • Prefer: return=representation — returns the lines created/modified; return=minimal for a response without a body (204). Prefer: count=exact is read on aura-db mutations (headers Content-Range + Preference-Applied); To rely on a reading, use the ?count=exact parameter
  • Range: 0-49 — only on a Postgres project served by PostgREST, which interprets it itself. The aura-db path (MongoDB project, or Postgres with PostgREST disabled) ignores this header: it only reads limit and offset. Prefer limit/offset, which work on both engines
  • Idempotency-Key — is NOT read on Database (POST /v1/db/…) writes: two identical POSTs create two lines. It is only honored by POST /v1/notifications/{project_id}/send (and /send/batch), and by the creation of the management plan API key (POST /v1/db/{project_id}/api-keys, 24-hour window)
pagination.shbash
# Only portable form — works on both engines
GET $AURA_URL/v1/db/$PROJECT_ID/sensors?order=id.asc&limit=50&offset=100

# Keyset “by hand”: filter on the last key read
GET $AURA_URL/v1/db/$PROJECT_ID/sensors?id=gt.{last_id}&order=id.asc&limit=50

# ?cursor=: aura-db ONLY (MongoDB, or Postgres without PostgREST).
# On PostgREST the request is refused in 400.
GET $AURA_URL/v1/db/$PROJECT_ID/sensors?cursor={meta.next_cursor}&limit=50
Astuce

Without limit, a read returns at most 1000 lines — this is both the default and the hard ceiling. The actually applied limit is returned in meta.per_page, never guessed.

Attention

The total is not read in the same place depending on the engine: on the aura-db path, the response carries the header Content-Range: items 100-149/1247 (the total is worth * if no count was requested); on the PostgREST path, the gateway does not relay this header and places the total in meta.total of the JSON envelope. Counting is never done by default: request it with the parameter ?count=exact (portable form, translated into Prefer by the gateway on the PostgREST path) or ?count=estimated.

#
Errors

Uniform format

error is always an object, never a string. Two variants, depending on the issuer - the fields code and message are common to both, and it is on code (never on message, free text) that we discriminate.

error emitted by an Aurabase servicejson
{
  "error": {
    "type": "auth_unauthorized",      // machine type, prefixed by domain
    "code": "UNAUTHORIZED",         // stable code
    "message": "Non autorisé : Clé API invalide ou révoquée",
    "request_id": "dc20e246-d8e0-412c-b9d7-ce675af6edd5"
  }
}
PostgREST error translated by the gatewayjson
{
  "error": {
    "code": "COLUMN_NOT_FOUND",    // never the raw PGRST code
    "message": "Column unknown_col not found in table sensors",
    "details": ""
  }
}
Attention

PostgREST/PostgreSQL codes (PGRST116, 23505…) are never returned as is: the gateway translates them into Aurabase codes (RECORD_NOT_FOUND, NOT_SINGULAR, COLUMN_NOT_FOUND, NO_RELATIONSHIP, SCHEMA_NOT_FOUND, DUPLICATE_KEY, FOREIGN_KEY_VIOLATION, TABLE_NOT_FOUND, INSUFFICIENT_PRIVILEGE, otherwise POSTGREST_ERROR). This variant bears neither type nor request_id; there is no hint nor trace_idfield.

CodeNameDescription

400Invalid Bad RequestPayload or malformed query. error.code = BAD_REQUEST.

401Unauthorizedapikey missing/revoked or invalid JWT. error.code = UNAUTHORIZED (or REFRESH_TOKEN_REJECTED on /refresh).

403ForbiddenRLS or authorization service refuses the operation. error.code = FORBIDDEN, QUOTA_EXCEEDED, or INSUFFICIENT_PRIVILEGE (PostgREST path).

404Not FoundResource nonexistent or invisible by RLS. error.code = NOT_FOUND, RECORD_NOT_FOUND or TABLE_NOT_FOUND.

406Not Acceptable Single line expected, multiple returned. error.code = NOT_SINGULAR.

409ConflictSingle constraint violation or FK. error.code = CONFLICT, DUPLICATE_KEY, FOREIGN_KEY_VIOLATION. Use on_conflict for upsert.

413Payload Too LargeRequest > MAX_BODY_SIZE (default 50 MB on the gateway side). Use multipart storage upload.

429Too Many RequestsRate limit reached. X-RateLimit-Limit / X-RateLimit-Remaining headers; Retry-After on gateway refusals.

500Internal ErrorServer error. error.request_id to provide to support.

503Service UnavailableCircuit breaker open, instance missing, or hibernated project (Retry-After: 5 in the latter case). Recovery breaker after 30 s.

504Gateway TimeoutTimeout upstream. error.code = TIMEOUT.

#
Rate limit

By IP at the gateway, plus limits per route

  • Gateway, all routes: per IP, 100 req/s with a burst of 1000 (adjustable via RATE_LIMIT_RPS / RATE_LIMIT_BURST). There is no separate tier per role.
  • Auth sensitive (login, register, forgot-password, magic-link, email-otp/send, sms/send, refresh, mfa/verify-login): 5 req/min per IP, burst 3. In addition, a quota per project: 30 connection attempts/hour per IP by default, adjustable in the project settings.
  • Raw SQL (/raw): 30 req/min, burst 10. IA: 10 req/min, burst 5.
Attention

Overflow → 429 Too Many Requests with the headers X-RateLimit-Limit and X-RateLimit-Remaining (present on any response from the gateway), plus X-RateLimit-Reset and Retry-After on the refusal.

#
Endpoints

Complete tree per service

Each endpoint has its dedicated page with parameters, response codes, examples in 5 languages and live rail code.

DatabaseAuthStorageRealtimeFunctions

Last updated · Apr 15, 2026