If you’ve ever tried automating some of your tasks with UltraDNS, you probably know it’s quite hard at the beginning. There are a few GitHub repositories with clients written in a few languages which can help you in achieving your tasks. All projects can be found here.

If you don’t want or cannot use those clients, there’s UltraDNS Rest API endpoint which you can use. There’s big document describing how to use this endpoint available here. Please note, you need to log in first to have access to that document.

Documentation has more than 350 pages and can be a little overwhelming at the beginning. That’s why I wanted to show you one example, where Rest API endpoint can be used to automate some of your work.

In this post, we will learn how to manage CNAME records in UltraDNS using PowerShell. Don’t worry if don’t want to use PowerShell, examples here are mostly just pure Rest requests and can be reused easily in any other language.

Working with UltraDNS


In order to send any request to UltraDNS Rest API, we need to obtain security token first. At this point I’m assumign you have some account in UltraDNS. Let’s write the code now:

$password ="some_password"
$ultraDnsUrl = "https://restapi.ultradns.com/v2/authorization/token"
$body= "grant_type=password&username=$userName&password=$password"
$result = Invoke-RestMethod -Method Post -Uri $ultraDnsUrl -Body $body -ContentType "application/x-www-form-urlencoded"
$token = $result.access_token

If your request is successful, you will get back an object with a few properties. access_token is the one which we need now.

Check if CNAME already exists

In our example, we’re in control of example.com domain. Our website is currently available under application.azurewebsite.net but we want it to be accessible under application.example.com.

Firstly, let’s try and check if application.example.com CNAME is already set in our domain and what application it’s pointing to.

$token = "token_from_previous_example"
$domain = "example.com"
$cname = "application"
$url = "https://restapi.ultradns.com/v2/zones/$domain./rrsets/CNAME/$cname"
try {
  $result = Invoke-RestMethod -Method Get -Uri $url -Headers @{"Authorization" = "Bearer $token"}
} catch {
Write-Host $_ | Format-List -Force | Out-String
$value =  $result.rrSets[0].rdata[0];

If there’s no CNAME value set, this request will throw an exception. For simplicity, we’re not checking the type of exception here. Please remember that there could be lots of other reasons why you’re getting an exception here. Most likely due to token time expiration.

If CNAME was already set, the response object will look like this:

    "zoneName": "example.com.",
    "rrSets": [
            "ownerName": "application.example.com.",
            "rrtype": "CNAME (5)",
            "ttl": 300,
            "rdata": [
    "queryInfo": {
        "sort": "OWNER",
        "reverse": false,
        "limit": 100
    "resultInfo": {
        "totalCount": 1,
        "offset": 0,
        "returnedCount": 1

As one CNAME cannot point to two different destinations, you can select first element from both rrSets and rdata arrays to get to currently set website destination.

Add or update CNAME value

There’s one endpoint which you can use to either add or update CNAME value. Make sure you’ll use:

  • POST request for new CNAME
  • PATCH request to update already existing CNAME

If you use POST request with already existing CNAME, you will get an exception. Similarly, don’t try to use PATCH if CNAME doesn’t exists yet.

$token = "token_from_previous_example"
$domain = "example.com"
$cname = "application"
$destinationUrl = "application.azurewebsite.net"
$ttl = 300
$url = "https://restapi.ultradns.com/v2/zones/$domain./rrsets/CNAME/$cname"
$method = "POST" or "PATCH"

$body = @{
	"ttl"= $ttl
	"rdata"= @("$destinationUrl.")

$result = Invoke-RestMethod -Method $method -Uri $url -Body (ConvertTo-Json $body) -ContentType "application/json" -Headers @{"Authorization" = "Bearer $token"}

You can make sure that value was set correctly, checking:

$result.message -eq "Successful"


The case described in this post is one of the many. But I hope this will give you some taste of that API and help you with your work.