DNS records
The site's own DNS records (A, AAAA, CNAME, TXT, MX, SRV, CAA, NS).
Nameserver status
GET/api/v1/sites/{site_id}/nameserversScope dns:read
The nameservers the domain must use (required), what it uses now (current, checked daily), whether it is pointed, whether the DNS zone expired at the provider (zone_expired: re-create it from the site page), and the registrar autopilot status when a registrar connection sets them for you.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
site_id | path | integer | yes | The site id (see GET /sites). |
Example
curl -s "https://app.pbn.ltd/api/v1/sites/123/nameservers" \
-H "Authorization: Bearer $PBN_API_KEY"
import os
import requests
headers = {"Authorization": "Bearer " + os.environ["PBN_API_KEY"]}
r = requests.get("https://app.pbn.ltd/api/v1/sites/123/nameservers", headers=headers, timeout=120)
print(r.status_code, r.json())
const res = await fetch("https://app.pbn.ltd/api/v1/sites/123/nameservers", {
method: "GET",
headers: {Authorization: `Bearer ${process.env.PBN_API_KEY}`}
});
console.log(res.status, await res.json());
Response
200
{
"data": {
"current": [
"ada.ns.cloudflare.com",
"bob.ns.cloudflare.com"
],
"required": [
"ada.ns.cloudflare.com",
"bob.ns.cloudflare.com"
],
"pointed": true,
"main_cloud": false,
"zone_expired": false,
"dns_provider": "Cloudflare",
"checked_at": "2026-09-19T13:25:00Z",
"autopilot": null
}
}
Errors: not_found, rate_limited, scope_missing, unauthorized
List DNS records
GET/api/v1/sites/{site_id}/dnsScope dns:read
The site's own DNS records (the DNS records tab), and the publishing state: the DNS provider, when the records were last published and any record the provider refused (with its error). Records the platform manages for the CDN are not listed and are never changed through this API.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
site_id | path | integer | yes | The site id (see GET /sites). |
Example
curl -s "https://app.pbn.ltd/api/v1/sites/123/dns" \
-H "Authorization: Bearer $PBN_API_KEY"
import os
import requests
headers = {"Authorization": "Bearer " + os.environ["PBN_API_KEY"]}
r = requests.get("https://app.pbn.ltd/api/v1/sites/123/dns", headers=headers, timeout=120)
print(r.status_code, r.json())
const res = await fetch("https://app.pbn.ltd/api/v1/sites/123/dns", {
method: "GET",
headers: {Authorization: `Bearer ${process.env.PBN_API_KEY}`}
});
console.log(res.status, await res.json());
Response
200
{
"data": {
"records": [
{
"id": 5501,
"type": "MX",
"name": "@",
"value": "10 mail.example.com",
"proxied": false,
"updated_at": "2026-09-19T10:00:00Z",
"parts": {
"priority": 10,
"target": "mail.example.com"
}
}
],
"publishing": {
"provider": "Cloudflare",
"errors": [],
"last_synced_at": "2026-09-19T10:01:00Z"
}
}
}
Errors: not_found, rate_limited, scope_missing, unauthorized
Add a DNS record
POST/api/v1/sites/{site_id}/dnsScope dns:write
Adds a record with the panel's own validation. It is published to the site's DNS provider within a minute or two (follow the job); your records are never overwritten by the platform.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
site_id | path | integer | yes | The site id (see GET /sites). |
type | body | string (one of: A, AAAA, CNAME, TXT, MX, SRV, CAA, NS) | yes | Record type. |
name | body | string | yes | "@" for the domain itself, or a name like blog, shop.eu, _dmarc, _sip._tcp. |
value | body | string | yes | IPv4 (A), IPv6 (AAAA), host name (CNAME, MX, SRV target, NS), text (TXT) or CA domain (CAA). |
priority | body | integer | no | MX and SRV. |
weight | body | integer | no | SRV. |
port | body | integer | no | SRV. |
caa_flags | body | integer (one of: 0, 128) | no | CAA: 0 or 128 (critical). |
caa_tag | body | string (one of: issue, issuewild, iodef) | no | CAA tag. |
proxied | body | boolean | no | Cloudflare only, A/AAAA/CNAME: proxy through the CDN (off = DNS only). |
Example
curl -s -X POST "https://app.pbn.ltd/api/v1/sites/123/dns" \
-H "Authorization: Bearer $PBN_API_KEY" \
-H "Content-Type: application/json" \
-d '{"type": "TXT", "name": "@", "value": "google-site-verification=abc123"}'
import os
import requests
headers = {"Authorization": "Bearer " + os.environ["PBN_API_KEY"]}
r = requests.post("https://app.pbn.ltd/api/v1/sites/123/dns", headers=headers, json={"type": "TXT", "name": "@", "value": "google-site-verification=abc123"}, timeout=120)
print(r.status_code, r.json())
const res = await fetch("https://app.pbn.ltd/api/v1/sites/123/dns", {
method: "POST",
headers: {Authorization: `Bearer ${process.env.PBN_API_KEY}`, "Content-Type": "application/json"},
body: JSON.stringify({"type": "TXT", "name": "@", "value": "google-site-verification=abc123"})
});
console.log(res.status, await res.json());
Response
201
{
"data": {
"id": 5501,
"type": "MX",
"name": "@",
"value": "10 mail.example.com",
"proxied": false,
"updated_at": "2026-09-19T10:00:00Z",
"parts": {
"priority": 10,
"target": "mail.example.com"
}
}
}
Errors: conflict, not_found, rate_limited, scope_missing, unauthorized, validation_failed
Change a DNS record
PATCH/api/v1/sites/{site_id}/dns/{record_id}Scope dns:write
Changes a record; send only the fields that change.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
site_id | path | integer | yes | The site id (see GET /sites). |
record_id | path | integer | yes | The DNS record id. |
type | body | string (one of: A, AAAA, CNAME, TXT, MX, SRV, CAA, NS) | no | Record type. |
name | body | string | no | "@" for the domain itself, or a name like blog, shop.eu, _dmarc, _sip._tcp. |
value | body | string | no | IPv4 (A), IPv6 (AAAA), host name (CNAME, MX, SRV target, NS), text (TXT) or CA domain (CAA). |
priority | body | integer | no | MX and SRV. |
weight | body | integer | no | SRV. |
port | body | integer | no | SRV. |
caa_flags | body | integer (one of: 0, 128) | no | CAA: 0 or 128 (critical). |
caa_tag | body | string (one of: issue, issuewild, iodef) | no | CAA tag. |
proxied | body | boolean | no | Cloudflare only, A/AAAA/CNAME: proxy through the CDN (off = DNS only). |
Example
curl -s -X PATCH "https://app.pbn.ltd/api/v1/sites/123/dns/5501" \
-H "Authorization: Bearer $PBN_API_KEY" \
-H "Content-Type: application/json" \
-d '{"value": "google-site-verification=xyz789"}'
import os
import requests
headers = {"Authorization": "Bearer " + os.environ["PBN_API_KEY"]}
r = requests.patch("https://app.pbn.ltd/api/v1/sites/123/dns/5501", headers=headers, json={"value": "google-site-verification=xyz789"}, timeout=120)
print(r.status_code, r.json())
const res = await fetch("https://app.pbn.ltd/api/v1/sites/123/dns/5501", {
method: "PATCH",
headers: {Authorization: `Bearer ${process.env.PBN_API_KEY}`, "Content-Type": "application/json"},
body: JSON.stringify({"value": "google-site-verification=xyz789"})
});
console.log(res.status, await res.json());
Response
200
{
"data": {
"id": 5501,
"type": "MX",
"name": "@",
"value": "10 mail.example.com",
"proxied": false,
"updated_at": "2026-09-19T10:00:00Z",
"parts": {
"priority": 10,
"target": "mail.example.com"
}
}
}
Errors: not_found, rate_limited, scope_missing, unauthorized, validation_failed
Delete a DNS record
DELETE/api/v1/sites/{site_id}/dns/{record_id}Scope dns:write
Deletes a record; it is removed at the DNS provider within a minute or two.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
site_id | path | integer | yes | The site id (see GET /sites). |
record_id | path | integer | yes | The DNS record id. |
Example
curl -s -X DELETE "https://app.pbn.ltd/api/v1/sites/123/dns/5501" \
-H "Authorization: Bearer $PBN_API_KEY"
import os
import requests
headers = {"Authorization": "Bearer " + os.environ["PBN_API_KEY"]}
r = requests.delete("https://app.pbn.ltd/api/v1/sites/123/dns/5501", headers=headers, timeout=120)
print(r.status_code, r.json())
const res = await fetch("https://app.pbn.ltd/api/v1/sites/123/dns/5501", {
method: "DELETE",
headers: {Authorization: `Bearer ${process.env.PBN_API_KEY}`}
});
console.log(res.status, await res.json());
Response
200
{
"data": {
"deleted": true,
"id": 5501
}
}
Errors: not_found, rate_limited, scope_missing, unauthorized