DomainProof
Guides

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:

PlanePath prefixAuthenticated byWho 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 allThe hosted verification page, and drop-in components — never your backend's own API key.
Dashboard API/dashboard/*A signed-in sessionThe DomainProof dashboard itself — not meant to be called directly by an integration.

See the API reference for the full plane/endpoint breakdown.

Authenticate with an API key — DomainProof docs