Create DNS zones and manage their records. Zones are served by ns1.vps.org, ns2.vps.org and ns3.vps.org.
A zone holds the records for one domain. Every change you make through the API is pushed to the VPS.org nameservers straight away. To serve a domain from these zones, set its nameservers at your registrar to ns1.vps.org, ns2.vps.org and ns3.vps.org.
Changes are saved and published in one step: if the nameservers refuse a change, the request returns 502 and nothing is saved. A zone cannot be created for a domain another account already manages, a parent or child of another account's zone, or a VPS.org reserved name.
Required permission:
dns:list (GET), dns:create (POST), dns:update (PUT, PATCH, sync), dns:delete (DELETE), dns:*
Returns your zones, newest first, 25 per page. Records are not included here; fetch a single zone to get them.
| Parameter | Type | Required | Description |
|---|---|---|---|
domain |
string | No | Return only the zone with exactly this domain name |
page |
integer | No | Page number, starting at 1 |
curl -X GET "https://admin.vps.org/api/v1/dns-zones/?domain=example.com" \
-H "Authorization: Bearer YOUR_API_TOKEN"
import requests
url = "https://admin.vps.org/api/v1/dns-zones/"
headers = {"Authorization": "Bearer YOUR_API_TOKEN"}
response = requests.get(url, headers=headers, params={"domain": "example.com"})
for zone in response.json()["results"]:
print(zone["uuid"], zone["domain"], zone["record_count"])
const response = await fetch('https://admin.vps.org/api/v1/dns-zones/?domain=example.com', {
headers: { 'Authorization': 'Bearer YOUR_API_TOKEN' }
});
const data = await response.json();
console.log(data.results);
{
"count": 1,
"next": null,
"previous": null,
"results": [
{
"uuid": "c7a1e3f0-2b4d-4e6a-9c8b-0d1f2e3a4b5c",
"domain": "example.com",
"created_at": "2026-09-06T03:11:48.829693Z",
"record_count": 5
}
]
}
| Field | Type | Description |
|---|---|---|
uuid |
string | Zone identifier |
domain |
string | Domain name, stored in lowercase |
created_at |
datetime | Creation time (ISO 8601, UTC) |
record_count |
integer | Number of records in the zone, including the three NS records |
| 200 | Success |
| 403 | Missing or invalid API token, or the token lacks the required permission |
Creates a zone and publishes it. The zone starts with three NS records for ns1, ns2 and ns3.vps.org, which are system records and cannot be edited or deleted.
| Parameter | Type | Required | Description |
|---|---|---|---|
domain |
string | Yes | The domain name, for example example.com |
curl -X POST "https://admin.vps.org/api/v1/dns-zones/" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"domain": "example.com"}'
{
"uuid": "c7a1e3f0-2b4d-4e6a-9c8b-0d1f2e3a4b5c",
"domain": "example.com",
"created_at": "2026-09-14T21:02:11.402113Z",
"records": [
{
"uuid": "1f2e3d4c-5b6a-4978-8a9b-0c1d2e3f4a5b",
"record_type": "NS",
"name": "@",
"value": "ns1.vps.org",
"ttl": 86400,
"priority": null,
"created_at": "2026-09-14"
},
...
],
"record_count": 3
}
| 201 | Zone created |
| 400 | Missing or invalid domain name |
Returns one zone with all of its records in a records array. The response has the same shape as the create response above.
curl -X GET "https://admin.vps.org/api/v1/dns-zones/c7a1e3f0-2b4d-4e6a-9c8b-0d1f2e3a4b5c/" \
-H "Authorization: Bearer YOUR_API_TOKEN"
| 200 | Success |
| 404 | Not found, or it belongs to another account |
Removes the zone from all three nameservers, checks that none of them still serves it, and then deletes the zone and its records. If a nameserver still answers for the zone, the request fails and the zone is kept so you can retry.
curl -X DELETE "https://admin.vps.org/api/v1/dns-zones/c7a1e3f0-2b4d-4e6a-9c8b-0d1f2e3a4b5c/" \
-H "Authorization: Bearer YOUR_API_TOKEN"
| 204 | Deleted. The response has no body. |
| 400 | A nameserver still serves the zone. The zone was not deleted; the detail field lists the errors. |
| 404 | Not found, or it belongs to another account |
GET returns every record in the zone as a plain array (not paginated), sorted by type and name. POST adds a record to the zone and publishes it.
| Parameter | Type | Required | Description |
|---|---|---|---|
record_type |
string | Yes | A, AAAA, CNAME, MX, NS, TXT, SRV, PTR, SOA, CAA |
name |
string | Yes | @ for the domain itself, or a label such as www. Names are stored in lowercase. |
value |
string | Yes | The record data, for example an IP address or a hostname. Hostnames do not need a trailing dot and TXT values do not need quotes; both are added when the record is published. |
ttl |
integer | Yes | Time to live in seconds |
priority |
integer | MX and SRV only | Required for MX and SRV records and ignored for every other type. For SRV, put weight, port and target in value. |
curl -X POST "https://admin.vps.org/api/v1/dns-zones/c7a1e3f0-2b4d-4e6a-9c8b-0d1f2e3a4b5c/records/" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"record_type": "MX", "name": "@", "value": "mail.example.com", "ttl": 3600, "priority": 10}'
import requests
zone_uuid = "c7a1e3f0-2b4d-4e6a-9c8b-0d1f2e3a4b5c"
url = f"https://admin.vps.org/api/v1/dns-zones/{zone_uuid}/records/"
headers = {"Authorization": "Bearer YOUR_API_TOKEN"}
data = {"record_type": "A", "name": "www", "value": "203.0.113.10", "ttl": 3600}
response = requests.post(url, headers=headers, json=data)
print(response.status_code, response.json())
{
"uuid": "9d430082-5562-42b4-a0b2-12a6f6c862f9",
"record_type": "MX",
"name": "@",
"value": "mail.example.com",
"ttl": 3600,
"priority": 10,
"created_at": "2026-09-14"
}
| Field | Type | Description |
|---|---|---|
uuid |
string | Record identifier, used by the /api/v1/dns-records/ endpoints |
priority |
integer | null | Priority for MX and SRV records, otherwise null |
created_at |
date | Creation date only (YYYY-MM-DD), without a time |
| 200 | GET: the zone's records |
| 201 | POST: record created |
| 400 | Validation error, for example an unknown record type, a missing ttl, or an MX or SRV record without priority |
| 404 | Not found, or it belongs to another account |
Pushes the zone and all of its records to the nameservers again. Record changes are published automatically, but publishing is best effort and a failure does not fail the original request, so use this when a change does not show up in DNS lookups. No request body is needed.
curl -X POST "https://admin.vps.org/api/v1/dns-zones/c7a1e3f0-2b4d-4e6a-9c8b-0d1f2e3a4b5c/sync/" \
-H "Authorization: Bearer YOUR_API_TOKEN"
{
"detail": "Zone example.com synced to PowerDNS"
}
GET returns the records of all your zones, 25 per page, ordered by domain, type and name. POST creates a record like the zone records endpoint, but takes the zone in the body as zone_uuid.
| Parameter | Type | Required | Description |
|---|---|---|---|
zone |
string | No | Only records of the zone with this uuid |
record_type |
string | No | Only records of this type, for example MX (case insensitive) |
page |
integer | No | Page number, starting at 1 |
curl -X GET "https://admin.vps.org/api/v1/dns-records/?zone=c7a1e3f0-2b4d-4e6a-9c8b-0d1f2e3a4b5c&record_type=A" \
-H "Authorization: Bearer YOUR_API_TOKEN"
curl -X POST "https://admin.vps.org/api/v1/dns-records/" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"zone_uuid": "c7a1e3f0-2b4d-4e6a-9c8b-0d1f2e3a4b5c", "record_type": "TXT", "name": "@", "value": "v=spf1 mx -all", "ttl": 3600}'
{
"count": 1,
"next": null,
"previous": null,
"results": [
{
"uuid": "4b8e2c10-7d3f-4a5b-9e6c-1a2b3c4d5e6f",
"record_type": "A",
"name": "www",
"value": "203.0.113.10",
"ttl": 3600,
"priority": null,
"created_at": "2026-09-14"
}
]
}
| 200 | GET: success |
| 201 | POST: record created |
| 400 | Validation error, or zone_uuid is missing or not one of your zones |
GET returns one record. PUT replaces it and needs record_type, name, value and ttl. PATCH changes only the fields you send. DELETE removes the record and returns 204 with no body. Changes are published straight away. The NS records created with the zone are system records: updating or deleting them returns 403.
curl -X PATCH "https://admin.vps.org/api/v1/dns-records/4b8e2c10-7d3f-4a5b-9e6c-1a2b3c4d5e6f/" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"ttl": 300}'
| 200 | GET, PUT or PATCH: the record |
| 204 | Deleted. The response has no body. |
| 400 | Validation error |
| 403 | The record is a system record, or the token lacks the required permission |
| 404 | Not found, or it belongs to another account |
Validation errors return 400 with the problem keyed by field name:
{
"priority": ["MX records require a priority value"]
}
Query the VPS.org nameservers directly to confirm a change is live before your registrar delegation or resolver caches catch up:
dig @ns1.vps.org example.com A
dig @ns2.vps.org example.com MX
dig @ns3.vps.org www.example.com