This document is about PowerDNS 4.X. If you have PowerDNS 3.X, please see the PowerDNS 3.X documentation

API Spec

This API runs over HTTP, preferably HTTPS.

Design Goals

Data format

Input data format: JSON.

Output data formats: JSON.

The Accept: header determines the output format. An unknown value or */* will cause a 400 Bad Request.

All text is UTF-8 and HTTP headers will reflect this.

Data types:

REST

not-so-REST

For interactions that do not directly map onto CRUD, we use these:

Action/Execute methods return a JSON body of this format:

{
  "message": "result message"
}

Authentication

The PowerDNS daemons accept a static API Key, configured with the api-key option, which has to be sent in the X-API-Key header.

Note: Authoritative Server 3.4.0 and Recursor 3.6.0 and 3.6.1 use HTTP Basic Authentication instead.

Errors

Response code 4xx or 5xx, depending on the situation. Never return 2xx for an error!

Error responses have a JSON body of this format:

{
  "error": "short error message",
  "errors": [
    { ... },
  ]
}

Where errors is optional, and the contents are error-specific.

Common Error Causes

400 Bad Request
  1. The client body was not a JSON document, or it could not be parsed, or the root element of the JSON document was not a hash.
  2. The client did not send an Accept: header, or it was set to */*.
  3. For requests that operate on a zone, the zone_id URL part was invalid. To get a valid zone_id, list the zones with the /api/v1/servers/:server_id/zones endpoint.

URL: /api

Version discovery endpoint.

Allowed methods: GET

[
  {
    "url": "/api/v1",
    "version": 1
  }
]

URL: /api/v1

Allowed methods: GET

{
  "server_url": "/api/v1/servers{/server}",
  "api_features": []
}

TODO:

General Collections Interface

Collections generally support GET and POST with these meanings:

GET

Retrieve a list of all entries.

The special type and url fields are included in the response objects:

Response format:

[
  obj1
  [, further objs]
]

Example:

[
  {
    "type": "AType",
    "id": "anid",
    "url": "/atype/anid",
    "a_field": "a_value"
  },
  {
    "type": "AType",
    "id": "anotherid",
    "url": "/atype/anotherid",
    "a_field": "another_value"
  }
]

POST

Create a new entry. The client has to supply the entry in the request body, in JSON format. application/x-www-form-urlencoded data MUST NOT be sent.

Clients SHOULD not send the 'url' field.

Client body:

obj1

Example:

{
  "type": "AType",
  "id": "anewid",
  "a_field": "anew_value"
}

Servers

TODO: further routes

server_resource

Example with server "localhost", which is the only server returned by pdns_server or pdns_recursor.

pdnsmgrd and pdnscontrol MUST NOT return “localhost”, but SHOULD return other servers.

{
  "type": "Server",
  "id": "localhost",
  "url": "/api/v1/servers/localhost",
  "daemon_type": "recursor",
  "version": "VERSION",
  "config_url": "/api/v1/servers/localhost/config{/config_setting}",
  "zones_url": "/api/v1/servers/localhost/zones{/zone}",
}

Note: On a pdns_server or pdns_recursor, the servers collection is read-only, and the only allowed returned server is read-only as well. On a pdnscontrol server, the servers collection is read-write, and the returned server resources are read-write as well. Write permissions may depend on the credentials you have supplied.

URL: /api/v1/servers

Collection access.

Allowed REST methods:

URL: /api/v1/servers/:server_id

Returns a single server_resource.

Config

config_setting_resource

{
   "type": "ConfigSetting",
   "name": "config_setting_name",
   "value": "config_setting_value"
}

URL: /api/v1/servers/:server_id/config

Collection access.

Allowed REST methods: GET, POST

POST

Creates a new config setting. This is useful for creating configuration for new backends.

TODO: Not yet implemented.

URL: /api/v1/servers/:server_id/config/:config_setting_name

