Skip to content

Zone files

A zone can be written to a file and records can be read from one. See DNS hosting. These routes need access to the zone, like every other zone route.

format File Carries
json (default) Dinio’s own document Records with geo_routing, balance_ratio, host_health, their geo bans and health checks, and redirects.
bind RFC 1035 zone file Name, TTL, type and data.
csv CSV with a header row Name, TTL, type and data.
{
"format": "dinio-zone",
"version": 1,
"zone": "example.com",
"records": [
{
"name": "www",
"type": "A",
"ttl": 300,
"data": "192.0.2.1",
"host_health": "Auto",
"geo_bans": [{ "level": "Country", "code": 191 }],
"health_check": {
"type": "http",
"config": { "url": "https://192.0.2.1/health" },
"interval": 60,
"timeout": 5
}
},
{ "name": "@", "type": "MX", "ttl": 3600, "data": "10 mail" }
],
"redirects": [
{ "name": "go", "code": 302, "location": "https://www.example.com/campaign", "tls": "None" }
]
}

Names are relative to the zone: @ for the apex, www, and names inside record data without the trailing dot (10 mail); names outside the zone keep their trailing dot. An export from example.com therefore imports into example.org unchanged — the document works as a template. Free text — TXT data, redirect targets, health check URLs and hosts — is never rewritten. zone says where the file came from and is ignored on import.

A health_check has the fields of Create a check without record_id. host_health is Up, Down or Auto and left out for None; Auto needs a health_check on the same record.

Documents exported before 28 October 2026 have a boolean host_health and health_check.enabled; they still import. A record with a health check becomes Auto (unless the check has enabled: false); otherwise true becomes Up and false becomes Down.

GET /api/v1/zones/:ref/export

Returns the zone as a file download (Content-Disposition: attachment, named after the zone). Query format: json, bind or csv.

Terminal window
curl -H "Authorization: Bearer $DINIO_API_KEY" -o example.com.zone \
"https://api-dinio.bitelex.com/api/v1/zones/example.com/export?format=bind"

What is left out:

  • json leaves out the apex SOA and NS and every value Dinio keeps — the target zone has its own, and a redirect brings its records with it.
  • bind and csv include the apex SOA/NS and the records of redirects, but not _acme-challenge records.
  • Certificates are never exported.
POST /api/v1/zones/:ref/import

Adds what the zone doesn’t have yet. An import never changes or deletes anything in the zone. The body is the file itself, up to 2 MiB and 10 000 records; Content-Type is not inspected.

Query
format json (default), bind or csv.
dry_run true: run every check and report, but write nothing.
Terminal window
curl -X POST -H "Authorization: Bearer $DINIO_API_KEY" --data-binary @example.com.zone \
"https://api-dinio.bitelex.com/api/v1/zones/example.org/import?format=bind&dry_run=true"
{
"success": true,
"data": {
"dry_run": true,
"committed": false,
"records": {
"created": 12,
"duplicates": 1,
"skipped": [
{ "ref": 3, "name": "example.org", "type": "SOA", "message": "SOA at the apex stays the zone's own (our nameservers)" }
],
"warnings": [],
"errors": []
},
"redirects": { "created": [], "errors": [] }
}
}

How the file is merged:

  • The apex SOA and NS in the file are skipped: the zone keeps Dinio’s.
  • A value the zone already has — same name, type and data — is a duplicate and left alone.
  • A record set the zone already has keeps its TTL, and one record set in the file gets the TTL of its first value; a different TTL is a warning, not an error.
  • Every value goes through the same checks as Add a value, including the options its type takes.
  • Health checks in the file count against the zone Owner’s package (auth.healthchecks.max, auth.healthchecks.min_interval_s). Over a limit, the report has an error with ref 0, and nothing is written.

Records are all or nothing. If any value is refused, nothing is written and the call returns 422 IMPORT_FAILED with the report in error.details. A dry run returns 200 with the same report, errors included — run one first and show it.

Redirects (json only) are created after the records, each on its own: one that fails is listed under redirects.errors, and the others stay.

ref in each item is the line in a bind or csv file (from 1), or the index in records of a json document (from 0); 0 in a bind or csv report means the whole file.

format What it accepts
json A dinio-zone document, as above. A document that doesn’t have that shape is 422 VALIDATION.
bind $ORIGIN, $TTL, @, relative names, parentheses and ; comments. Class IN only; no $INCLUDE or $GENERATE.
csv A header row naming name, type, data and optionally ttl, in any order. A name without the zone is relative to it; names inside data are absolute.

A file over 2 MiB is 413 PAYLOAD_TOO_LARGE.

POST /api/v1/zones/:ref/discover

For a domain moving from another provider. Almost no provider allows a zone transfer, so Dinio asks the zone’s current nameservers about the names a zone usually has — web, mail, common DKIM selectors, SRV services — and then about the names their answers point to. It writes nothing: it returns a dinio-zone document to review, trim and send to Import.

Field Type
nameservers string[] Optional, up to 8 host names or public IP addresses. The previous provider’s nameservers — needed once the domain’s delegation already points to Dinio.
Terminal window
curl -X POST -H "Authorization: Bearer $DINIO_API_KEY" -H "Content-Type: application/json" \
-d '{"nameservers":["ns1.old-provider.example"]}' \
https://api-dinio.bitelex.com/api/v1/zones/example.com/discover
{
"success": true,
"data": {
"nameservers": ["ns1.old-provider.example"],
"server": "198.51.100.53",
"wildcard": false,
"queries": 214,
"notes": [],
"document": { "format": "dinio-zone", "version": 1, "records": [ … ] }
}
}

server is the address that answered, queries how many questions were asked, and notes anything worth showing the user. With wildcard: true the zone answers any name, so Dinio proposes the wildcard instead of every name it tried.

It takes up to about a minute, and only one discovery per zone runs at a time (409 while one is running). 422 DISCOVERY_FAILED means no usable nameserver answered — typically because the delegation already points to Dinio; send the previous provider’s nameservers.