Skip to content

DNS API

Built The API runs at https://dns.paasbox.com/v1. Tokens are handed out once the service opens, with the components’ first release. DNS names for your clusters explains the service; this page is the reference.

https://dns.paasbox.com/v1

The API serves the zone and record-set requests of the Hetzner Cloud API, with Hetzner’s request and answer bodies unchanged: {"zones": […], "meta": {"pagination": …}}, {"rrset": {…}}, {"action": {…}}. A Hetzner client works against it when you set its endpoint to this URL and its token to a PaaSbox DNS token. For the hcloud CLI and Hetzner’s Go client that is HCLOUD_ENDPOINT and HCLOUD_TOKEN.

There is one zone, paasbox.app. Your team writes below <team>.paasbox.app, and record names are relative to the zone: the record set api.prod.acme is api.prod.acme.paasbox.app. A wildcard name is sent as a literal *, for example *.apps.acme.

Every request carries a team token as a bearer token:

Authorization: Bearer pbdns_…

A token belongs to a team, carries the scope dns, and is shown once when it is created. Without a token, or with an unknown or revoked one, the answer is 401 unauthorized; with a token that lacks the dns scope, 403 forbidden. A team can hold up to five active tokens.

Method and pathWhat it does
GET /zonesLists the one zone, paasbox.app. ?name= with any other name returns an empty list.
GET /zones/{zone}The zone, by its ID or by its name.
GET /zones/{zone}/rrsetsYour team’s record sets, and only those.
POST /zones/{zone}/rrsetsCreates a record set: name, type, records (each with a value and an optional comment), an optional ttl and labels.
GET /zones/{zone}/rrsets/{name}/{type}One record set.
DELETE /zones/{zone}/rrsets/{name}/{type}Deletes a record set.
POST /zones/{zone}/rrsets/{name}/{type}/actions/set_recordsReplaces the records of a record set.
POST /zones/{zone}/rrsets/{name}/{type}/actions/add_recordsAdds records to a record set.
POST /zones/{zone}/rrsets/{name}/{type}/actions/remove_recordsRemoves records from a record set.
POST /zones/{zone}/rrsets/{name}/{type}/actions/change_ttlChanges the TTL of a record set.
GET /actions?id=…, GET /actions/{id}The progress of a write, for clients that wait for it. Only zone actions are visible.

Lists are paginated the way Hetzner paginates them: page and per_page (25 by default, at most 50), with meta.pagination in the answer.

Not served: creating, changing or deleting zones, zone files, zone and record-set protection, the other record-set actions, and every resource of the Hetzner Cloud API that is not DNS, such as servers and volumes. A method the API does not support on a path answers 405 method_not_allowed.

  • Names: your team’s own name (acme, an A record on acme.paasbox.app is allowed) and every name ending in .acme. Not the zone apex, not another team’s name, not a name outside the zone. Names must be plain DNS names; a name is checked before it reaches Hetzner.
  • Types: A, AAAA, CNAME and TXT. NS is refused everywhere.
  • Values: at most 50 records per record set, each value at most 4,096 characters; a TTL is empty or a non-negative integer.

A read of a name outside your team answers 404 not_found, not 403, so the zone’s contents cannot be listed through the API. Every write is recorded in the team’s audit log with the token, the name, the type and Hetzner’s answer.

Records per team200, counted across all your record sets
Records per record set50
Active tokens per team5
RequestsIn progress 120 per minute per token, 600 per minute per team, 300 per minute per address before a token is checked

Errors have Hetzner’s shape, so a client’s error handling stays unchanged:

{"error": {"code": "resource_limit_exceeded", "message": "this team is limited to 200 DNS records on acme.paasbox.app"}}
StatuscodeWhen
400invalid_inputThe body is not a JSON object, records is empty or malformed, or ttl is not an integer.
401unauthorizedNo token, or an unknown or revoked one.
403forbiddenThe token lacks the dns scope, or a write names the apex, another team’s name or an invalid name, or a type other than A, AAAA, CNAME and TXT.
403resource_limit_exceededThe write would take the team past 200 records.
404not_foundAn unknown zone, a name outside your team on read, or an unsupported record-set action.
405method_not_allowedThe method is not supported on that path.
429rate_limit_exceededIn progress Over a request limit. Hetzner’s clients retry with a backoff.
502upstream_unavailableHetzner’s API could not be reached.

When Hetzner itself refuses a write, its answer is passed on unchanged, with its own status code and code.

With curl, list your record sets and create an A record:

Terminal window
export PAASBOX_DNS_TOKEN=pbdns_…
curl -s https://dns.paasbox.com/v1/zones/paasbox.app/rrsets \
-H "Authorization: Bearer $PAASBOX_DNS_TOKEN"
curl -s -X POST https://dns.paasbox.com/v1/zones/paasbox.app/rrsets \
-H "Authorization: Bearer $PAASBOX_DNS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "api.prod.acme", "type": "A", "ttl": 300, "records": [{"value": "203.0.113.7"}]}'

With the hcloud CLI, replace the records of a wildcard name:

Terminal window
export HCLOUD_ENDPOINT=https://dns.paasbox.com/v1
export HCLOUD_TOKEN=pbdns_…
hcloud zone rrset set-records --record 203.0.113.8 paasbox.app '*.apps.acme' A

In progress On a branch, not released: short-lived names under demo.paasbox.app, each with a token that can write only below it.

Method and pathAuthWhat it does
POST /demosa team token, or no token and {"course_code": "…"}Creates a demo name and its token. Body: name (optional), ttl in seconds (optional; 4 hours by default, at least 300, at most 7 days). The token is in this answer only.
GET /demosa team tokenThe team’s live demos, without tokens.
GET /demos/{label}the team’s token or the demo’s ownOne demo.
POST /demos/{label}/actions/extendthe same{"ttl": seconds}: the expiry becomes now plus ttl, never later than 7 days after creation.
DELETE /demos/{label}the sameDeletes the demo’s records now and revokes its token.

A team has at most 10 live demos, a demo at most 20 records. A demo token works with the zone endpoints above, confined to its own name; it cannot create or list demos.