Skip to content

REST API

The REST contract is Conjure's public API — the frontend talks to it 1:1, and it follows SemVer. The base path is whatever you mounted (path("conjure/", include("conjure.urls"))); examples below assume /conjure/.

Stable contract

The URL shapes and query parameters on this page are a frozen contract between backend and frontend. Breaking changes to them are major-version changes.

Schema (introspection)

GET /conjure/schema/                  # all registered models
GET /conjure/schema/{app}.{Model}/    # one model

Returns field metadata (types, choices, FK targets, inlines), per-model permissions for the current user, and — once the actions system ships — the user's allowed_actions. Both codegen and runtime modes read this.

Generic CRUD

A single generic viewset serves every registered model under a {app}.{Model} key:

Method & path Action
GET /conjure/r/{app}.{Model}/ List (paginated, filtered, sorted).
POST /conjure/r/{app}.{Model}/ Create.
GET /conjure/r/{app}.{Model}/{pk}/ Retrieve one.
PATCH /conjure/r/{app}.{Model}/{pk}/ Partial update.
DELETE /conjure/r/{app}.{Model}/{pk}/ Delete.
GET /conjure/r/{app}.{Model}/autocomplete/?q=&page= FK search (combobox).
POST /conjure/r/{app}.{Model}/bulk/ Bulk + atomic inline operations.
GET /conjure/r/{app}.{Model}/{pk}/related/ Count objects a delete would affect.
POST /conjure/r/{app}.{Model}/action/{key}/ Run an action. 📋

The {pk} converter adapts to the model's PK type (int, UUID, or string) automatically.

List query parameters

Parameter Meaning
page 1-based page number.
page_size Rows per page (capped by MAX_PAGE_SIZE).
ordering Sort field; - prefix for descending.
search Full-text-ish search across the config's search_fields.
{field}={value} Exact-match filter on a field.
{field}__gte=, {field}__lte= Range filters (dates, numbers).
curl -s "http://localhost:8000/conjure/r/order.Order/?status=paid&ordering=-created_at&page_size=20"

Serialized rows

The dynamic serializer adds display helpers so the frontend renders labels without extra round-trips: a top-level _label, {fk}_label for each foreign key, and {field}_display for fields with choices.

Bulk

POST /conjure/r/{app}.{Model}/bulk/
body: { "action": "delete" | "update", "ids": [...], "data": { ... } }

Bulk delete / update, and atomic inline saves, run in a single transaction.

Authentication

Send the Django session cookie (and CSRF token for writes). No extra endpoints — if the user is logged in and is_staff, requests are authorized.

POST /conjure/auth/login/      body: { "username": "...", "password": "..." }  -> { access, refresh }
POST /conjure/auth/refresh/    body: { "refresh": "..." }                      -> { access }
GET  /conjure/auth/me/         -> current user payload (see USER_PAYLOAD)

Staff-only. The dashboard's API client stores the token and refreshes on 401 automatically.

Permissions

Every endpoint is gated by is_staff, then by the matching Django model permission (view_* / add_* / change_* / delete_*); superusers pass everything. This is the same permission data Django admin uses — see Migrating from Django admin.

Widgets

GET /conjure/widgets/{name}/    # built-in: recent-audit, model-counts — add your own with @register_widget

Dashboard data sources, registered via @register_widget. See Extension points.

Auto-generated OpenAPI

Planned generator

📋 A future docs generator (gen/gen_openapi.py) will embed the live OpenAPI schema (via drf-spectacular) so this page is generated from the running API rather than maintained by hand. See the generators README.