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
- Sign in to the Nossic DNS app with your Nossic ID and add your domain.
- Open API keys and create a key. Copy it straight away: it's shown once.
- 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:
- Domains: all your domains (including ones you add later), or only the ones you pick.
- Permission: read only, or read and change records.
- Expiry: never, or after 30, 90 or 365 days.
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:
ns1.nossic.ukns2.nossic.ukEvery domain in the API includes them in nameservers, and its status says whether the registry points it here yet.
Requests and errors
- Names are relative to the domain:
@is the domain itself,wwwis www.example.com. Full names (www.example.com) work too. - Values go in
content, one string, such as"10 mail.example.com"for MX. See record types. You can sendfieldsinstead. - TTL is in seconds, 30 to 604800 (7 days); 3600 if left out. All records with the same name and type share one TTL, so a new TTL applies to the whole set.
- Record ids (
r_…) stay the same while a record is unchanged. Editing a record gives it a new id. - Changes go live straight away on our primary server, and on the secondary within a couple of seconds. Each change bumps the zone's
serial. - Rate limit: 120 requests a minute per key. Over that you get
429withRetry-After.
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." } }
| Status | Means |
|---|---|
| 400 | The request isn't valid, or breaks a DNS rule (such as a CNAME next to other records). |
| 401 | No key, or it's invalid, expired or revoked. |
| 403 | The key can't do that (read-only, or not for all domains). |
| 404 | No such domain in your account (or the key's), record or endpoint. |
| 409 | The domain is in another account (see claiming), or the zone changed at the same moment: try again. |
| 429 | Too many requests. |
Domains
/domainsYour 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.
/domainsAdd 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.
/domains/{domain}One domain, with its current serial and number of records.
/domains/{domain}/checkCheck now whether the registry points the domain at Nossic DNS, and get the updated status.
/domains/{domain}/zoneEvery record as a standard zone file (text).
/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
/domains/{domain}/recordsEvery 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.
/domains/{domain}/recordsAdd 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"}'
/domains/{domain}/records/{id}One record.
/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"}'
/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.
/domains/{domain}/rrsets/{name}/{type}The set, with its TTL.
/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"]}'
/domains/{domain}/rrsets/{name}/{type}Delete the whole set. Answers 204.
Record types
| Type | content | Example |
|---|---|---|
| A | IPv4 address | 192.0.2.10 |
| AAAA | IPv6 address | 2001:db8::10 |
| CNAME | Host it's an alias of | example.net |
| MX | Priority and mail server | 10 mail.example.com |
| TXT | Any text (we split long values for you) | v=spf1 include:_spf.example.net ~all |
| SRV | Priority, weight, port, target | 0 5 5060 sip.example.com |
| CAA | Flags, tag, value | 0 issue letsencrypt.org |
| NS | Name server for a subdomain you hand to someone else | ns1.other-dns.example |
| PTR | Host name | host.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.