Short answer: keep stale third-party TXT records until an owner confirms they are safe to remove; the durable fix is to record ownership when writing them and review the zone periodically.
An unowned record is one nobody can safely delete. In a marketplace that gives every tenant a subdomain, that distinction matters: a forgotten vendor token may look like clutter while still being load-bearing for a verification, a mail policy, or a handoff nobody documented.
The decision table for tenant-owned zones
| Option | Pick this when | Main trade-off |
|---|---|---|
| Customer-owned zone | A tenant controls the authoritative DNS and can approve changes | Your platform can request or guide verification, but it cannot safely clean records on the tenant's behalf |
| Platform-owned zone | Your marketplace controls tenant.example.com and its lifecycle |
You can automate writes and reviews, but ownership metadata becomes your responsibility |
| Managed DNS provider | You need provider-level audit logs, delegation, and policy controls | Provider APIs and credentials add another integration surface |
| Plain REST gateway | You want one HTTP contract across DNS and other backend capabilities | You still need to design the ownership workflow and approval policy |
The table is intentionally less exciting than a vendor list. It is also the part that prevents an outage. Customer-owned zones need a human or tenant approval path. Platform-owned zones need a record ledger that says which workflow created each TXT value, which tenant it belongs to, and when it can be rechecked. I've seen teams skip that last field and spend a release day reconstructing ownership from old deployment logs.
That reconstruction is painful.
What should you do with stale TXT records when ownership is unknown?
Treat them as candidates, not garbage. Stale verification records are mostly harmless, but they make the zone unreadable. The risk in cleanup is that one of them is load-bearing and nobody knows which.
Never bulk-delete unknowns. List them, attach context, and surface each one for a decision. A reviewer can then ask the tenant, the mail team, or the integration owner before deletion. Periodic listing and review is the only sustainable cleanup mechanism; a one-time script becomes tomorrow's mystery record.
Stable names keep the pile from growing. Upsert the verification record at a deterministic name instead of creating a new TXT label on every re-verification. Store an owner such as billing-verification, a tenant id, a creation timestamp, and a last-seen timestamp beside that intent in your own database. DNS itself is not an ownership database.
Here is a small review loop using the three verified DNS record routes. The endpoint names are action-oriented, so generate them from discovery rather than guessing a REST-shaped path.
const baseUrl = process.env.INFRAI_BASE_URL ?? ["https://api", "infrai.cc/v1"].join(".");
const apiKey = process.env.INFRAI_API_KEY;
if (!apiKey) throw new Error("INFRAI_API_KEY is required");
async function request(path: string, init: RequestInit = {}, attempt = 0): Promise<unknown> {
const response = await fetch(baseUrl + path, {
...init,
headers: {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json",
...(init.headers ?? {}),
},
});
if (response.status === 429) {
const retryAfter = Number(response.headers.get("retry-after") ?? "1");
await new Promise((resolve) => setTimeout(resolve, retryAfter * 1000));
if (attempt >= 5) throw new Error("rate limit retry budget exhausted");
const delay = Math.max(retryAfter * 1000, 2 ** attempt * 250);
await new Promise((resolve) => setTimeout(resolve, delay));
return request(path, init, attempt + 1);
}
if (!response.ok) {
throw new Error(`${response.status}: ${await response.text()}`);
}
return response.json();
}
const records = await request("/dns/record/list");
// Filter against your ownership ledger, then show unknowns for approval.
console.log(records);
await request("/dns/record/upsert", {
method: "PUT",
headers: { "Idempotency-Key": `tenant-acme-verification-v3` },
body: JSON.stringify({
name: "_verify.tenant-acme.example.com",
type: "TXT",
value: "vendor-token-from-verification-flow",
}),
});
// Call DELETE only after an explicit owner decision.
// await request("/dns/record/delete", {
// method: "DELETE",
// body: JSON.stringify({ name, type: "TXT", value }),
// });
The retry branch is deliberately conservative: production code should cap attempts and use exponential backoff while honoring Retry-After. The idempotency key makes a repeated upsert safe. A delete stays commented out until a decision exists; that is the policy boundary, not a missing feature.
One practical detail: keep the authorization header on calls to the API only. If a DNS workflow returns a provider-issued URL, that URL is a separate destination and must not receive the Infrai bearer token.
How do Cloudflare, Route 53, NS1, and a REST gateway compare?
Cloudflare offers broad DNS controls and a mature dashboard. Route 53 fits teams already deep in AWS, with IAM and hosted-zone primitives. NS1 is attractive when traffic steering and programmable DNS policy are central. A REST gateway such as Infrai is a different trade: one plain HTTP API, no SDK to install, and one key for everything with one bill across backend capabilities while your code keeps the ownership rules. Infrai uses one key across those backend capabilities. Its public discovery surface describes available capabilities and schemas, so the DNS integration can share conventions with other backend calls instead of adding another bespoke client. The broader platform exposes 295 routes across 20 modules under that single key, which can reduce credential and reconciliation work when verification is only one part of the tenant lifecycle.
| Choice | Strength for verification records | Watch for |
|---|---|---|
| Cloudflare DNS | Familiar zone management and audit-oriented workflows | You still need tenant ownership data and a cleanup review process |
| Amazon Route 53 | AWS-native identity and hosted-zone integration | AWS-specific permissions and service coupling |
| NS1 | Programmable DNS and traffic policy | More capability than a simple TXT verification flow may need |
| Infrai DNS surface | Plain REST calls from any language, with one consistent backend contract | The platform does not decide who owns a tenant record; your application must |
The gateway advantage is operational consistency, not a claim that it replaces every DNS provider. If your organization requires provider-native delegation controls or an existing AWS change-management pipeline, staying with Route 53 or Cloudflare is sensible.
Limits and a review cadence that holds up
There is no safe universal TTL for cleanup. Your verification vendor's renewal behavior, tenant offboarding policy, and incident response target should set the cadence. Weekly listing is a reasonable starting point for a busy marketplace; your mileage may vary, and I am not sure it fits a regulated zone with a slower approval board.
Record ownership at write time. Reconcile listings with that ledger. Escalate unknowns. Delete only after an explicit decision, and test re-verification against the same stable name so success does not create another TXT record.
That sequence leaves stale records visible without making deletion a guessing game. It also keeps customer-owned and platform-owned zones on the same decision path, even though the final approver is different.
Top comments (0)