Allowed REST methods: GET, PUT

NOTE: only the Recursors allow_from configuration setting can be retrieved or modified.

Zones

Authoritative DNS Zones.

A Resource Record Set (below as "RRset") are all records for a given name and type.

Comments are per-RRset.

zone_collection

{
  "id": "<id>",
  "name": "<string>",
  "type": "Zone",
  "url": "/api/v1/servers/:server_id/zones/:id",
  "kind": "<kind>",
  "serial": <int>,
  "notified_serial": <int>,
  "masters": ["<ip>", ...],
  "dnssec": <bool>,
  "nsec3param": "<nsec3param record>",
  "nsec3narrow": <bool>,
  "presigned": <bool>,
  "soa_edit": "<string>",
  "soa_edit_api": "<string>",
  "account": "<string>",
  "nameservers": ["<string>", ...],
  "servers": ["<string>", ...],
  "recursion_desired": <bool>,
  "rrsets": [<RRset>, ...],
}

Where RRset is defined as:

{
  "name": "<string>",
  "type": "<type>",
  "ttl": <int>,
  "records": [<Record>, ...],
  "comments": [<Comment>, ...]
}

Where Record is defined as:

{
  "content": "<string>",
  "disabled": <bool>
}

Where Comment is defined as:

{
  "content": "<string>",
  "account": "<string>",
  "modified_at": <int>
}
Parameters:

Switching dnssec to true (from false) sets up DNSSEC signing based on the other flags, this includes running the equivalent of secure-zone and rectify-zone. This also applies to newly created zones. If presigned is true, no DNSSEC changes will be made to the zone or cryptokeys. Note: Authoritative only.

TODO: dnssec, nsec3narrow, nsec3param, presigned are not yet implemented.

Please see the description for PATCH for details on the fields in RRset, Record and Comment.

Notes:

Turning on DNSSEC with custom keys: just create the zone with dnssec set to false, and add keys using the cryptokeys REST interface. Have at least one of them active set to true. TODO: not yet implemented.

Changes made through the Zones API will always yield valid zone data, and the zone will be properly "rectified" (TODO: not yet implemented). If changes are made through other means (e.g. direct database access), this is not guaranteed to be true and clients SHOULD trigger rectify.

Backends might implement additional features (by coincidence or not). These things are not supported through the API.

When creating a slave zone, it is recommended to not set any of nameservers, records.

URL: /api/v1/servers/:server_id/zones

Allowed REST methods: GET, POST

POST

Creates a new domain.

TODO: dnssec, nsec3narrow, nsec3param, presigned are not yet implemented.

URL: /api/v1/servers/:server_id/zones/:zone_id

Allowed methods: GET, PUT, DELETE, PATCH.

GET

Returns zone information.

DELETE

Deletes this zone, all attached metadata and rrsets.

PATCH

Modifies present RRsets and comments. Returns 204 No Content on success.

Note: Authoritative only.

Client body for PATCH:

{ "rrsets":
  [
    {
      "name": <string>,
      "type": <string>,
      "ttl": <int>,
      "changetype": <changetype>,
      "records":
        [
          {
            "content": <string>,
            "disabled": <bool>,
            "set-ptr": <bool>
          }, ...
        ],
      "comments":
        [
          {
            "account": <string>,
            "content": <string>,
            "modified_at": <int>
          }, ...
        ]
    },
    { ... }
  ]
}

PUT

Modifies basic zone data (metadata).

Allowed fields in client body: all except id and url. Returns 204 No Content on success.

Changing name renames the zone, as expected.

URL: /api/v1/servers/:server_id/zones/:zone_id/notify

Allowed methods: PUT

Send a DNS NOTIFY to all slaves.

Fails when zone kind is not Master or Slave, or master and slave are disabled in pdns configuration. Only works for Slave if renotify is on.

Not supported for recursors.

Clients MUST NOT send a body.

