Backend API (Django Ninja)
Backend API (Django Ninja)
Source of truth: backend/config/api.py.
Router Layout
AppNinjaAPI is mounted at /api/v1/ in backend/config/urls.py.
Key endpoints:
- OpenAPI schema:
/api/v1/openapi.json - OpenAPI schema (merged with allauth headless paths, for reference):
/api/v1/openapi-merged.json - Human docs:
/api/v1/docs/(template atbackend/templates/pages/api_docs.html)
Routers are added explicitly in backend/config/api.py, for example:
/billing/->backend/apps/payments/api/billing.py/workspaces/->backend/apps/tenants/api/workspaces.py/ai/chat/->backend/apps/ai/api.py
JSON Shape (camelCase In/Out)
Requests:
- The API parser decamelizes JSON request bodies (
ORJSONParserinbackend/config/api.py), so clients can sendcamelCaseand backend code can keepsnake_case.
Responses:
- Many response schemas use
BASE_MODEL_CONFIG(backend/apps/common/schema.py) so fields serialize ascamelCase. - Many endpoints pass
by_alias=Trueso aliases are used in output.
Auth On The Ninja API
Ninja API auth is configured as a list in backend/config/api.py:
django_auth(cookie-based browser sessions)headless_x_session_token_auth(header-based session token for non-cookie clients)
The frontend sends cookies plus X-Session-Token by default via Axios interceptors (frontend/lib/api-client.ts).
Error Handling
backend/config/api.py registers exception handlers for:
- ORM lookups (
ObjectDoesNotExist,Http404) - auth/permission errors (
AuthenticationError,PermissionDenied) - validation (
django.core.exceptions.ValidationError, Pydantic validation)
This is the place to look if the frontend sees unexpected error shapes.
Adding A New Endpoint (Pattern)
- Add/update a router under the relevant app.
- Define request/response schemas in that app (convention varies: many apps use
schema.py, some useschemas.py). - Mount the router in
backend/config/api.pyviaapi.add_router(...). - Regenerate frontend hooks if needed:
make create_spec.
Implementation tip:
- Prefer small routers with thin endpoints.
- Put business logic in model methods or
services/modules.
OpenAPI Operation IDs
AppNinjaAPI.get_openapi_operation_id() generates operation IDs based on router tag + function name. This impacts Orval hook names.
Last updated June 21, 2026