API Endpoints¶
This page is a task-shaped map of the API, not the complete list. The API Reference is generated from the source and documents every operation with its full request and response schemas - use that when you need the authoritative answer, and this page when you want to find the right endpoint for a job.
A running instance can also serve the same specification interactively.
Interactive API documentation¶
When api.docs_enabled = true in config/settings.php, every Poweradmin
instance hosts its own Swagger UI:
From there you can:
- Browse every endpoint grouped by tag (Zones, Records, Users, ...)
- See the exact JSON request and response schemas
- Paste in an API key via the Authorize button
- Issue real requests against the running instance and inspect the response
For production deployments, leave docs_enabled off and use a staging
instance for exploration.
High-level endpoint map (API v2)¶
API v2 is the recommended version. All paths are prefixed with /api/v2.
Zones¶
| Method | Path | Purpose |
|---|---|---|
GET |
/zones |
List zones |
POST |
/zones |
Create zone |
GET |
/zones/{id} |
Get zone |
PUT |
/zones/{id} |
Update zone |
DELETE |
/zones/{id} |
Delete zone |
GET |
/zones/{id}/owners |
List zone owners (v4.2.0+) |
POST |
/zones/{id}/owners |
Add owner(s), supports batch (v4.2.0+) |
DELETE |
/zones/{id}/owners/{user_id} |
Remove owner (v4.2.0+) |
Setting the serial policy on create (v4.5.0+)¶
POST /zones accepts an optional soa_edit_api string that sets the zone's
SOA-EDIT-API serial policy:
Omit the field, or send an empty string, to apply the dns.soa_edit_api
configuration default. Send OFF to disable the policy for this zone
specifically; in API backend mode that also clears the default PowerDNS applies.
The accepted values are DEFAULT, INCREASE, EPOCH, SOA-EDIT,
SOA-EDIT-INCREASE and OFF, narrowed to whatever the dns.soa_edit_api_options
configuration list allows. A value outside that set returns 400, and so does a
non-string value. This differs deliberately from the add-zone form, which silently
drops an unoffered value and falls back to the default.
Two limits worth knowing before scripting against it. The field is create-only:
PUT /zones/{id} does not accept it, and an existing zone's policy is changed
through PUT /zones/{id}/metadata/SOA-EDIT-API instead. And a SLAVE zone takes
its serial from the primary, so a value accepted there is validated but never
applied.
Zone metadata and DNSSEC¶
| Method | Path | Purpose |
|---|---|---|
GET |
/zones/{id}/metadata |
List all metadata kinds for a zone (v4.3.0+) |
GET |
/zones/{id}/metadata/{kind} |
Get one metadata kind (v4.3.0+) |
PUT |
/zones/{id}/metadata/{kind} |
Set one metadata kind (v4.3.0+) |
DELETE |
/zones/{id}/metadata/{kind} |
Remove one metadata kind (v4.3.0+) |
GET |
/zones/{id}/dnssec |
Get DNSSEC status and keys (v4.5.0+) |
POST |
/zones/{id}/dnssec |
Sign or unsign the zone (v4.5.0+) |
Dynamic DNS¶
| Method | Path | Purpose |
|---|---|---|
POST |
/dynamic-dns |
Update a record from a dynamic DNS client (v4.5.0+) |
This is the API v2 equivalent of the standalone dynamic_update.php script
described in Dynamic DNS. Both remain
supported; the standalone script keeps the dyndns2-compatible query-string
interface that routers expect.
Records¶
| Method | Path | Purpose |
|---|---|---|
GET |
/zones/{id}/records |
List records in a zone |
POST |
/zones/{id}/records |
Create record |
GET |
/zones/{id}/records/{recordId} |
Fetch a single record |
PUT |
/zones/{id}/records/{recordId} |
Update record |
DELETE |
/zones/{id}/records/{recordId} |
Delete record |
POST |
/zones/{id}/records/bulk |
Bulk create records |
GET |
/zones/{id}/rrsets |
List RRsets |
GET |
/zones/{id}/rrsets/{name}/{type} |
Get a specific RRset |
When ttl is omitted on a record create call, Poweradmin applies the
configured default (dns.ttl_reverse for PTR records in reverse zones when
set, dns.ttl otherwise). See
DNS settings for details.
Records in Secondary and Consumer zones are read-only - they replicate
from a primary. Create, update, delete, and bulk-write calls against such a
zone return 403 with a message stating the zone is read-only (rather than a
permission error). Edit the records on the primary instead.
Users¶
| Method | Path | Purpose |
|---|---|---|
GET |
/users |
List users |
POST |
/users |
Create user |
GET |
/users/{id} |
Get user |
PUT |
/users/{id} |
Update user |
DELETE |
/users/{id} |
Delete user |
Writing perm_templ is gated separately from the write itself, and a rejected
assignment returns 403:
- Callers holding
user_is_ueberusermay assign any template. - Callers holding
user_edit_templ_permmay assign any template that does not grantuser_is_ueberuser, and may not change their own account's template unless they also holduser_edit_others. - Everyone else may not send
perm_templat all.
Omitting perm_templ on create assigns the least-privileged non-superuser template,
whoever the caller is; it no longer falls back to template id 1. If no such template
exists, the request fails rather than granting administrator rights.
Permission template and groups on reads (v4.5.0+)¶
User reads carry the assigned permission template by ID and by name, plus the groups the user belongs to:
{
"user_id": 5,
"username": "svc-acme",
"perm_templ": 2,
"perm_templ_name": "Zone Manager",
"groups": [{ "id": 3, "name": "dns-operators" }]
}
perm_templ_name is null when the stored template no longer exists or is a
group template rather than a user template.
Assigning groups on create (v4.5.0+)¶
POST /users accepts an optional groups array holding integer group IDs,
exact group names, or a mix of both:
The response lists the memberships that were actually created, so a caller does not have to assume the request took full effect:
Rules worth knowing before you script against it:
- Sending
groupsrequiresuser_is_ueberuser, because a group carries its own permission template. Callers without it get403, even when they may otherwise create users. - Names are matched exactly, including case and accents.
"Viewers"resolves,"viewers"does not. This is deliberate: MySQL's default collation would otherwise accept variants that PostgreSQL and SQLite reject. - Numeric strings are treated as names, not IDs. Send
3to reference group 3;"3"is looked up as a group named3and will normally fail. - If any entry does not resolve to a group, the whole request returns
400and no user is created. - Naming the same group more than once, whether by ID and by name or by repeating one value, still creates a single membership.
- The array may hold up to 50 groups. A longer list returns
400and creates nothing.
Membership changes after creation go through
POST/DELETE /groups/{id}/members; PUT /users/{id} does not accept groups.
Groups (v4.2.0+)¶
| Method | Path | Purpose |
|---|---|---|
GET |
/groups |
List groups |
POST |
/groups |
Create group |
GET |
/groups/{id} |
Get group |
PUT |
/groups/{id} |
Update group |
DELETE |
/groups/{id} |
Delete group |
GET |
/groups/{id}/members |
List group members |
POST |
/groups/{id}/members |
Add member |
DELETE |
/groups/{id}/members/{user_id} |
Remove member |
GET |
/groups/{id}/zones |
List zones assigned to group |
POST |
/groups/{id}/zones |
Assign zone to group |
DELETE |
/groups/{id}/zones/{zone_id} |
Remove zone from group |
Permission templates¶
| Method | Path | Purpose |
|---|---|---|
GET |
/permission-templates |
List templates |
POST |
/permission-templates |
Create template |
GET |
/permission-templates/{id} |
Get template |
PUT |
/permission-templates/{id} |
Update template |
DELETE |
/permission-templates/{id} |
Delete template |
GET |
/permissions |
List available permission flags |
GET |
/permissions/{id} |
Get permission flag details |
Zone templates (v4.2.0+)¶
| Method | Path | Purpose |
|---|---|---|
GET |
/zone-templates |
List zone templates |
POST |
/zone-templates |
Create zone template |
GET |
/zone-templates/{id} |
Get zone template |
PUT |
/zone-templates/{id} |
Update zone template |
DELETE |
/zone-templates/{id} |
Delete zone template |
GET |
/zone-templates/{id}/records |
List template records |
POST |
/zone-templates/{id}/records |
Add template record |
PUT |
/zone-templates/{template_id}/records/{id} |
Update template record |
DELETE |
/zone-templates/{template_id}/records/{id} |
Delete template record |
Health endpoints (v4.5.0+)¶
These sit outside the versioned API and outside the API key model. They take no
credentials, are disabled by default, and return 404 while disabled. Paths are
absolute, not relative to /api/v2.
| Method | Path | Purpose |
|---|---|---|
GET |
/api/health |
Readiness: database and PowerDNS API reachability. 200 healthy, 503 otherwise |
GET |
/ping |
Liveness: returns ok and checks nothing else |
They are not part of the OpenAPI specification, and they answer regardless of whether
api.enabled is set. See Health Checks.
API v1 endpoints¶
Removed in 4.5.0. On 4.5.0 and later, every /api/v1 path answers
410 Gone and points at /api/v2.
On 4.2.x-4.4.x, v1 is still available under /api/v1. The endpoint surface is
similar but the response envelope is less consistent and several v2 features
(RRsets, bulk records, zone owners, groups, zone templates) are not available.
See API Configuration for
the v1 endpoint list, and migrate to v2 before upgrading to 4.5.0.
Pagination¶
List endpoints for zones and users accept page and per_page query
parameters:
Omitting per_page returns all results. page is only read when per_page is
given, and per_page is capped at 10000.
Warning: The parameter is
per_page, notlimit. An unrecognised parameter is ignored rather than rejected, so?limit=50silently returns every row.
Paginated responses include a pagination block alongside data:
Related documentation¶
- Overview - what the API can do, response envelope
- Authentication - API keys and Basic Auth
- API Configuration - enabling the API, web server requirements, security, request/response examples
- Dynamic DNS with cURL - the separate,
simpler
dynamic_update.phpendpoint for IP-update scripts