URL: /api/v1/servers/:server_id/zones/:zone_id/axfr-retrieve

Allowed methods: PUT

Retrieves the zone from the master.

Fails when zone kind is not Slave, or slave is disabled in PowerDNS. configuration.

Not supported for recursors.

Note: Added in 3.4.2

URL: /api/v1/servers/:server_id/zones/:zone_id/export

Allowed methods: GET

Returns the zone in AXFR format.

Not supported for recursors.

URL: /api/v1/servers/:server_id/zones/:zone_id/check

Allowed methods: GET

Verify zone contents/configuration.

Return format:

{
  "zone": "<zone_name>",
  "errors": ["error message1", ...],
  "warnings": ["warning message1", ...]
}

TODO: Not yet implemented.

Zone Metadata

Note: Available since PowerDNS Authoritative Server 4.1.0.

zone_metadata_resource

{
  "type": "Metadata",
  "kind": <metadata_kind>,
  "metadata": [
    "value1",
    ...
  ]
}
Parameters:

kind: valid values for <metadata_kind> are specified in the domainmetadata documentation.

metadata: an array with all values for this metadata kind.

Clients MUST NOT modify NSEC3PARAM, NSEC3NARROW, PRESIGNED and LUA-AXFR-SCRIPT through this interface. The server rejects updates to these metadata. Modifications to custom metadata kinds starting with X- is allowed as well.

URL: /api/v1/servers/:server_id/zones/:zone_name/metadata

Collection access.

Allowed methods: GET, POST

GET

Returns all metadata entries for the zone.

POST

Creates a set of metadata entries of given kind for the zone.

URL: /api/v1/servers/:server_id/zones/:zone_name/metadata/:metadata_kind

Allowed methods: GET, PUT, DELETE

GET

Returns all metadata entries of a given kind for the zone.

DELETE

Deletes all metadata entries of a given kind for the zone.

PUT

Modifies the metadata entries of a given kind for the zone.

This returns 200 OK on success.

Cryptokeys

cryptokey_resource

{
  "type": "Cryptokey",
  "id": <int>,
  "active": <bool>,
  "keytype": <keytype>,
  "dnskey": <string>,
  "privatekey": <string>,
  "ds": [ <ds>,
          <ds>,
          .... ]
}
Parameters:

id: read-only.

keytype: <keytype> is one of the following: ksk, zsk, csk.

dnskey: the DNSKEY for this key

ds: an array with all DSes for this key

privatekey: private key data (in ISC format).

URL: /api/v1/servers/:server_id/zones/:zone_name/cryptokeys

Allowed methods: GET, POST

GET

Returns all public data about cryptokeys, but not privatekey.

POST

This method adds a new key to a zone. The key can either be generated or imported by supplying the content parameter.

Parameters:

If content == null, the server generates a new key. In this case, the following additional fields MAY be supplied:

Where <algo> is one of the supported key algorithms in lowercase OR the numeric id, see the list.

Response:

URL: /api/v1/servers/:server_id/zones/:zone_name/cryptokeys/:cryptokey_id

Allowed methods: GET, PUT, DELETE

GET

Returns all public data about cryptokeys, including privatekey.

PUT

This method de/activates a key from zone_name specified by cryptokey_id.

Parameters:
Responses:

DELETE

This method deletes a key from zone_name specified by cryptokey_id.

Responses:

Data searching

URL: /api/v1/servers/localhost/search-data?q=:search_term&max=:max_results

Note: Authoritative only.

Allowed methods: GET

GET

Search the data inside PowerDNS for :search_term and return at most :max_results. This includes zones, records and comments. The * character can be used in :search_term as a wildcard character and the ? character can be used as a wildcard for a single character.

Response body is an array of one or more of the following objects:

For a zone:

{
  "name": "<zonename>",
  "object_type": "zone",
  "zone_id": "<zoneid>"
}

For a record:

