API documentation
Manage zones and records from CI/CD, infrastructure-as-code, and internal tools over a small, predictable REST API.
Overview
The HarborDNS API is JSON over HTTPS. Requests send and receive application/json, every response includes an HTTP status code that reflects the result, and record changes are applied atomically so a zone is never left half-updated. The current version is v1; a future breaking change ships under a new version prefix, so integrations keep working.
Base URL
https://harbordns.dev.bastnet.ca/api/v1
Authentication
Create a scoped token under Settings → API tokens. The token is shown once at creation — store it in your secret manager and send it as a bearer token on every request. Tokens can be revoked at any time, which immediately stops all requests that use them.
curl https://harbordns.dev.bastnet.ca/api/v1/me \
-H "Authorization: Bearer YOUR_TOKEN"
Scopes
Grant a token only the permissions its job needs. A request that exceeds its scopes returns 403.
| Scope | Grants |
|---|---|
| zones:read | List and inspect zones and their status |
| zones:write | Create and delete zones; import records |
| records:read | Read record sets (rrsets) in a zone |
| records:write | Apply record changes and imports |
Pagination and rate limits
List endpoints accept page and per_page and return a meta object with the current page and total counts. Requests are rate limited per token according to your plan; when you exceed the limit the API returns 429 with a Retry-After header. Back off and retry after the interval it indicates.
Endpoints
GET /me /plan
Return the authenticated account, or its current plan and included capacity. Use /me as a connection check right after issuing a token.
GET /zones
List zones in the account. Filter with status and page with per_page. Requires zones:read.
curl "https://harbordns.dev.bastnet.ca/api/v1/zones?status=active&per_page=50" \
-H "Authorization: Bearer YOUR_TOKEN"
POST /zones
Create a zone. Requires zones:write. The response includes the assigned nameservers to set at your registrar.
curl -X POST https://harbordns.dev.bastnet.ca/api/v1/zones \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "example.com", "zone_type": "primary"}'
GET /zones/{zone} /zones/{zone}/status
Fetch a single zone, or just its serving status. Requires zones:read.
DELETE /zones/{zone}
Remove a zone and its records. Requires zones:write. This does not change nameservers at your registrar — remove or repoint the delegation there as well.
GET /zones/{zone}/rrsets
List the record sets in a zone. A record set groups all records that share a name and type. Filter with name, type, or search. Requires records:read.
POST /zones/{zone}/changes
Apply an atomic batch of record changes — the whole batch succeeds or nothing changes. Each request carries an idempotency_key: retrying the same key with the same body is safe and applies the change exactly once, which makes this endpoint reliable from CI/CD and retrying clients. Requires records:write.
curl -X POST https://harbordns.dev.bastnet.ca/api/v1/zones/example.com/changes \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"idempotency_key": "deploy-20260713-001",
"changes": [
{ "action": "upsert", "name": "www", "type": "A",
"ttl": 300, "records": ["192.0.2.42"] },
{ "action": "delete", "name": "old", "type": "A" }
]
}'
GET /zones/{zone}/export POST /zones/{zone}/import
Export the zone as a BIND-style file, or replace its editable records from zone_contents or an uploaded zone_file. Import requires records:write; the apex nameservers and SOA stay managed by HarborDNS.
Errors and retries
The API uses standard HTTP status codes. The body of an error includes a machine-readable message and, for validation errors, a field-level breakdown.
| Status | Meaning | What to do |
|---|---|---|
| 200 / 201 | Success | Continue |
| 401 | Missing or invalid token | Check the Authorization header |
| 403 | Token lacks the required scope or plan access | Re-issue the token with the needed scope |
| 404 | Zone or resource not found | Verify the identifier |
| 409 | Idempotency key reused with a different body | Use a new key for a new change |
| 422 | Validation failed | Read the field errors and fix the request |
| 429 | Rate limit exceeded | Wait for Retry-After, then retry |
Retry transient network failures and 429/5xx responses with the same idempotency_key. Do not retry a 422 without changing the request.