Managing DNS records
Tandem runs authoritative DNS (PowerDNS) for every zone your org owns — whether the domain was registered through Tandem or adopted via “Add external domain”. These five tools are the programmatic zone editor. For attaching a domain to a service (rather than editing raw records), see Custom domains and DNS and Domain lifecycle.
Finding a zone and its records
{ "name": "list_dns_records", "arguments": { "hostname": "example.com" } }
Pass the zone apex (example.com) or any name under it (api.example.com) — both resolve to the owning zone. list_dns_records is read-only (needs the read action) and returns:
- the zone:
{ id, mode, status, defaultTtl, last sync info } - every record:
{ id, name, type, content, ttl, priority, managedBy, managedPurpose, takeoverable }
Records with managedBy='platform' back something Tandem runs for you — managedPurpose says what: web_default (the seeded apex/www A records), service_routing (a domain attached to a Tandem service), or email (MX/SPF/DKIM/DMARC). They can’t be edited or deleted directly, but web-serving ones (takeoverable=true) can be taken over (below).
Creating a record
{ "name": "create_dns_record",
"arguments": { "hostname": "example.com", "name": "www", "type": "CNAME",
"content": "example.com" } }
Supported types: A, AAAA, CNAME, ALIAS, NS, TXT, MX, SRV, CAA. Field rules:
nameis relative to the zone; use@for the apex.- Put the value in
content— an IP for A/AAAA, a hostname for CNAME/ALIAS/NS/MX/SRV, text for TXT, the value for CAA. - Structured fields go in their own params:
priority(MX/SRV),weight+port(SRV),flags+tag(CAA).ttlis optional. - CNAME is rejected at the apex (use ALIAS) and cannot coexist with any other record at the same name.
The record is written and pushed to the authoritative nameservers immediately; resolver propagation still takes up to the record’s TTL. If PowerDNS is momentarily unavailable the record is saved and the response returns syncPending=true — the reconcile loop converges within minutes, no retry needed.
Updating a record
{ "name": "update_dns_record",
"arguments": { "hostname": "example.com", "recordId": "…", "name": "www",
"type": "CNAME", "content": "new-target.example.com" } }
Get the recordId from list_dns_records. Supply the full desired record — this replaces the record’s values, it is not a partial patch. Editing name or type re-syncs both the old and new RRset so nothing drifts.
Deleting a record
{ "name": "delete_dns_record", "arguments": { "hostname": "example.com", "recordId": "…" } }
Irreversible — recreate with create_dns_record if removed by mistake. Resolvers may keep serving the old answer until the TTL expires.
Taking over a Tandem-managed record
{ "name": "take_over_dns_record", "arguments": { "hostname": "example.com", "recordId": "…" } }
Use this when the org runs its website on its own infrastructure and uses Tandem as the nameserver (and optionally the email host). Tandem seeds apex/www A records — and writes one per attached service domain — pointing at Tandem. Taking such a record over flips it to managedBy='user': Tandem stops managing, restoring, or cascade-deleting it, and update_dns_record / delete_dns_record work on it. Point it at any server with a normal update afterwards — published DNS doesn’t change until you edit it.
Notes:
- Only web-serving records are takeoverable (
takeoverable=trueinlist_dns_records). Email records returnrecord_not_takeoverable— enable/disable email for the domain instead. - You can’t sidestep takeover by adding a second record at the same name/type: that returns
record_managed_by_platform(both values would publish side by side). - Idempotent — re-running it on a record you already own is a no-op.
- If the record was routing an attached service’s hostname, that hostname only reaches the service while the record points at Tandem.
Permissions
list_dns_records needs the read action. create_/update_/delete_/take_over_dns_record all need the manage action and developer (or higher) role on the owning org. Platform-managed records return record_managed_by_platform if you try to change them without taking them over first.