Our Help Center has a fresh new feel.

We've made it easier to browse, search, and get to the information you need. Use the left navigation menu to explore by topic, or search for something specific.

API: Managing Domains

The Storefront API lets you manage your customers' domain portfolio programmatically without needing to log in to Storefront Manager. This is useful if you want to automate renewals, keep domain data in sync with your own platform, migrate a portfolio in bulk, or build tooling for your support team.

Before you begin

Requirements

  • An active OpenSRS Storefront with API access enabled
  • API credentials (Client ID and Client Secret) — see API DNS Management Guide for how to generate these and obtain an access token
  • Your OpenSRS account balance above $10 to keep your Storefront active

Domain endpoints

Get domain details

Returns everything known about one domain: its status and dates, current settings, the customer who owns it, and the transfer auth code.

GET /v1/domain/{domain}

Response: 200 OK — a domain object.

FieldTypeDescription
namestringThe domain name
registration_datedatetime or nullWhen the domain was registered
expiry_datedatetimeCurrent expiry date
statusstringOne of: active, renewing, expiring, expired, redemption, suspended, verifying
has_whois_privacyboolean or nullnull if the TLD has no WHOIS privacy
is_lock_enableboolean or nullRegistrar lock. null if the TLD has no lock
is_auto_renewboolean or nullnull if the TLD has no auto-renew
managed_dnsboolean or nullWhether DNS is served by Storefront and manageable through the DNS endpoints
reseller_has_default_dnsboolean or nullWhether you have a default DNS template configured
domain_auth_infostring or nullTransfer auth code. null for TLDs that don't use one
tld_supports_auth_code / tld_supports_locking / tld_supports_contact_privacy / tld_supports_send_auth_codebooleanWhich settings this domain's TLD actually allows — check these before calling an endpoint that would be rejected
domain_privacy_purchasedbooleanWhether the privacy product has been purchased for this domain
free_whois_privacybooleanWhether privacy is included free for this TLD
whois_privacy_is_for_individualbooleanRegistry-specific privacy classification
tld_dataobject or nullTLD-specific registrant data where the TLD has any (e.g. se_registration_number, vat_id for .se/.be)
usernamestringLogin name of the owning customer
customerobjectThe owning customer — id, email, username, first_name, last_name, status, created_date, last_login_date

Note: settings a TLD doesn't support come back as null rather than false — check the tld_supports_* flags before assuming a setting is simply off.

Domains mid-transfer-in aren't visible here until the transfer completes. Requesting a domain that doesn't belong to your account returns a 403; a domain not in your storefront returns 404.


Get domain contacts

GET /v1/domain/{domain}/contacts

Response: 200 OK — registrant is always present. admin, tech, and billing are omitted (not null) when the registry doesn't hold a separate contact for that role, so check for the key rather than assuming null.

Each contact includes: first_name, last_name, org_name, address1address3, city, country (2-letter ISO code), postal_code, state, phone, fax, email. The registrant record may carry extra TLD-required fields (for example se_registration_number for .se) — only fields that apply to this domain's TLD are returned.


Update domain contacts

PUT /v1/domain/{domain}/contacts

registrant is required and replaces the current registrant in full. admin, tech, and billing are each left untouched if you omit them.

Registries validate registrant changes, and some TLDs require extra registrant fields (e.g. ca_legal_type for .ca). A rejection comes back as 400 with the registry's reason in extra. Some TLDs also treat a registrant change as a trade requiring approval, so the change may not be visible immediately.


Get the DNS template assigned to a domain

GET /v1/domain/{domain}/dns_template_id

Returns which of your DNS zone templates this domain is set to use, if any. This is the template that POST /v1/domain/{domain}/dns_records/reset restores.


Update the DNS template assigned to a domain

PUT /v1/domain/{domain}/dns_template_id

Points the domain at one of your DNS zone templates, or send null to remove the association. This only records which template the domain should follow — it doesn't rewrite the zone. Call the reset endpoint to actually apply the template's records. The template must be one of yours.

See DNS Templates for how templates are created.


Get current nameservers for a domain

GET /v1/domain/{domain}/nameservers

Returns the nameservers currently delegated at the registry, in registry order — read live from the registry, not from Storefront's own copy.


Update nameservers for a domain

POST /v1/domain/{domain}/nameservers

Replaces the domain's delegation with the nameservers you send — at least two, no duplicates. This is a full replacement, not a merge.

Moving a domain off Storefront's managed DNS stops Storefront serving its zone; the records themselves are kept, so pointing the nameservers back restores them. If the domain is registrar-locked and its TLD allows locking, Storefront unlocks it for the update and re-locks it afterward automatically.


Reassign a domain to another customer ("push transfer")

Reassigns a domain from its current customer to another customer within your own storefront. This is not a transfer to another reseller — both the current and target customer must already belong to you.

