VPS.org API

REST API Documentation

DNS Management API

Create DNS zones and manage their records. Zones are served by ns1.vps.org, ns2.vps.org and ns3.vps.org.

Endpoints 13
Base Path /api/v1/dns-zones, /api/v1/dns-records

Overview

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:*

GET /api/v1/dns-zones/

List All DNS Zones

Returns your zones, newest first, 25 per page. Records are not included here; fetch a single zone to get them.

Query Parameters

Parameter Type Required Description
domain string No Return only the zone with exactly this domain name
page integer No Page number, starting at 1

Example Request

cURL
Python
JavaScript
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);

Example Response

{
  "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
    }
  ]
}

Response Fields

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

Response Status Codes

200 Success
403 Missing or invalid API token, or the token lacks the required permission
POST /api/v1/dns-zones/

Create DNS Zone

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.

Request Body Parameters

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"}'

Example Response

{
  "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
}

Response Status Codes

201 Zone created
400 Missing or invalid domain name
GET /api/v1/dns-zones/{uuid}/

Get DNS Zone Details

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"

Response Status Codes

200 Success
404 Not found, or it belongs to another account
DELETE /api/v1/dns-zones/{uuid}/

Delete DNS Zone

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"

Response Status Codes

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 POST /api/v1/dns-zones/{uuid}/records/

List or Add Records in a Zone

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.

Request Body Parameters (POST)

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.

Example Request

cURL
Python
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())

Example Response

{
  "uuid": "9d430082-5562-42b4-a0b2-12a6f6c862f9",
  "record_type": "MX",
  "name": "@",
  "value": "mail.example.com",
  "ttl": 3600,
  "priority": 10,
  "created_at": "2026-09-14"
}

Response Fields

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

Response Status Codes

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
POST /api/v1/dns-zones/{uuid}/sync/

Republish a Zone

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 POST /api/v1/dns-records/

List or Create Records Across Zones

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.

Query Parameters

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"
    }
  ]
}

Response Status Codes

200 GET: success
201 POST: record created
400 Validation error, or zone_uuid is missing or not one of your zones
GET PUT PATCH DELETE /api/v1/dns-records/{uuid}/

Get, Update or Delete a Record

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.

When you PATCH the priority of an MX or SRV record, send record_type in the same request. A PATCH body with priority but without record_type clears the priority.
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}'

Response Status Codes

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

Error Handling

Validation errors return 400 with the problem keyed by field name:

{
  "priority": ["MX records require a priority value"]
}

Testing DNS Changes

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