{
  "content": "<content>",
  "disabled": <bool>,
  "name": "<name>",
  "object_type": "record",
  "ttl": <ttl>,
  "type": "<type>",
  "zone": "<zonename>,
  "zone_id": "<zoneid>"
}

For a comment:

{
  "object_type": "comment",
  "name": "<name>",
  "content": "<content>"
  "zone": "<zonename>,
  "zone_id": "<zoneid>"
}

Cache Access

TODO: Not yet implemented: Peek at the cache, clear the cache, possibly read cache?

URL: /api/v1/servers/:server_id/cache/flush?domain=:domain

Allowed methods: PUT (Execute)

PUT (Execute)

Flush the cache for a given domain name :domain. Response body:

{
  "count": 10,
  "result": "Flushed cache."
}

Implementation detail: On Authoritative servers, this clears the packet cache. On Recursors, this clears the positive, negative and packet cache.

Logging & Statistics

URL: /api/v1/servers/:server_id/search-log?q=:search_term

Allowed methods: GET (Query)

GET (Query)

Query the log, filtered by :search_term (query parameter). Response body:

[
  "<log_line>",
  ...
]

URL: /api/v1/servers/:server_id/statistics

Allowed methods: GET (Query)

GET (Query)

Query PowerDNS internal statistics. Response body:

[
  {
    "type": "StatisticItem",
    "name": "<name>",
    "value": "<value>"
  },
  ...
]

The statistic entries are dependent on the daemon type. Values are returned as strings.

URL: /api/v1/servers/:server_id/trace

TODO: Not yet implemented.

PUT (Configure)

Configure query tracing.

Client body:

{
  "domains": "<regex_string>"
}

Set domains to null to turn off tracing.

GET (Query)

Retrieve query tracing log and current config. Response body:

{
  "domains": "<Regex>",
  log: [
    "<log_line>",
    ...
  ]
}

URL: /api/v1/servers/:server_id/failures

TODO: Not yet implemented.

PUT

Configure query failure logging.

Client body:

{
  "top-domains": <int>,
  "domains": "<Regex>",
}
Parameters:

top-domains are the number of top resolved domains that are automatically monitored for failures.

domains is a Regex of domains that are additionally monitored for resolve failures.

GET

Retrieve query failure logging and current config.

Response body:

{
  "top-domains": <int>,
  "domains": "<Regex>",
  "log": [
    {
      "first_occurred": <timestamp>,
      "domain": "<full domain>",
      "qtype": "<qtype>",
      "failure": <failure_code>,
      "failed_parent": "<full parent domain>",
      "details": "<log message>",
      "queried_servers": [
         {
           "name": <name>,
           "address": <address>
         }, ...
      ]
    },
    ...
  ]
}
Parameters:

failed_parent is generally OPTIONAL.

Where <failure_code> is one of these:

Data Overrides

TODO: Not yet implemented.

override_type

created is filled by the Server.

{
  "type": "Override",
  "id": <int>,
  "override": "ignore-dnssec",
  "domain": "nl",
  "until": <timestamp>,
  "created": <timestamp>
}


{
  "type": "Override",
  "id": <int>,
  "override": "replace",
  "domain": "www.cnn.com.",
  "rrtype": "AAAA",
  "values": ["203.0.113.4", "203.0.113..2"],
  "until": <timestamp>,
  "created": <timestamp>
}

TODO: what about validation here?

{
  "type": "Override",
  "id": <int>,
  "override": "purge",
  "domain": "example.net.",
  "created": <timestamp>
}

Clears recursively all cached data ("plain" DNS + DNSSEC)

TODO: should this be stored? (for history)

URL: /api/v1/servers/:server_id/overrides

TODO: Not yet implemented.

Collection access.

Allowed Methods: GET, POST

URL: /api/v1/servers/:server_id/overrides/:override_id

TODO: Not yet implemented.

Allowed methods: GET, PUT, DELETE