NEW Bare Metal Servers with 20G Dedicated Unmetered Bandwidth 20G Dedicated Unmetered Servers Read more STATUS

Automate reverse DNS for a delegated block

Sep 22, 2026 4 min read

Once a whole block is delegated to your server, you get to name every address in it, and clicking through them one at a time in the portal wears thin quickly. A short script handles all of it: read the block's usable range, then put a PTR on each address that matters to you. Reach for this with a mail pool, a group of load-balancer addresses, or an IPv6 range that never gets listed at all. If reverse DNS is new to you, read Set reverse DNS for your IPs first; this page covers doing it by script.

One scope, one call shape

Your key needs ips.write (reading comes with it). Only two endpoints are involved: GET /v1/ips to discover your blocks, and PUT /v1/ips/rdns to name an address. You pass the address itself to the write, not a row id, so it works on any of your addresses, listed before or not.

Find the block

GET /v1/ips returns your addresses grouped by the resource they belong to. Each server lists its delegated blocks under prefixes along with the usable range:

curl -s https://api.amoni.app/v1/ips \
  -H "Authorization: Bearer nr_live_..."
"prefixes": [
  {
    "cidr": "203.0.113.8/29",
    "version": 4,
    "usable_from": "203.0.113.10",
    "usable_to": "203.0.113.14",
    "usable": 5,
    "ips": [ { "address": "203.0.113.10", "dns_name": "ip4-203-0-113-10.rdns.netrouting.net" } ]
  }
]

Any address from usable_from and usable_to is yours to name. The ips list only shows the ones that already have a name. For IPv6, usable is null since a /64 is far too big to count. There you name the particular addresses you use instead of looping over the range.

Name the addresses

Every write is a PUT /v1/ips/rdns with an address and a dns_name. The call is idempotent, so sending the same value twice does no harm, and created is true only on the first write to an address that wasn't listed yet. Here's a bash loop that names a mail pool across the block:

#!/usr/bin/env bash
set -euo pipefail
KEY="nr_live_..."
API="https://api.amoni.app/v1"
DOMAIN="mail.example.com"

for n in 10 11 12 13 14; do
  addr="203.0.113.$n"
  host="mx${n}.${DOMAIN}"
  curl -sf -X PUT "$API/ips/rdns" \
    -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
    -d "{\"address\": \"$addr\", \"dns_name\": \"$host\"}" \
    | jq -r '.data | "\(.address) -> \(.dns_name) (created: \(.created))"'
done

Every call returns the address, the name it now carries, and whether a new row was created:

{ "success": true, "data": {
    "id": 11687, "address": "203.0.113.12",
    "dns_name": "mx12.mail.example.com", "created": false,
    "message": "Reverse DNS updated."
} }

To clear a PTR, send an empty dns_name: {"address": "203.0.113.12", "dns_name": ""}. If you want a block to follow a source of truth, drive the same script from a config file. The write is idempotent, so a re-run only touches what's actually different.

Handle the two refusals

Catch these two errors by their code instead of lumping every non-200 together.

  • If the address is the block's network, gateway or broadcast you get 422 with code address_reserved. Skip those. A loop from usable_from to usable_to never hits them anyway.
  • An address outside any block delegated to you gets 404, never a 403. That way a typo in the range fails instead of being quietly accepted.

Without ips.write, a key gets 403 with code insufficient_scope. The rest uses the standard envelope: branch on success and read code when it's false.

The forward record still matters

A PTR is only half of a forward-confirmed pair. With mail in particular, the hostname you put in the PTR has to resolve forward to the same address in your own DNS. This API handles the reverse side on our nameservers. The matching A or AAAA record belongs to whoever runs the domain. Skip it and receiving mail servers will go on distrusting the address.

Questions we get

  • Do I need the row id? No, the by-address write only needs the address. Ids exist for addresses that are already listed, and the response gives you one if you want it.
  • Does this work for IPv6? Yes, and it's the only way to do it. We never enumerate a /64, so each IPv6 address you use gets named through this same call.
  • Will re-running my script cause churn? No. An unchanged value is a no-op on our side, which makes a scheduled sync safe to run.
  • How fast can I go? Each key is capped at 120 requests a minute. If the block is bigger than that, slow the loop down or spread it across a couple of minutes.

Still stuck?

Open a support ticket with the block and an address that fails. We'll check the delegation and tell you why that write was refused.

Built for production

Why teams stay with Netrouting

We connect you to the Internet using network engineers (and not order takers) and hardware and infrastructure that is built to last, so we can pick up where you left off when you need us.

  • Expert-Level Support Our staff is available 24 hours a day, 7 days a week to handle network administration and systems management issues as they occur.
  • Scalable Solutions Build whatever depth or breadth your infrastructure needs and then scale as required.
  • Enhanced Security Enable 2-factor authentication and also limit by IP address from the control panel to secure your account.
  • Cost-Efficient Infrastructure You will always receive the best value from your investment as you will be optimized for budget without any compromise on Quality.