Information
- License: Source First License 1.1
- OpenAPI version:
3.1.0
Control plane REST API for opdns profiles, accounts and tokens.
The dashboard is the first client; there are no private endpoints.
Authentication: a session cookie (opdns_session, set by POST /v1/auth/login)
or an API token sent as Authorization: Bearer opdns_.... Tokens carry scopes
(profiles:read, profiles:write, account:read, logs:read, analytics:read);
sessions have every scope. The admin scope (operator routes under /v1/admin)
exists only for accounts flagged as operators. Cookie-authenticated writes from another origin are
rejected unless the origin is an allowed dashboard origin. The unauthenticated /v1/auth writes
(signup, login, verification, password reset, recovery, passkey login) apply the same check: an
Origin that is present and not allowed answers 403 csrf_rejected; requests without one are unaffected.
CORS: the four public signup surfaces (/v1/auth/signup, /v1/auth/signup-mode,
/v1/waitlist, /v1/waitlist/confirm) allow exact configured origins, their route’s
method and Content-Type only. Eligible preflights answer 204; a rejected origin,
method or header answers 403. Actual responses name the origin and allow credentials.
Other /v1 routes add Access-Control-Expose-Headers: ETag, Retry-After, X-Request-Id,
Content-Disposition, Location for an allowed dashboard origin. Their preflights
answer 204 without authentication; unallowed origins get no CORS headers.
Responses vary on Origin on those routes, and on signup surfaces when Origin is present.
Errors are RFC 9457 problem documents (application/problem+json) with a stable
machine code.
Profile writes are optimistic: every profile resource returns an ETag holding
the profile version, and writes accept If-Match with it (412 on mismatch).
Every write bumps the version and publishes the full profile document to the edge.
Unauthenticated routes are rate limited per client IP (429 with Retry-After).
Lists are cursor-paginated: limit (default 50, at most 200) and cursor (the
next_cursor of the previous page, opaque); next_cursor is null on the last
page. Order is stable, so rows created between pages are never repeated or
skipped before the cursor. A modified cursor is a 400 invalid_cursor.
POSTs that create something take an Idempotency-Key header: a repeat with the
same key and request within 24 h replays the first (2xx) response with
Idempotent-Replayed: true instead of creating again; the key reused with a
different request is a 409 idempotency_key_reused, and a repeat while the first
is still running a 409 idempotency_in_progress. Keys are per account.
Sessions last at most 30 days from sign-in and end after 7 days unused;
the first request more than 24 h after the session token was issued gets a new
token in Set-Cookie (the previous one stays valid for a few seconds).
Credentials: passkeys (WebAuthn) are the primary credential; password
sign-in takes a TOTP code when TOTP is on; ten single-use recovery codes are issued
with the first second factor. Credential changes need a sign-in within the last
five minutes (reauth_required). Emailed links point at the dashboard:
/verify-email?token=, /reset-password?token=, /login, /account/security.
Versioning and deprecation. The path carries the major version: every
route is under /v1, and within /v1 changes are additive only: new endpoints,
new optional request fields, new response fields, new enum values in responses
(clients ignore unknown fields and treat unknown enum values as “other”), new
columns appended to query results. Nothing is renamed, removed, retyped or made
required within /v1; such a change needs /v2, served alongside /v1 until
/v1’s sunset. info.version is this document’s version: it changes with
every change to the document (minor for additions, patch for wording), and
every response carries it in the X-Opdns-Api-Version header (also
api_version in GET /v1/meta). A field or endpoint being retired is marked
deprecated: true here with its replacement; responses that use it carry
Deprecation (RFC 9745: @<unix seconds>, when it was deprecated) and Sunset
(RFC 8594: an HTTP date after which it may be removed, at least 90 days after
the deprecation), so clients can find the calls that must change before they
break.
Security scheme type: apiKey
Cookie parameter name: opdns_session
API token (opdns_...) with scopes.
Security scheme type: http
Node token (opdnsnode_...) from POST /v1/nodes/enrol, for the node-side endpoints.
Security scheme type: http