Getting started
From signup to a verified custom domain — create an app, mint a connect session, and receive the signed webhook.
1. Sign in and create an app
Sign in at app.dodomain.io/signin — with Google or with email and password. Every account gets a personal team, and the free plan needs no card.
Create an app in the dashboard. You get two keys:
- Public key (
dd_pk_...) — identifies the app in the widget; safe to expose, grants nothing. - Secret key (
dd_sk_...) — authenticates your server's API calls. It is shown once and stored only as a hash; keep it server-side, never in a browser bundle. You can rotate it from the dashboard if it leaks.
2. Mint a connect session
One call from your server. Describe the records your product needs on the user's domain — host is relative to the domain ("app" becomes app.customer.com; use "@" for the apex), and value is where the record points.
curl -X POST https://app.dodomain.io/api/v1/sessions \
-H "Authorization: Bearer dd_sk_YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"domain": "app.customer.com",
"records": [
{ "type": "CNAME", "host": "app", "value": "edge.yourproduct.com" },
{ "type": "TXT", "host": "_yourproduct", "value": "yourproduct-verify=7f3a9c" }
],
"returnUrl": "https://yourproduct.com/settings/domains"
}'The response is a short-lived session (24-hour expiry):
{
"id": "cmcwl0d9x0001…",
"token": "dd_sess_Qy3v…",
"expiresAt": "2026-07-12T14:03:07.000Z",
"connectUrl": "https://app.dodomain.io/connect/dd_sess_Qy3v…"
}3. Send your user to the connect flow
Open connectUrl — link, redirect, or new tab. The hosted page detects the user's DNS provider: on Cloudflare it offers one-click apply via OAuth; everywhere else it shows provider-specific copy-paste instructions with live per-record verification. Prefer it embedded? The @dodomain/connect widget opens the same flow in a modal on your own page.
4. Receive the signed webhook
Add a webhook endpoint for your app in the dashboard — you get a whsec_... signing secret. The moment the records verify against authoritative DNS, DoDomain POSTs a connection.verified event to it. Verify the signature (header x-dodomain-signature, format t=<unix ms>,v1=<hex HMAC-SHA256>), then activate the domain in your product.
Or use the SDK
@dodomain/node (npm install @dodomain/node) wraps all of this — a schema-validated
sessions.create plus a verifyWebhook helper. The raw HTTP stays fully supported; the SDK is a
convenience over the same shapes.
import { DoDomain, verifyWebhook } from "@dodomain/node";
const dodomain = new DoDomain({ secretKey: process.env.DODOMAIN_SECRET_KEY });
const session = await dodomain.sessions.create({
domain: "app.customer.com",
records: [{ type: "CNAME", host: "app", value: "edge.yourproduct.com" }],
});
// session.connectUrl → hand to your user
// verifyWebhook(secret, rawBody, signatureHeader) → boolean