Custom Domain
The state is current on every read, so a domain the customer fixed days later reports correctly with no other call. Reading changes nothing.
When the state cannot be checked the record still comes back, with a null lastCheckedAt — do not read certificate health from such a record. A null isBoundInAzure likewise means unknown, not a confirmed absence.
diagnostics is populated for global administrators only.
The tenant's custom domain.
One custom domain, as the admin API reports it.
The hostname, lowercased.
Where provisioning has got to.
True when the tenant's publicUri points at this hostname, so end users are sent here.
Whether the hostname is bound on the platform. Null when this could not be determined, which does not mean the ownership record is missing.
When the hostname was claimed. Null when this could not be determined.
When the provisioning status was read to build this record, i.e. the time of the request. Null means the status could not be read and Neo.Runtime.Security.CustomDomains.CustomDomainRecord.State reflects the tenant configuration only — do not read certificate health from such a record.
The caller is not authenticated.
The caller lacks the tenant.configuration.customDomain:read scope.
This tenant has no custom domain.
Over 1200 requests per minute to this endpoint for the tenant (default limit); retry after Retry-After.
Custom domain provisioning is not configured on this environment.
GET /api/{tenantId}/admin/customdomain HTTP/1.1
Host: app.neostore.cloud
Authorization: Bearer YOUR_OAUTH2_TOKEN
Accept: */*
{
"hostname": "text",
"state": "pending_dns",
"dnsRecords": [
{
"type": "text",
"name": "text",
"value": "text",
"purpose": "routing"
}
],
"isLive": true,
"isBoundInAzure": null,
"certificate": {
"status": null,
"expiresOn": null,
"autoRenew": true
},
"claimedAt": null,
"lastCheckedAt": null,
"diagnostics": {
"cloudflareId": null,
"cloudflareStatus": null,
"cloudflareSslStatus": null,
"domainControlValidationMethod": null,
"originSni": null,
"validationErrors": [
"text"
]
}
}Registers the hostname and records it as claimed. Nothing about the tenant's public address changes — that needs a separate call to activate.
Refused with 409 when the tenant already has a different domain: a tenant has one public address, so replace a domain by removing it, then adding the new one.
Root domains are accepted; they need a DNS provider that can flatten them (CNAME flattening, ALIAS or ANAME), which is the customer's to check. Wildcards are rejected.
Call GET preflight first if you need to know why a hostname is unusable — this action reports a rejection as a 400 for a human to read, not as codes to branch on.
Request body to claim a domain.
Hostname to claim, for example registration.brand.com. Lowercased server-side.
Domain claimed. The response says which DNS records the customer must create.
One custom domain, as the admin API reports it.
The hostname, lowercased.
Where provisioning has got to.
True when the tenant's publicUri points at this hostname, so end users are sent here.
Whether the hostname is bound on the platform. Null when this could not be determined, which does not mean the ownership record is missing.
When the hostname was claimed. Null when this could not be determined.
When the provisioning status was read to build this record, i.e. the time of the request. Null means the status could not be read and Neo.Runtime.Security.CustomDomains.CustomDomainRecord.State reflects the tenant configuration only — do not read certificate health from such a record.
The hostname cannot be used.
The caller is not authenticated.
The caller lacks the tenant.configuration.customDomain:write scope.
The hostname is already in use, or this tenant already has a domain.
Over 1200 requests per minute to this endpoint for the tenant (default limit); retry after Retry-After.
A provider did not answer. Nothing was changed; the call is worth retrying.
Custom domain provisioning is not configured on this environment.
POST /api/{tenantId}/admin/customdomain HTTP/1.1
Host: app.neostore.cloud
Authorization: Bearer YOUR_OAUTH2_TOKEN
Content-Type: application/json
Accept: */*
Content-Length: 19
{
"hostname": "text"
}{
"hostname": "text",
"state": "pending_dns",
"dnsRecords": [
{
"type": "text",
"name": "text",
"value": "text",
"purpose": "routing"
}
],
"isLive": true,
"isBoundInAzure": null,
"certificate": {
"status": null,
"expiresOn": null,
"autoRenew": true
},
"claimedAt": null,
"lastCheckedAt": null,
"diagnostics": {
"cloudflareId": null,
"cloudflareStatus": null,
"cloudflareSslStatus": null,
"domainControlValidationMethod": null,
"originSni": null,
"validationErrors": [
"text"
]
}
}Puts the tenant back on the platform's own address, then releases the hostname.
Requires confirm=true, because for a live domain this reverts every customer-facing URL.
Must be true; acknowledges that a live domain's customer-facing URLs revert.
Domain removed.
No content
The confirmation flag was not passed.
The caller is not authenticated.
The caller lacks the tenant.configuration.customDomain:write scope.
This tenant has no custom domain.
Over 1200 requests per minute to this endpoint for the tenant (default limit); retry after Retry-After.
Custom domain provisioning is not configured on this environment.
DELETE /api/{tenantId}/admin/customdomain HTTP/1.1
Host: app.neostore.cloud
Authorization: Bearer YOUR_OAUTH2_TOKEN
Accept: */*
No content
The only call that changes what customers see: sets the tenant's publicUri to the domain.
Refused unless the domain is ready and a check has passed for it recently.
The tenant's public address now points at the domain.
One custom domain, as the admin API reports it.
The hostname, lowercased.
Where provisioning has got to.
True when the tenant's publicUri points at this hostname, so end users are sent here.
Whether the hostname is bound on the platform. Null when this could not be determined, which does not mean the ownership record is missing.
When the hostname was claimed. Null when this could not be determined.
When the provisioning status was read to build this record, i.e. the time of the request. Null means the status could not be read and Neo.Runtime.Security.CustomDomains.CustomDomainRecord.State reflects the tenant configuration only — do not read certificate health from such a record.
The caller is not authenticated.
The caller lacks the tenant.configuration.customDomain:write scope.
No domain, or it is not ready, or it has not passed a recent check.
Over 1200 requests per minute to this endpoint for the tenant (default limit); retry after Retry-After.
Custom domain provisioning is not configured on this environment.
POST /api/{tenantId}/admin/customdomain/activate HTTP/1.1
Host: app.neostore.cloud
Authorization: Bearer YOUR_OAUTH2_TOKEN
Accept: */*
{
"hostname": "text",
"state": "pending_dns",
"dnsRecords": [
{
"type": "text",
"name": "text",
"value": "text",
"purpose": "routing"
}
],
"isLive": true,
"isBoundInAzure": null,
"certificate": {
"status": null,
"expiresOn": null,
"autoRenew": true
},
"claimedAt": null,
"lastCheckedAt": null,
"diagnostics": {
"cloudflareId": null,
"cloudflareStatus": null,
"cloudflareSslStatus": null,
"domainControlValidationMethod": null,
"originSni": null,
"validationErrors": [
"text"
]
}
}Calls the hostname from the outside and confirms the request arrives here identified as that hostname. One call exercises the customer's DNS, the certificate, and the platform accepting the hostname.
Expected to fail while the customer still has records to add — the failure code says which link in the chain is broken, which is the point of running it early.
Requires the write scope: the check can complete the domain's setup before testing it.
Check ran. The body says whether it passed and, if not, why.
Outcome of one configuration check.
True when an HTTPS request to the hostname reached this application and arrived identified as that hostname.
The host this application reported seeing, when the answer could be read at all; null for an unreachable
host, a TLS failure, a timeout or a non-success response. Differs from the hostname on
hostNotRewritten.
Why it did not pass. Null when it did.
When the check ran, in UTC.
The caller is not authenticated.
The caller lacks the tenant.configuration.customDomain:write scope.
This tenant has no custom domain.
Over 1200 requests per minute to this endpoint for the tenant (default limit); retry after Retry-After.
Custom domain provisioning is not configured on this environment.
POST /api/{tenantId}/admin/customdomain/check HTTP/1.1
Host: app.neostore.cloud
Authorization: Bearer YOUR_OAUTH2_TOKEN
Accept: */*
{
"passed": true,
"resolvedHost": null,
"failure": "unreachable",
"checkedAt": "2026-01-01T00:00:00.000Z"
}Answers the two questions the add screen cannot answer on its own: whether the hostname is already in use, and — for a root domain — whether the customer's DNS provider can even point it at us. Creates nothing and writes nothing.
The apex verdict is correct for brand.co.uk and for a delegated subzone.
An invalid hostname is still a 200: the point is to report what is wrong with it, in codes the caller can translate.
Hostname the customer intends to claim, for example registration.brand.com.
Preflight completed. A hostname may be invalid and still return 200.
What a preflight found out about a hostname.
The hostname, lowercased and normalised.
False when one of the rules below rejected it.
True when the hostname is the root of its DNS zone. Correct for multi-part suffixes such as
brand.co.uk and for delegated subzones.
Root of the zone the hostname belongs to, when DNS answered.
Recognised DNS provider, or null when the nameservers are unfamiliar.
Whether that provider can point a zone root at a hostname. Null means unknown — show the generic caution, never "no".
Whether the hostname can be claimed.
hostname is missing.
The caller is not authenticated.
The caller lacks the tenant.configuration.customDomain:read scope.
Over 1200 requests per minute to this endpoint for the tenant (default limit); retry after Retry-After.
Custom domain provisioning is not configured on this environment.
GET /api/{tenantId}/admin/customdomain/preflight?hostname=text HTTP/1.1
Host: app.neostore.cloud
Authorization: Bearer YOUR_OAUTH2_TOKEN
Accept: */*
{
"hostname": "text",
"isValid": true,
"rejections": [
"malformed"
],
"isApex": true,
"zoneApex": null,
"dnsProvider": null,
"supportsApex": null,
"availability": "available"
}Last updated

