curl --request PATCH \
--url https://dns.basaltic.sh/v1/zones/{zone_id} \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"description": "Production DNS",
"tags": {
"environment": "production",
"team": "backend"
}
}
'import requests
url = "https://dns.basaltic.sh/v1/zones/{zone_id}"
payload = {
"description": "Production DNS",
"tags": {
"environment": "production",
"team": "backend"
}
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.patch(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PATCH',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
description: 'Production DNS',
tags: {environment: 'production', team: 'backend'}
})
};
fetch('https://dns.basaltic.sh/v1/zones/{zone_id}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://dns.basaltic.sh/v1/zones/{zone_id}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PATCH",
CURLOPT_POSTFIELDS => json_encode([
'description' => 'Production DNS',
'tags' => [
'environment' => 'production',
'team' => 'backend'
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://dns.basaltic.sh/v1/zones/{zone_id}"
payload := strings.NewReader("{\n \"description\": \"Production DNS\",\n \"tags\": {\n \"environment\": \"production\",\n \"team\": \"backend\"\n }\n}")
req, _ := http.NewRequest("PATCH", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.patch("https://dns.basaltic.sh/v1/zones/{zone_id}")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"description\": \"Production DNS\",\n \"tags\": {\n \"environment\": \"production\",\n \"team\": \"backend\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://dns.basaltic.sh/v1/zones/{zone_id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Patch.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"description\": \"Production DNS\",\n \"tags\": {\n \"environment\": \"production\",\n \"team\": \"backend\"\n }\n}"
response = http.request(request)
puts response.read_body{
"zone": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"crn": "crn:dns::my-account:zone/example.com",
"name": "example.com",
"description": "Public zone for the marketing site",
"nameservers": [
"028t5cy4tqkff.triton.dns.basaltic.cloud",
"028t5cy4tqkff.proteus.dns.basaltic.cloud"
],
"soa": {
"primary_ns": "028t5cy4tqkff.triton.dns.basaltic.cloud",
"admin_email": "hostmaster@basaltic.sh",
"refresh": 10800,
"retry": 3600,
"expire": 604800,
"minimum": 3600
},
"visibility": "public",
"dnssec": {
"enabled": true,
"ksk_key_tag": 12345,
"zsk_key_tag": 54321,
"algorithm": 13,
"ds_records": [
{
"key_tag": 12345,
"algorithm": 13,
"digest_type": 2,
"digest": "B8FA03AA1BB49CC702C32C5C3FE6061BBDD0808371F43A28A8E8BE2738CC9861",
"rdata": "12345 13 2 B8FA03AA1BB49CC702C32C5C3FE6061BBDD0808371F43A28A8E8BE2738CC9861"
}
]
},
"tags": {
"environment": "production",
"team": "backend"
},
"ownership": {
"verified": false,
"verified_at": "2026-01-15T09:30:00Z",
"checked_at": "2026-04-14T09:30:00Z",
"recheck_deadline": "2026-04-28T09:30:00Z"
}
}
}{
"error": {
"code": "INVALID_INPUT",
"message": "Invalid request parameters",
"request_id": "550e8400-e29b-41d4-a716-446655440000"
}
}{
"error": {
"code": "UNAUTHORIZED",
"message": "Authentication required",
"request_id": "550e8400-e29b-41d4-a716-446655440000"
}
}{
"error": {
"code": "ACCESS_DENIED",
"message": "You don't have permission to perform this action",
"request_id": "550e8400-e29b-41d4-a716-446655440000"
}
}{
"error": {
"code": "NOT_FOUND",
"message": "Resource not found",
"request_id": "550e8400-e29b-41d4-a716-446655440000"
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "An internal error occurred",
"request_id": "550e8400-e29b-41d4-a716-446655440000"
}
}Update zone
Updates a zone’s description and tags. Omit description to keep it or send an empty string to clear it. Omitted tags are left alone; a tags map replaces the zone’s tag set, so an empty object clears it.
Tags gate policy as well as label the zone, so this is authorized against both the tags being requested and the tags the zone already carries — a principal fenced to one of them is refused by the other.
curl --request PATCH \
--url https://dns.basaltic.sh/v1/zones/{zone_id} \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"description": "Production DNS",
"tags": {
"environment": "production",
"team": "backend"
}
}
'import requests
url = "https://dns.basaltic.sh/v1/zones/{zone_id}"
payload = {
"description": "Production DNS",
"tags": {
"environment": "production",
"team": "backend"
}
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.patch(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PATCH',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
description: 'Production DNS',
tags: {environment: 'production', team: 'backend'}
})
};
fetch('https://dns.basaltic.sh/v1/zones/{zone_id}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://dns.basaltic.sh/v1/zones/{zone_id}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PATCH",
CURLOPT_POSTFIELDS => json_encode([
'description' => 'Production DNS',
'tags' => [
'environment' => 'production',
'team' => 'backend'
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://dns.basaltic.sh/v1/zones/{zone_id}"
payload := strings.NewReader("{\n \"description\": \"Production DNS\",\n \"tags\": {\n \"environment\": \"production\",\n \"team\": \"backend\"\n }\n}")
req, _ := http.NewRequest("PATCH", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.patch("https://dns.basaltic.sh/v1/zones/{zone_id}")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"description\": \"Production DNS\",\n \"tags\": {\n \"environment\": \"production\",\n \"team\": \"backend\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://dns.basaltic.sh/v1/zones/{zone_id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Patch.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"description\": \"Production DNS\",\n \"tags\": {\n \"environment\": \"production\",\n \"team\": \"backend\"\n }\n}"
response = http.request(request)
puts response.read_body{
"zone": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"crn": "crn:dns::my-account:zone/example.com",
"name": "example.com",
"description": "Public zone for the marketing site",
"nameservers": [
"028t5cy4tqkff.triton.dns.basaltic.cloud",
"028t5cy4tqkff.proteus.dns.basaltic.cloud"
],
"soa": {
"primary_ns": "028t5cy4tqkff.triton.dns.basaltic.cloud",
"admin_email": "hostmaster@basaltic.sh",
"refresh": 10800,
"retry": 3600,
"expire": 604800,
"minimum": 3600
},
"visibility": "public",
"dnssec": {
"enabled": true,
"ksk_key_tag": 12345,
"zsk_key_tag": 54321,
"algorithm": 13,
"ds_records": [
{
"key_tag": 12345,
"algorithm": 13,
"digest_type": 2,
"digest": "B8FA03AA1BB49CC702C32C5C3FE6061BBDD0808371F43A28A8E8BE2738CC9861",
"rdata": "12345 13 2 B8FA03AA1BB49CC702C32C5C3FE6061BBDD0808371F43A28A8E8BE2738CC9861"
}
]
},
"tags": {
"environment": "production",
"team": "backend"
},
"ownership": {
"verified": false,
"verified_at": "2026-01-15T09:30:00Z",
"checked_at": "2026-04-14T09:30:00Z",
"recheck_deadline": "2026-04-28T09:30:00Z"
}
}
}{
"error": {
"code": "INVALID_INPUT",
"message": "Invalid request parameters",
"request_id": "550e8400-e29b-41d4-a716-446655440000"
}
}{
"error": {
"code": "UNAUTHORIZED",
"message": "Authentication required",
"request_id": "550e8400-e29b-41d4-a716-446655440000"
}
}{
"error": {
"code": "ACCESS_DENIED",
"message": "You don't have permission to perform this action",
"request_id": "550e8400-e29b-41d4-a716-446655440000"
}
}{
"error": {
"code": "NOT_FOUND",
"message": "Resource not found",
"request_id": "550e8400-e29b-41d4-a716-446655440000"
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "An internal error occurred",
"request_id": "550e8400-e29b-41d4-a716-446655440000"
}
}dns:UpdateZone. See DNS permissions for the full list, what each one covers, and an example policy.Authorizations
An OAuth 2.0 bearer token, sent as Authorization: Bearer <token>.
This is the recommended way to authenticate.
Get one by exchanging a service account's access key pair at
POST /v1/oauth/token with grant_type=client_credentials. It is the
standard client-credentials grant, so any OAuth-aware library will
obtain and refresh it for you.
curl -s -u "$KEY_ID:$SECRET" -d grant_type=client_credentials \
https://iam.basaltic.sh/v1/oauth/token
Tokens last an hour by default. The same access key pair is separately your AWS SigV4 credential for the S3-compatible object endpoint, which speaks nothing else.
Path Parameters
DNS Zone ID
Body
Patches description and tags. The name, visibility and DNSSEC posture are fixed at creation; records are their own sub-resource.
Omit to preserve the description; send an empty string to clear it.
"Production DNS"
Omit to leave the zone's tags untouched. A present map REPLACES them, so send an empty object to clear them. Tags are policy-relevant — a statement can condition on basalt:ResourceTag/ — so changing them is authorized against both the tags requested and the tags already on the zone.
Show child attributes
Show child attributes
{
"environment": "production",
"team": "backend"
}
Response
The updated zone
Show child attributes
Show child attributes

