Nossic DNS API

Manage your domains and DNS records from scripts, CI jobs and tools: add records, renew certificates with DNS challenges, keep a home address up to date. Anything you can do in the app, you can do here.

Getting started

  1. Sign in to the Nossic DNS app with your Nossic ID and add your domain.
  2. Open API keys and create a key. Copy it straight away: it's shown once.
  3. Send it with every request:
# List your domains
curl https://app.dns.nossic.uk/api/v1/domains \
  -H "Authorization: Bearer ndns_…"

The base address is https://app.dns.nossic.uk/api/v1. Requests and responses are JSON. There's also an OpenAPI 3.1 description for generating clients.

API keys

A key acts as you, limited to what you choose when you create it:

Adding, claiming and removing domains needs a key for all your domains with write access. Keys look like ndns_ followed by an id and a secret. We keep only a hash of the secret, so a lost key can't be shown again: revoke it and create another. Revoking works straight away.

# Which key is this, and what can it do?
curl https://app.dns.nossic.uk/api/v1/me -H "Authorization: Bearer $NOSSIC_DNS_KEY"

Name servers

To use Nossic DNS, set your domain's name servers at the registrar where you bought it to exactly these two:

Name server 1ns1.nossic.uk
Name server 2ns2.nossic.uk

Every domain in the API includes them in nameservers, and its status says whether the registry points it here yet.

Requests and errors

Errors have an HTTP status and a body like this:

