Engineering
How to register domains in bulk through an API
Register domains in bulk through an API by checking an exact list first, then sending one idempotent request per domain. The safe workflow, and its limits.
The short answer
Checking domain availability in bulk and registering domains in bulk are two different operations. A list of exact names can be checked for availability in one API call, but each domain actually bought should be its own registration request with its own idempotency key, so one failure or one already-taken name never blocks the rest of the batch. A row marked "unknown" means the registry did not answer in time, and a row marked "premium" means the name is not sold here yet; neither means the name is taken. As of October 2026, ResellerHQ's POST /v1/domains/check checks up to 100 exact domain names in one call, and the dashboard's Bulk import page does the same from a pasted list or an uploaded CSV file, though domain registration itself still runs in the sandbox only.
To register domains in bulk through an API you need two operations rather than one, and conflating them is a frequent mistake in a bulk workflow. Checking is a read: you hand over a list of names and get back which ones are free. Registering is a write that spends money and can only ever happen once per name, so it has to be sent, tracked and retried differently from a check. This article walks through both, using the public documentation and route behaviour of ResellerHQ's domains API as the worked example, and links out rather than repeating the per-vendor rate-limit figures and the idempotency-key pattern already covered elsewhere on this site.
Why are checking and registering two different operations?
A check costs nothing and changes nothing: you send a list of names and get back a verdict for each. A registration charges your wallet and, if it succeeds, takes a name off the market for good, so it cannot be batched the same carefree way a check can.
That distinction shows up directly in how the API is shaped. ResellerHQ's check route takes an array of up to 100 domains in one call and returns a row per name with no money moved (Domains). Its register route takes exactly one domain per call, not an array, and every successful call debits the wallet for that name's price times the years registered (Domains). A batch of fifty names you want to buy is therefore one check call and up to fifty separate register calls, not two calls total.
Sending registrations one at a time is also simpler to reason about when something goes wrong. If a check fails, you retry the whole check: nothing was committed. If one registration out of fifty fails, nothing about the other forty-nine changes, because they were forty-nine separate requests in the first place.
Is a single search call the same as a bulk availability check?
No. A name search answers "what are my options starting from this one word", and a bulk check answers "which of these exact domains can I buy right now." They serve different stages of the same job.
ResellerHQ's GET /v1/domains/search takes a bare name or a full domain and prices it across every ending on offer, which is the feature built for finding a name: "Search one name across every ending at once" is literally one of the three things the product's domains page lists it can do. A premium name is left out of search results entirely, because it has no single yearly price to show next to the others, and a name the registrar could not answer for comes back marked unknown rather than being called taken (Domains).
POST /v1/domains/check is a different endpoint built for a different question: given a specific list of up to 100 exact domains, which are available to buy. It is the right tool once you already have the list, whether that list came from a customer's intake form or a CSV of a portfolio you are consolidating.
GET /domains/search | POST /domains/check | |
|---|---|---|
| Input | One bare name or full domain | Up to 100 exact domain names |
| What it answers | Which endings are available for this name, and at what price | Which of these specific names are available |
| Premium names | Left out of the results | Returned, marked premium, with a null price |
| A name the registrar could not answer | Marked unknown, kept in the results with its ordinary price | Marked unknown, with a null price |
| Good for | Finding a name | Buying a list you already have |
Source: Domains.
Running a search once per ending you care about, across a long list of names, is not a substitute for a bulk check: it is slower, it returns pricing for endings you may not want, and it still is not checking the exact set of domains you intend to buy. Use search to find names, and check to confirm the ones you already picked.
What do "unknown" and "premium" rows mean in a bulk check?
Neither means "taken," and treating them that way loses a sale or wastes a retry on a name that was never going to come back differently.
A row marked unknown means the registry did not answer the check in time. ResellerHQ's docs are explicit that an unknown row keeps its ordinary price and should simply be tried again shortly (Domains); it is a timing problem, not an availability answer. A row marked premium means the registry prices that name outside its normal per-year fee, and ResellerHQ specifically does not sell premium names through the API yet, so a premium row comes back with a null price and cannot be registered - attempting it answers 422 premium_domain (Domains). Nobody necessarily owns a premium name; it is simply not on sale here yet, which is a different fact from a name someone else has already registered.
A full bulk check can report six distinct outcomes for a single name, and only one of them is a straightforward purchase decision:
| Row says | What it means | Register it now? |
|---|---|---|
| Available | Free to register at the price shown | Yes |
| Taken | Someone else already owns it | No |
| Ending not sold | That TLD is not on offer at all | No |
| Not a valid name | The name itself is malformed | No, fix the name |
Could not check (unknown) | The registry did not answer in time | Not yet; check it again |
| Premium | Priced outside the normal fee; not sold here yet | No |
Source: Domains.
How do you register domains in bulk through an API safely?
The safe pattern is: one check call for the whole list, then one independent, idempotent register call per name you decide to buy.
- Build the exact list. Collect the specific domain names you want, not a topic to search broadly. This might come from a customer's order form or a CSV export of names you are migrating.
- Check the list in one call. Send up to 100 names to
POST /v1/domains/check. Anything longer than 100 is sent as more than one check call. - Keep only the rows marked available. Leave
taken,unsold,invalidandpremiumrows out of the next step entirely, and setunknownrows aside to check again shortly. - Register each one as its own request. For every name you are buying, send a separate
POST /v1/domainswith a fresh, uniqueIdempotency-Keyheader on that call. If a connection drops mid-request, retrying with the same key cannot register the name twice; the server replays the first outcome instead of running it again (Domains). Our idempotency keys and webhooks guide covers the pattern and its 409/422 behaviour in detail, so it is not repeated here. - Let a
pendingregistration settle on its own. A registration can come backpendingwhile the registrar finishes the order; it becomesactiveby itself with nothing further to send (Domains). - Retry only what failed. A name that failed for a reason that might change, such as a timeout, can be retried with a brand-new idempotency key for that new attempt; a name that failed with a definite answer, such as
409 domain_taken, should simply be dropped from the batch.
Doing it this way means a batch of fifty names you want to buy is one check call and up to fifty independent register calls, each of which can succeed or fail without touching the others.
How do rate limits affect a bulk domain workflow?
They set how fast step 4 above can run, and the ceiling varies enormously by vendor, so check it before you fire off fifty register calls back to back. Published domain reseller API rate limits differ by a factor of more than 100; the full per-vendor table, with each figure's own source link, is already published in domain reseller APIs compared and is not repeated here. If a vendor's limit is low, send your register calls with modest concurrency and a queue rather than all at once, and read any rate-limit response headers the vendor documents instead of hard-coding a number.
How do you import a domain portfolio from a CSV file?
By checking the names in the file the same way you would check a list typed by hand, then registering the available ones one at a time; ResellerHQ's dashboard does exactly this for you. Its Bulk import page, under Domains, takes a dropped or uploaded .csv or .txt file, guesses which column holds the domain names, and lets you confirm or change that column before checking anything.
From there, the page follows the same shape as the API workflow above:
- It checks up to 100 names from the file in one call to
/domains/check; from a longer file, only the first 100 are checked. - Each row is shown with its verdict: available, taken, ending not sold, not a valid name, could not check, or premium, using the same six outcomes described above.
- Rows marked
unknownorpremiumcan never be ticked for registration, so they cannot be bought by mistake. - Registering the ticked rows sends one
POST /domainsper domain, each with its own freshly generated idempotency key, running four at a time by default. A failure that leaves your wallet able to pay, such as a name someone else bought moments after the check, is reported against that row only and the rest of the batch keeps going. Running out of funds is the exception: nothing after it could be paid for either, so the remaining rows are not tried. - Anything that fails can be retried from the same screen without re-checking the whole file again.
If you are building your own CSV importer against the API rather than using the dashboard, this is the behaviour to copy: check the file's names in batches of up to 100, then register each confirmed name as its own idempotent request, and surface per-row failures instead of failing the whole import.
Where does ResellerHQ fit for bulk domain registration today?
ResellerHQ's domain availability check and its dashboard import page both work today, in the sandbox; live domain registration does not yet, and that is worth being direct about before you build against it. POST /v1/domains/check checks up to 100 exact names per call, POST /v1/domains registers one at a time with an optional Idempotency-Key header whose outcome is stored for 24 hours, and the dashboard's Bulk import page runs both of those for you from a pasted list or an uploaded CSV file (Domains). Domains are listed as "Open in the sandbox" on the product overview, and on the live side every domain route currently answers 422 not_available; sandbox domains are not registered anywhere (Domains).
So a bulk import built against ResellerHQ today is real end-to-end testing of the check-then-register workflow, the idempotency behaviour, and the CSV import page itself, against sandbox data rather than a live registry. For how this compares with vendors whose domain APIs are live now, see domain reseller APIs compared, and for a fuller test plan covering retries and webhooks before any go-live, see how to test a reseller API integration in a sandbox.
Questions
- No, not as one call. A bulk availability check can cover up to 100 exact names in one request, but registering is a financial transaction against your wallet, so it is sent as its own request per domain, each with its own idempotency key. That way one domain being taken, over your balance, or failing for any other reason does not stop the rest of the batch.
- A search takes one name and prices it across every ending a registrar offers, which is useful for finding a name to begin with. A bulk check takes a list of exact domains, up to 100 at a time, and tells you which of those specific names are free to buy. They answer different questions, and a search result is not a substitute for checking the exact list you actually want to buy.
- It means the registry could not be reached to answer in time, not that the name is taken. Treat it as a row to check again shortly, separately from the rows marked available or taken.
- A premium name is one a registry prices outside its normal yearly fee. ResellerHQ does not sell premium names through its API today, so a premium row comes back with no price and cannot be registered. It is a distinct outcome from "taken": nobody necessarily owns it, it is simply not available to buy through the API yet.
- An idempotency key makes one specific request safe to retry; it has no meaning across two different domains. Giving each registration its own key means a dropped connection on domain A can be retried safely without touching domain B's order, and a batch of 40 registrations becomes 40 independent, individually retryable operations instead of one all-or-nothing call.
- Up to 100 exact domain names in one call to POST /v1/domains/check. If you are writing your own client, send a longer list as more than one call of 100 or fewer. The dashboard's own Bulk import page does not split a long file: it checks the first 100 names in it, and says so on screen alongside the number of names the file held.