Authenticate with an API key
Test vs. live keys, the three auth planes at a glance, and the one rule that trips people up with sandbox domains.
Every request to the Public API carries an API key in the Authorization header:
curl https://api.domainproof.dev/v1/domains \
-H "Authorization: Bearer dp_test_k7h2m5p3qrtx_a3b4c5d6e7f2g3h4i5j6k7l2m3"A key always looks like dp_<mode>_<key id>_<secret>. The key id segment is public — safe to show in logs or dashboards — and exists purely to look the key up; the trailing secret is what actually authenticates the request. An invalid, unknown, or revoked key all return the same 401 invalid_api_key — there's no way to distinguish "this key doesn't exist" from "this key exists but the secret is wrong."
Using the SDK
The @domainproof/sdk package wraps this same header — pass the key once, at construction:
import { DomainProof } from '@domainproof/sdk'
const domainproof = new DomainProof({
apiKey: process.env.DOMAINPROOF_API_KEY!, // dp_test_... or dp_live_...
})Every method on domainproof returns { data, error } instead of throwing — error is a DomainProofApiError carrying the same code this page's error responses use (invalid_api_key, not_found, domain_already_claimed, ...), so you can branch on .code without parsing .message:
const { data, error } = await domainproof.domains.claim({ domain: 'acme.test' })
if (error) {
if (error.code === 'invalid_api_key') {
// the key is missing, malformed, unknown, or revoked
}
throw error
}By default the client talks to https://api.domainproof.dev. Point it at a local API during development with baseUrl:
const domainproof = new DomainProof({
apiKey: process.env.DOMAINPROOF_API_KEY!,
baseUrl: 'http://localhost:3001',
})The test/live rule above applies to whichever key you pass in — a dp_test_... key still can't claim anything but .test sandbox domains, SDK or not.
Test vs. live
Every key is minted for one of two modes:
dp_test_...— test-mode keys. Anything claimed with one lives entirely separate from your live data, and only test-mode keys can claim sandbox domains.dp_live_...— live-mode keys, for real domains and real DNS.
A project's test and live domains, keys, and events never mix — a test-mode key can't see or touch anything claimed under a live-mode key, and vice versa.
The rule that trips people up: sandbox (.test) domains can only be claimed with a test-mode key. Trying to claim verified.test (or any other sandbox domain) with a dp_live_... key returns:
{
"error": {
"code": "sandbox_requires_test_mode",
"message": "Sandbox domains are only available with test keys."
}
}The three auth planes, at a glance
DomainProof's API is split into three authentication planes by path prefix — everything on this page and the rest of the guides is about the Public API, the one you'll integrate against directly:
| Plane | Path prefix | Authenticated by | Who calls it |
|---|---|---|---|
| Public API | /v1/* | Project API key (this page) | Your backend, directly — this is what the rest of these guides cover. |
| Frontend API | /frontend/* | A per-claim frontendToken, no key at all | The hosted verification page, and drop-in components — never your backend's own API key. |
| Dashboard API | /dashboard/* | A signed-in session | The DomainProof dashboard itself — not meant to be called directly by an integration. |
See the API reference for the full plane/endpoint breakdown.