HarborDNS

API documentation

Manage zones and records from CI/CD, infrastructure-as-code, and internal tools over a small, predictable REST API.

View plans

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.

ScopeGrants
zones:readList and inspect zones and their status
zones:writeCreate and delete zones; import records
records:readRead record sets (rrsets) in a zone
records:writeApply 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.

StatusMeaningWhat to do
200 / 201SuccessContinue
401Missing or invalid tokenCheck the Authorization header
403Token lacks the required scope or plan accessRe-issue the token with the needed scope
404Zone or resource not foundVerify the identifier
409Idempotency key reused with a different bodyUse a new key for a new change
422Validation failedRead the field errors and fix the request
429Rate limit exceededWait 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.