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.