{ "error": { "code": "invalid", "message": "www is a CNAME, which must be the only record for its name." } }
StatusMeans
400The request isn't valid, or breaks a DNS rule (such as a CNAME next to other records).
401No key, or it's invalid, expired or revoked.
403The key can't do that (read-only, or not for all domains).
404No such domain in your account (or the key's), record or endpoint.
409The domain is in another account (see claiming), or the zone changed at the same moment: try again.
429Too many requests.

Domains

GET/domains

Your domains (the ones this key can use).

{
  "domains": [{
    "name": "example.com",
    "kind": "tenant",
    "status": "active",
    "nameservers": ["ns1.nossic.uk", "ns2.nossic.uk"],
    "delegatedTo": ["ns1.nossic.uk", "ns2.nossic.uk"],
    "createdAt": "2026-10-12T10:00:00.000Z",
    "checkedAt": "2026-10-12T10:05:00.000Z",
    "activeAt": "2026-10-12T10:05:00.000Z"
  }]
}

status is pending (not pointed at Nossic DNS yet), active (the registry uses our name servers), partial (only some of them) or moved (was active, now points elsewhere). We check pending domains every few minutes.

POST/domains

Add a domain. Body: {"name": "example.com"}. It starts with no records, and is pending until you change its name servers.

curl -X POST https://app.dns.nossic.uk/api/v1/domains \
  -H "Authorization: Bearer $NOSSIC_DNS_KEY" -H "Content-Type: application/json" \
  -d '{"name": "example.com"}'

You can add whole domains you can register (example.com, example.co.uk), not subdomains. Each account can have up to 25.

GET/domains/{domain}

One domain, with its current serial and number of records.

POST/domains/{domain}/check

Check now whether the registry points the domain at Nossic DNS, and get the updated status.

GET/domains/{domain}/zone

Every record as a standard zone file (text).

DELETE/domains/{domain}

Remove the domain and all its records. Change its name servers at the registrar first. The name stays reserved for you for 30 days.

Claiming a domain from another account

If someone else has already added your domain, POST /domains answers 409 with a TXT record to create:

{ "error": { "code": "domain_taken", "message": "…",
  "claim": { "name": "_nossic-dns-claim.example.com", "type": "TXT", "value": "nossic-dns-claim=…" } } }

Add that record at the domain's current DNS provider, wait a few minutes, then call POST /domains/{domain}/claim. The domain moves to your account with no records.

Records

GET/domains/{domain}/records

Every record. Filter with ?name=www and ?type=A.

{
  "serial": 2026101203,
  "records": [{
    "id": "r_3kQe0vV1u2zXl9aB",
    "name": "www",
    "fqdn": "www.example.com.",
    "type": "A",
    "ttl": 300,
    "content": "192.0.2.10",
    "data": "192.0.2.10",
    "fields": { "address": "192.0.2.10" },
    "locked": null
  }]
}

locked says why a record can't be changed: the SOA and the domain's own NS records are managed by Nossic DNS.

POST/domains/{domain}/records

Add a record. Answers 201 with the record.

curl -X POST https://app.dns.nossic.uk/api/v1/domains/example.com/records \
  -H "Authorization: Bearer $NOSSIC_DNS_KEY" -H "Content-Type: application/json" \
  -d '{"name": "www", "type": "A", "ttl": 300, "content": "192.0.2.10"}'
GET/domains/{domain}/records/{id}

One record.

PUT/domains/{domain}/records/{id}

Change a record: send what changes (name, type, ttl, content); the rest stays. Answers with the record and its new id.

curl -X PUT https://app.dns.nossic.uk/api/v1/domains/example.com/records/r_3kQe0vV1u2zXl9aB \
  -H "Authorization: Bearer $NOSSIC_DNS_KEY" -H "Content-Type: application/json" \
  -d '{"content": "192.0.2.20"}'
DELETE/domains/{domain}/records/{id}

Delete a record. Answers 204.

Record sets

A record set is every record with one name and type, such as all the TXT records at _acme-challenge. Replacing a set in one call is the easiest way to automate: you don't need ids, and the change is all or nothing.

GET/domains/{domain}/rrsets/{name}/{type}

The set, with its TTL.

PUT/domains/{domain}/rrsets/{name}/{type}

Replace the set (or create it). Body: {"ttl": 60, "records": ["value", …]}. Items can also be {"content": …} objects.

curl -X PUT https://app.dns.nossic.uk/api/v1/domains/example.com/rrsets/@/MX \
  -H "Authorization: Bearer $NOSSIC_DNS_KEY" -H "Content-Type: application/json" \
  -d '{"ttl": 3600, "records": ["10 mx1.example.net", "20 mx2.example.net"]}'
DELETE/domains/{domain}/rrsets/{name}/{type}

Delete the whole set. Answers 204.

Record types

TypecontentExample
AIPv4 address192.0.2.10
AAAAIPv6 address2001:db8::10
CNAMEHost it's an alias ofexample.net
MXPriority and mail server10 mail.example.com
TXTAny text (we split long values for you)v=spf1 include:_spf.example.net ~all
SRVPriority, weight, port, target0 5 5060 sip.example.com
CAAFlags, tag, value0 issue letsencrypt.org
NSName server for a subdomain you hand to someone elsens1.other-dns.example
PTRHost namehost.example.com

Host names are always full names (mail.example.com); @ means the domain itself. A CNAME must be the only record for its name, and the domain itself can't be a CNAME.

Recipes

Let's Encrypt with certbot (DNS-01)

For wildcard certificates, or servers the internet can't reach. Save these two scripts and make them executable, with NOSSIC_DNS_KEY set to a read-and-write key for the domain:

# /etc/letsencrypt/nossic-auth.sh
#!/bin/sh
curl -fsS -X PUT "https://app.dns.nossic.uk/api/v1/domains/$CERTBOT_DOMAIN/rrsets/_acme-challenge/TXT" \
  -H "Authorization: Bearer $NOSSIC_DNS_KEY" -H "Content-Type: application/json" \
  -d "{\"ttl\": 60, \"records\": [\"$CERTBOT_VALIDATION\"]}" >/dev/null
sleep 10

# /etc/letsencrypt/nossic-cleanup.sh
#!/bin/sh
curl -fsS -X DELETE "https://app.dns.nossic.uk/api/v1/domains/$CERTBOT_DOMAIN/rrsets/_acme-challenge/TXT" \
  -H "Authorization: Bearer $NOSSIC_DNS_KEY"

# Then
certbot certonly --manual --preferred-challenges dns \
  --manual-auth-hook /etc/letsencrypt/nossic-auth.sh \
  --manual-cleanup-hook /etc/letsencrypt/nossic-cleanup.sh \
  -d example.com -d '*.example.com'

These hooks are for domains added as they are (example.com). For a certificate on a subdomain, put the subdomain into the record name, such as _acme-challenge.shop.

Dynamic DNS (keep a home address up to date)

# Run every 5 minutes from cron
IP=$(curl -fsS https://api.ipify.org)
curl -fsS -X PUT "https://app.dns.nossic.uk/api/v1/domains/example.com/rrsets/home/A" \
  -H "Authorization: Bearer $NOSSIC_DNS_KEY" -H "Content-Type: application/json" \
  -d "{\"ttl\": 300, \"records\": [\"$IP\"]}"

Back up a zone

curl -fsS https://app.dns.nossic.uk/api/v1/domains/example.com/zone \
  -H "Authorization: Bearer $NOSSIC_DNS_KEY" > example.com.zone

This is version 1 of the API. We add to it without breaking what is here. How we handle data: privacy notice · cookies.