Everything the dashboard does goes through a JSON API under /api/v1. This page covers authentication, errors and every route; the field-level reference is docs/api.md in the repository.
Basics
Base path /api/v1; JSON in and out (Content-Type: application/json).
Request bodies are limited to 16 MiB (1 MiB on some account routes, 64 MiB for webhook ingest).
Durations are strings such as "30s"; times are RFC 3339.
Secrets are never returned: they come back as "••••••", and sending the mask back keeps the stored value.
Types are defined in internal/model (Task, Status, TaskView, Connector, Destination, DLQEntry, LogEntry, Schema) and internal/diff (Report, SchemaReport).
Authentication
Method
Use
Session cookie cdc_session
Created by POST /auth/login, /auth/setup or /auth/invite/accept. Valid 7 days, sliding. Cookie-authenticated writes must send an Origin (or Referer) matching the host (CSRF protection); browsers do it automatically.
Bearer token
Authorization: Bearer $CDC_ADMIN_TOKEN: the static admin token, acting as an admin named "API token". GET /events also accepts ?token=.
Webhook signature
Only for POST /ingest/{id} on webhook tasks with a signing secret; see Webhook.
MCP tokens (cdcmcp_…) authenticate only at /mcp, not at the REST API. The role each route needs is listed in the permission matrix.
TOKEN=$CDC_ADMIN_TOKEN
CDC=https://cdc.example.com
curl -s -H "Authorization: Bearer $TOKEN" "$CDC/api/v1/tasks" | jq '.[] | {id, state: .status.state}'
# Or sign in and keep the cookie (send Origin on writes)
curl -s -c jar -H 'Content-Type: application/json' -H "Origin: $CDC" \
-d '{"email":"you@example.com","password":"…"}' "$CDC/api/v1/auth/login"
curl -s -b jar "$CDC/api/v1/auth/me"
Errors
Errors are JSON: {"error": "message"}, with details (a list of messages) for validation errors and code when Meilisearch reported the error.
Not authenticated ({"error":"authentication required"}), or an invalid webhook signature.
403
Role too low ({"error":"requires role moderator"}), owner protection, or cross-origin request refused.
404
Unknown task, connector, destination, index or route.
409
Conflict: duplicate id, a resource still in use, a running task writing to an index you delete, a primary key mismatch, a diff already running, single-instance mode, the last admin.
422
Validation failed; details lists every problem, for example ["name is required", "index.uid is required and may only contain a-z A-Z 0-9 - _"].
429
Too many failed sign-ins; see the Retry-After header.
4xx from Meilisearch
Passed through with Meilisearch's message and code (index and instance routes).
503, 504
Webhook ingest: task not running, or confirmation took longer than 60 s.
The last Report: status, counts, missing, extra, mismatched, inSync, samples, and repair counts when it repaired.
POST /tasks/{id}/diff/repair
{"missing":true,"mismatched":true,"extra":false} → 202 {"status":"running"}; poll GET /tasks/{id}/diff for the result. (docs/api.md describes a synchronous {"upserted","deleted"} response; the server runs it in the background.)