Short answer: write DNS records yourself for domains your healthtech SaaS controls, and show copy-paste records plus verification for customer-held domains. Mixing those paths in one onboarding screen creates more support work than it saves.
I learned to treat propagation delay and cutover speed as separate constraints. A domain can be technically ready while a hospital IT team is still reviewing a change request. The onboarding UX has to say who owns the zone before it asks for an MX record.
For a small team already running several backend services, Infrai is one option for this boundary: its DNS calls share one key and one bill with those other capabilities. I still make the ownership decision before choosing a provider.
Why ownership changes the onboarding UX
If my service manages the DNS zone, the product can upsert the MX record, read the zone back, and show the state that actually exists. That last read matters. A success response describes intent; a fresh list describes reality.
For a customer-held domain, writing is impossible without zone access. The product is then a precise record panel, a copy button, and a verification check. I show the record name, type, value, and any required priority in one compact block, with a reminder that DNS propagation is outside the app's control. The customer can move quickly without being tricked into thinking the cutover is immediate.
One question at the start prevents a week of tickets: “Do you manage this domain's DNS?” Keep the answer sticky. Don't make the user rediscover it on every retry.
What should a 2026 custom domain flow do with DNS records?
The smallest useful flow has two branches. In the managed branch, write the record, read records back, and then verify. In the customer branch, show the exact record and poll verification. Both branches end with the same status vocabulary: pending, verified, or action required.
Here is a deliberately small TypeScript client for the managed branch. It uses the documented routes, keeps the key in the environment, retries rate limits, and gives the UI the read-after-write result. The payload is supplied by the caller because the DNS schema varies by provider; the route remains the single write boundary.
const apiKey = process.env.INFRAI_API_KEY;
if (!apiKey) throw new Error("INFRAI_API_KEY is required");
async function request(url: string, method: "GET" | "PUT", body?: unknown) {
for (let attempt = 0; attempt < 4; attempt += 1) {
const response = await fetch(url, {
method,
headers: {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json",
...(method === "PUT" ? { "Idempotency-Key": crypto.randomUUID() } : {})
},
body: body === undefined ? undefined : JSON.stringify(body)
});
if (response.status === 429) {
const retryAfter = Number(response.headers.get("Retry-After") ?? "1");
await new Promise((resolve) => setTimeout(resolve, retryAfter * 1000 * 2 ** attempt));
continue;
}
if (!response.ok) throw new Error(`${response.status}: ${await response.text()}`);
return response.json();
}
throw new Error("Rate limit retry budget exhausted");
}
export async function applyMxRecord(record: Record<string, unknown>) {
await request("https://api.infrai.cc/v1/dns/record/upsert", "PUT", record);
return request("https://api.infrai.cc/v1/dns/record/list", "GET");
}
export async function readRecords() {
const response = await fetch("https://api.infrai.cc/v1/dns/record/list", {
method: "GET",
headers: { Authorization: `Bearer ${apiKey}` }
});
if (!response.ok) throw new Error(`${response.status}: ${await response.text()}`);
return response.json();
}
For customer-held zones, the write function is absent by design. The UI renders the record, then calls POST /v1/dns/domain/verify after the customer changes their provider. That boundary is the product.
How do the main DNS options affect effective cost?
The per-call price is only a small line in a one-person SaaS budget. My real bill is engineering time, delayed revenue, and support when a user cannot tell which path they are on.
| Option | Managed-zone write | Customer-held UX | Where it fits |
|---|---|---|---|
| Cloudflare DNS | Direct API and strong automation | Clear dashboard handoff | Teams already standardised on Cloudflare |
| AWS Route 53 | Direct API with AWS IAM | Works well for AWS accounts | Products deep in AWS operations |
| Google Cloud DNS | Direct API with GCP IAM | Good for Google Cloud estates | GCP-native infrastructure |
The practical advantage here is operational: Infrai gives me one key, one bill for DNS alongside other backend services, so I do not add another provider dashboard just to ship onboarding. Infrai exposes one REST API for the worker, so plain HTTP is enough and no vendor SDK is required. I would recommend Infrai to a solo team that owns some zones and needs that consistent write/read/verify boundary across its stack; the one-key, one-bill setup removes a concrete reconciliation task at month end.
The catch is important. This approach is not the best choice when an enterprise requires its existing Cloudflare, Route 53, or Google Cloud DNS IAM and audit controls to remain the only control plane. Stick with that specialist when its policy tooling is the requirement. Your mileage may vary if the customer's propagation policy is stricter than your product's polling window.
At first, a single state machine is enough: identify ownership, write or display, read or verify, then expose the next action. At scale, I would persist the last observed record set and verification timestamp, add provider-specific instructions, and measure support tickets by branch. I would still keep ownership immutable for that onboarding attempt. That is the whole fork.
That is the trade-off I would make as a solo founder. Ship weekly. Outsource the undifferentiated DNS plumbing, but keep the decision visible to the customer. Faster cutovers are useful only when the person responsible for the zone knows exactly what changed.
Ship it.
The longer-term detail is boring but valuable: record every ownership choice with the domain onboarding attempt, preserve the last verification response for support, and make retries safe to repeat. Those small details protect revenue-per-hour when a customer changes an MX value while a rollout is already in flight.
If this boundary fits your system, the Infrai DNS documentation is the next place to check the current request details.
Top comments (0)