OpenAPI spec
The machine-readable OpenAPI 3.1 description of the /api/v1 surface — generated from the same schemas the API validates with.
The whole /api/v1 surface is published as an OpenAPI 3.1 document:
https://dodomain.io/docs/openapi.json
It describes every endpoint on the REST API page — request and response bodies, query
parameters, both authentication schemes and their OAuth scopes, and the exact error codes each
endpoint can answer with, including the 429 Retry-After contract.
It is generated, not written
The document is produced from the same zod schemas the request handlers validate with. A CI gate regenerates it on every pull request and fails the build if it differs by a single byte from the committed file, and a second gate fails if any endpoint exists in the code without an entry in the spec. So the spec cannot quietly fall behind the API: either it is current, or the build is red.
Two consequences worth knowing:
- Response objects do not set
additionalProperties: false. We add response fields additively —recordsandwarningson the create-session response both arrived that way — so a client that rejected unknown keys would break on a release that broke nothing else. Ignore fields you do not recognise. - The version is
v1, not a semver. The surface is versioned by its/api/v1path prefix.
Using it
curl -sSL https://dodomain.io/docs/openapi.json -o dodomain-openapi.jsonPoint any OpenAPI-aware tool at that file or URL — an API client (Postman, Insomnia, Bruno, Hoppscotch),
a client generator (openapi-generator, openapi-typescript, Kiota, Speakeasy), a mock server, or a
contract-test runner.
AI assistants can call the API directly
If you want an assistant to use DoDomain rather than write code against it, connect the MCP server instead — see Connecting AI assistants. It runs on the same authentication, scopes and rate limits described here.
Authentication in the spec
Two security schemes are declared, and integrator endpoints accept either:
| Scheme | How it appears | Notes |
|---|---|---|
secretKey | Authorization: Bearer dd_sk_... | App-scoped, no scope grammar, server-to-server only. |
oauth2 | Authorization-code flow with PKCE | Team-scoped. Each operation lists the scope it needs; a missing scope answers 403 with details.code: SCOPE_MISSING. |
Session-scoped endpoints (/api/v1/sessions/{token}/detect, /verify, and the one-click entry
points) carry security: [] — that is not an oversight. The unguessable session token in the path
is the credential, which is what lets the hosted flow and the embeddable widget call them from a
browser. Treat that token like a bearer token.
Two classes deviate from "either credential", and the spec says so per operation rather than in prose:
- Credential-management operations take the secret key only.
POST /api/v1/keys/rotateand every/api/v1/webhook-endpointsoperation declaresecretKeyas their sole security requirement. An OAuth access token is refused with403anddetails.code: SECRET_KEY_REQUIRED— signing secrets and key rotation stay with the app's own credential rather than with a delegated consent grant. GET /api/v1/sessions/{token}accepts either, or neither. It is one path with two arms, told apart by the shape of the path segment: pass add_sess_...token and send noAuthorizationheader, or pass the session id and authenticate. The spec encodes that as an optional security requirement (a leading{}alongside the two credential entries) and the200as aoneOfover the two response shapes, because the two arms genuinely return different objects.