POST /v1/domain/{domain}/push_transfer

Request body: the target customer's ID (UUID).

Asynchronous — the call queues the move and responds 200 immediately. Poll the GET endpoint below for the outcome. A domain with an in-flight transfer isn't eligible for another one. Errors: 400 if the domain is mid-transfer or the target customer already owns it; 404 if the domain or customer doesn't exist.


Check a domain reassignment

GET /v1/domain/{domain}/push_transfer

Response: the outcome of the most recent push transfer for this domain — status is one of pending (queued or running), completed, or failed.

Requesting status for a domain with no active or past transfer returns 404, not an empty result.


Update domain settings

Turns auto-renew, registrar lock, and WHOIS privacy on or off for one domain.

PATCH /v1/domain/{domain}/settings

Request fields (all optional — send only what you want to change):

FieldTypeDescription
has_whois_privacybooleanHide the registrant's details in WHOIS. Only for TLDs with tld_supports_contact_privacy
is_lock_enablebooleanRegistrar lock, blocks transfers away. Only for TLDs with tld_supports_locking
is_auto_renewbooleanRenew automatically before the domain expires

Not every TLD supports every setting — check the tld_supports_* flags on the domain object first. Responds 200 with no body. A rejected change returns 400 with the reason in extra.


Update settings for many domains at once

PATCH /v1/domains/settings

Updates auto-renew, registrar lock, and WHOIS privacy for up to 100 domains in a single request. Each domain is processed independently, so a failure on one doesn't affect the others.

Request: a domains array (1–100 items), each with a domain name and any of is_auto_renew, is_lock_enable, has_whois_privacy.

Response: 200 OK always (even with partial failures) — num_succeeded, num_failed, and a results array with one entry per input domain, in request order, each showing success and, on failure, an error with the reason.


Import a batch of domains

POST /v1/domains/import

Request: an array of domain names (1 or more) that you already hold at OpenSRS. Pulls them into this storefront so they show up in the domain list and can be managed through this API.

Asynchronous — returns a batch ID immediately. Duplicates in the list are collapsed; importing a domain already in the storefront is a no-op for that domain, not an error. If your reseller account hasn't completed the required onboarding steps, the request is rejected with 400.

See Importing Domains for the equivalent UI-based flow.


List your domain portfolio

GET /v1/domains

Every domain in your storefront, filterable and sortable on any column.

Filter syntax: ?<column>=<operator>.<value>. Operators: eq, neq, gt, gte, lt, lte, like, ilike (* wildcard), in, is — prefix any operator with not. to negate it. Repeat a parameter to AND several conditions on the same column.

GET /v1/domains?status=eq.active GET /v1/domains?status=in.(active,expiring) GET /v1/domains?expiry_date=lt.2026-01-01&order=expiry_date.asc

Filterable/sortable columns: name, registration_date, expiry_date, status, username, customer_id, tld, true_tld, created_date, lock_enabled, whois_privacy, autorenew, nameservers, tld_supports_locking, tld_supports_auth_code, tld_supports_send_auth_code.

Note: these column names don't all match the single-domain object's field names above — lock_enabled here is is_lock_enable on the domain object, whois_privacy here is has_whois_privacy, and autorenew here is is_auto_renew. Use the list column names when filtering /v1/domains, and the object field names everywhere else.

Sorting: order=<column>.<asc|desc>, comma-separated for multiple columns, with optional .nullsfirst/.nullslast.

Pagination: limit defaults to 25; anything above 100 is clamped to 100 rather than rejected. offset skips rows. Read the Content-Range response header (e.g. 0-24/1337) for the total count and to decide whether to fetch the next page. This is not cursor-based — there's no page token.

Common use cases from filters on this same endpoint:

  • Domains expiring soon: expiry_date=lt.<date>
  • Domains for a specific customer: customer_id=eq.<id>
  • Domains in a given status: status=eq.<status> or status=in.(<status1>,<status2>)

Error responses

Two error shapes appear across these endpoints:

Auth and not-found errors use detail:

{ "detail": "<message>" }

Business validation errors use error_string and extra:

{ "error_string": "domain settings update failed", "extra": "TLD does not support locking" }
StatusMeaning
400 Bad RequestConstraint violation — registry validation failure, duplicate nameservers, settings not supported by the TLD, onboarding incomplete
401 UnauthorizedMissing or invalid token
403 ForbiddenDomain belongs to another reseller
404 Not FoundDomain, contact, template, customer, or transfer not found
422 Unprocessable EntityRequest failed schema validation
429 Too Many RequestsRate limit exceeded — check Retry-After header

Related articles

Questions or issues with the API? Contact OpenSRS Support.

How helpful was this article?

Thanks for your feedback!

Do you still need help? If so please submit a request here.