Skip to content
Start here

Registrar Sandbox

Use the Registrar Sandbox API to test domain search, availability checks, registration, and domain management flows without buying real domains.

This API is a test environment for the production Registrar API.

Prerequisites

Before using this API, make sure you have:

  1. Cloudflare account — the caller must have a valid Cloudflare account.
  2. API authentication — create an API token with Registrar Sandbox permissions.

How the Sandbox API differs from the production Registrar API

Because the Sandbox API is intended for testing, it behaves differently from the production Registrar API in a few important ways:

  1. No billing — you will not be charged real money for purchasing a domain.
  2. No real domains — purchased domains are test records and will not be reachable on the Internet.
  3. No DNS zones — purchasing a domain does not create a zone resource.
  4. No Registration Express Mode — you must provide full contact data.

Sandbox purchases are still persisted. If you purchase a domain in the sandbox, that domain will not be available for others to purchase in the sandbox.

Terminology: domain extension

Throughout this API, “extension” refers to the domain extension part of a fully qualified domain name — the portion after the registrable label. For example, in example.co.uk, the extension is co.uk (not just uk). This covers both top-level domains like com and multi-level extensions like co.uk. This is distinct from other uses of the word “extension” (e.g., EPP extensions).

Supported extensions

The Sandbox API currently supports programmatic registration for these extensions:

com, net

The production Registrar API supports 40+ extensions.

Cloudflare Registrar supports 400+ extensions in the dashboard. Extensions not listed above can be registered at https://dash.cloudflare.com/{account_id}/domains/registrations.

Typical workflow

  1. Search — call GET /domain-search?q={keyword} to discover available domains.
  2. Check — call POST /domain-check with candidate domains to verify real-time availability and pricing.
  3. Review the response — if registrable: false, inspect reason to understand whether the domain is unavailable, the extension is not supported by this API, the extension is not supported by Cloudflare Registrar at all, or the extension’s registry has frozen new registrations.
  4. Handle premium domains — if tier: premium, premium registration is not currently supported by this API. The Sandbox API currently supports only com and net, which do not have premium registrations, but clients should still handle this response for consistency with the production Registrar API. Surface the premium pricing to the user, but do not proceed to POST /registrations for that domain.
  5. Register — call POST /registrations with the chosen domain name for supported non-premium registrations.
  6. Confirm completion — if the response is 201 Created, registration completed within the default timeout and no polling is needed.
  7. Poll when needed — if the response is 202 Accepted, poll links.self from the workflow response.
  8. Stop for user action — if state: action_required, stop polling and surface context.action to the user. The workflow will not resolve on its own.
  9. Continue when blocked — if state: blocked, continue polling and inform the user that a third party, such as the extension registry or losing registrar, is delaying progress.
  10. Review failures before retrying — if state: failed, review error.code and error.message, then decide whether user action or a new Check call is needed.

Default behavior for mutating operations

By default, mutating operations such as create and update hold the connection for a bounded, server-defined amount of time while the operation completes. In most cases, the response contains a completed workflow status and no polling is required.

  • Completed within the synchronous wait window: Returns 201 (create) or 200 (update) with a workflow_status where state: succeeded and completed: true.
  • Still processing after the synchronous wait window: Returns 202 Accepted with a workflow_status where completed: false. Use the links.self URL to poll for completion.

Non-blocking mode

To receive an immediate 202 Accepted response without waiting, send the Prefer: respond-async request header (RFC 7240). The server will acknowledge it with a Preference-Applied: respond-async response header.

Polling

When the response is 202, poll the workflow status endpoint indicated by links.self in the response body until the workflow reaches a terminal state or requires user action.

Search for available domains
GET/accounts/{account_id}/registrar-sandbox/domain-search
Check domain availability
POST/accounts/{account_id}/registrar-sandbox/domain-check
ModelsExpand Collapse
Registration object { auto_renew, created_at, domain_name, 4 more }

A domain registration resource representing the current state of a registered domain.

auto_renew: boolean

Whether the domain will be automatically renewed before expiration.

created_at: string

When the domain was registered. Present when the registration resource exists.

formatdate-time
domain_name: string

Fully qualified domain name (FQDN) including the extension (e.g., example.com, mybrand.app). The domain name uniquely identifies a registration — the same domain cannot be registered twice, making it a natural idempotency key for registration requests.

expires_at: string

When the domain registration expires. Present when the registration is ready; may be null only while status is registration_pending.

formatdate-time
locked: boolean

Whether the domain is locked for transfer.

privacy_mode: "redaction"

Current WHOIS privacy mode for the registration.

status: "active" or "registration_pending" or "expired" or 3 more

Current registration status.

  • active: Domain is registered and operational
  • registration_pending: Registration is in progress
  • expired: Domain has expired
  • suspended: Domain is suspended by the registry
  • redemption_period: Domain is in the redemption grace period
  • pending_delete: Domain is pending deletion by the registry
One of the following:
"active"
"registration_pending"
"expired"
"suspended"
"redemption_period"
"pending_delete"
WorkflowStatus object { completed, created_at, links, 4 more }

Status of an async registration workflow.

completed: boolean

Whether the workflow has reached a terminal state. true when state is succeeded or failed. false for pending, in_progress, action_required, and blocked.

created_at: string
formatdate-time
state: "pending" or "in_progress" or "action_required" or 3 more

Workflow lifecycle state.

  • pending: Workflow has been created but not yet started processing.
  • in_progress: Actively processing. Continue polling links.self. The workflow has an internal deadline and will not remain in this state indefinitely.
  • action_required: Paused — requires action by the user (not the system). See context.action for what is needed. An automated polling loop must break on this state; it will not resolve on its own without user intervention.
  • blocked: The workflow cannot make progress due to a third party such as the domain extension’s registry or a losing registrar. No user action will help. Continue polling — the block may resolve when the third party responds.
  • succeeded: Terminal. The operation completed successfully. completed will be true. For registrations, context.registration contains the resulting registration resource.
  • failed: Terminal. The operation failed. completed will be true. See error.code and error.message for the reason. Do not auto-retry without user review.
One of the following:
"pending"
"in_progress"
"action_required"
"blocked"
"succeeded"
"failed"
updated_at: string
formatdate-time
context: optional map[unknown]

Workflow-specific data for this workflow.

The workflow subject is identified by context.domain_name for domain-centric workflows.

error: optional object { code, message }

Error details when a workflow reaches the failed state. The specific error codes and messages depend on the workflow type (registration, update, etc.) and the underlying registry response. These workflow error codes are separate from immediate HTTP error errors[].code values returned by non-2xx responses. Surface error.message to the user for context.

code: string

Machine-readable error code identifying the failure reason.

message: string

Human-readable explanation of the failure. May include registry-specific details.

RegistrarSandboxSearchResponse object { domains }

Contains the search results.

domains: array of object { name, registrable, pricing, 2 more }

Array of domain suggestions sorted by relevance. May be empty if no domains match the search criteria.

name: string

The fully qualified domain name (FQDN) in punycode format for internationalized domain names (IDNs).

registrable: boolean

Indicates whether this domain appears available based on search data. Search results are non-authoritative and may be stale. - true: The domain appears available. Use POST /domain-check to confirm before registration.

  • false: The domain does not appear available in search results.
pricing: optional object { currency, registration_cost, renewal_cost }

Annual pricing information for a registrable domain. This object is only present when registrable is true. All prices are per year and returned as strings to preserve decimal precision.

registration_cost and renewal_cost are frequently the same value, but may differ — especially for premium domains where registries set different rates for initial registration vs. renewal. For a multi-year registration (e.g., 4 years), the first year is charged at registration_cost and each subsequent year at renewal_cost. Registry pricing may change over time; the values returned here reflect the current registry rate. Premium pricing may be surfaced by Search and Check, but premium registration is not currently supported by this API.

currency: string

ISO-4217 currency code for the prices (e.g., “USD”, “EUR”, “GBP”).

registration_cost: string

The first-year cost to register this domain. For premium domains (tier: premium), this price is set by the registry and may be significantly higher than standard pricing. For multi-year registrations, this cost applies to the first year only; subsequent years are charged at renewal_cost.

renewal_cost: string

Per-year renewal cost for this domain. Applied to each year beyond the first year of a multi-year registration, and to each annual auto-renewal thereafter. May differ from registration_cost, especially for premium domains where initial registration often costs more than renewals.

reason: optional "extension_not_supported_via_api" or "extension_not_supported" or "extension_disallows_registration" or 2 more

Present only when registrable is false on search results. Explains why the domain does not appear registrable through this API. These values are advisory; use POST /domain-check for authoritative status.

  • extension_not_supported_via_api: Cloudflare Registrar supports this extension in the dashboard but it is not yet available for programmatic registration via this API.
  • extension_not_supported: This extension is not supported by Cloudflare Registrar at all.
  • extension_disallows_registration: The extension’s registry has temporarily or permanently frozen new registrations.
  • domain_premium: The domain is premium priced. Premium registration is not currently supported by this API.
  • domain_unavailable: The domain appears unavailable.
One of the following:
"extension_not_supported_via_api"
"extension_not_supported"
"extension_disallows_registration"
"domain_premium"
"domain_unavailable"
tier: optional "standard" or "premium"

The pricing tier for this domain. Always present when registrable is true; defaults to standard for most domains. May be absent when registrable is false.

  • standard: Standard registry pricing
  • premium: Premium domain with higher pricing set by the registry
One of the following:
"standard"
"premium"
RegistrarSandboxCheckResponse object { domains }

Contains the availability check results.

domains: array of object { name, registrable, pricing, 2 more }

Array of domain availability results. Domains on unsupported extensions are included with registrable: false and a reason field. Malformed domain names may be omitted.

name: string

The fully qualified domain name (FQDN) in punycode format for internationalized domain names (IDNs).

registrable: boolean

Indicates whether this domain can be registered programmatically through this API based on a real-time registry check.

  • true: Domain is available for registration. The pricing object will be included.
  • false: Domain is not available. See the reason field for why. tier may still be present on some non-registrable results, such as premium domains.
pricing: optional object { currency, registration_cost, renewal_cost }

Annual pricing information for a registrable domain. This object is only present when registrable is true. All prices are per year and returned as strings to preserve decimal precision.

registration_cost and renewal_cost are frequently the same value, but may differ — especially for premium domains where registries set different rates for initial registration vs. renewal. For a multi-year registration (e.g., 4 years), the first year is charged at registration_cost and each subsequent year at renewal_cost. Registry pricing may change over time; the values returned here reflect the current registry rate. Premium pricing may be surfaced by Search and Check, but premium registration is not currently supported by this API.

currency: string

ISO-4217 currency code for the prices (e.g., “USD”, “EUR”, “GBP”).

registration_cost: string

The first-year cost to register this domain. For premium domains (tier: premium), this price is set by the registry and may be significantly higher than standard pricing. For multi-year registrations, this cost applies to the first year only; subsequent years are charged at renewal_cost.

renewal_cost: string

Per-year renewal cost for this domain. Applied to each year beyond the first year of a multi-year registration, and to each annual auto-renewal thereafter. May differ from registration_cost, especially for premium domains where initial registration often costs more than renewals.

reason: optional "extension_not_supported_via_api" or "extension_not_supported" or "extension_disallows_registration" or 2 more

Present only when registrable is false. Explains why the domain cannot be registered via this API.

  • extension_not_supported_via_api: Cloudflare Registrar supports this extension in the dashboard but it is not yet available for programmatic registration via this API. The user can register via https://dash.cloudflare.com/{account_id}/domains/registrations.
  • extension_not_supported: This extension is not supported by Cloudflare Registrar at all.
  • extension_disallows_registration: The extension’s registry has temporarily or permanently frozen new registrations. No registrar can register domains on this extension at this time.
  • domain_premium: The domain is premium priced. Premium registration is not currently supported by this API.
  • domain_unavailable: The domain is already registered, reserved, or otherwise not available on a supported extension.
One of the following:
"extension_not_supported_via_api"
"extension_not_supported"
"extension_disallows_registration"
"domain_premium"
"domain_unavailable"
tier: optional "standard" or "premium"

The pricing tier for this domain. Always present when registrable is true; defaults to standard for most domains. May be absent when registrable is false.

  • standard: Standard registry pricing
  • premium: Premium domain with higher pricing set by the registry
One of the following:
"standard"
"premium"

Registrar SandboxRegistrations

Create Registration
POST/accounts/{account_id}/registrar-sandbox/registrations
List Registrations
GET/accounts/{account_id}/registrar-sandbox/registrations
Get Registration
GET/accounts/{account_id}/registrar-sandbox/registrations/{domain_name}
Update Registration
PATCH/accounts/{account_id}/registrar-sandbox/registrations/{domain_name}
ModelsExpand Collapse
RegistrationCreateResponse object { completed, created_at, links, 4 more }

Status of an async registration workflow.

completed: boolean

Whether the workflow has reached a terminal state. true when state is succeeded or failed. false for pending, in_progress, action_required, and blocked.

created_at: string
formatdate-time
state: "pending" or "in_progress" or "action_required" or 3 more

Workflow lifecycle state.

  • pending: Workflow has been created but not yet started processing.
  • in_progress: Actively processing. Continue polling links.self. The workflow has an internal deadline and will not remain in this state indefinitely.
  • action_required: Paused — requires action by the user (not the system). See context.action for what is needed. An automated polling loop must break on this state; it will not resolve on its own without user intervention.
  • blocked: The workflow cannot make progress due to a third party such as the domain extension’s registry or a losing registrar. No user action will help. Continue polling — the block may resolve when the third party responds.
  • succeeded: Terminal. The operation completed successfully. completed will be true. For registrations, context.registration contains the resulting registration resource.
  • failed: Terminal. The operation failed. completed will be true. See error.code and error.message for the reason. Do not auto-retry without user review.
One of the following:
"pending"
"in_progress"
"action_required"
"blocked"
"succeeded"
"failed"
updated_at: string
formatdate-time
context: optional map[unknown]

Workflow-specific data for this workflow.

The workflow subject is identified by context.domain_name for domain-centric workflows.

error: optional object { code, message }

Error details when a workflow reaches the failed state. The specific error codes and messages depend on the workflow type (registration, update, etc.) and the underlying registry response. These workflow error codes are separate from immediate HTTP error errors[].code values returned by non-2xx responses. Surface error.message to the user for context.

code: string

Machine-readable error code identifying the failure reason.

message: string

Human-readable explanation of the failure. May include registry-specific details.

RegistrationListResponse object { auto_renew, created_at, domain_name, 4 more }

A domain registration resource representing the current state of a registered domain.

auto_renew: boolean

Whether the domain will be automatically renewed before expiration.

created_at: string

When the domain was registered. Present when the registration resource exists.

formatdate-time
domain_name: string

Fully qualified domain name (FQDN) including the extension (e.g., example.com, mybrand.app). The domain name uniquely identifies a registration — the same domain cannot be registered twice, making it a natural idempotency key for registration requests.

expires_at: string

When the domain registration expires. Present when the registration is ready; may be null only while status is registration_pending.

formatdate-time
locked: boolean

Whether the domain is locked for transfer.

privacy_mode: "redaction"

Current WHOIS privacy mode for the registration.

status: "active" or "registration_pending" or "expired" or 3 more

Current registration status.

  • active: Domain is registered and operational
  • registration_pending: Registration is in progress
  • expired: Domain has expired
  • suspended: Domain is suspended by the registry
  • redemption_period: Domain is in the redemption grace period
  • pending_delete: Domain is pending deletion by the registry
One of the following:
"active"
"registration_pending"
"expired"
"suspended"
"redemption_period"
"pending_delete"
RegistrationGetResponse object { auto_renew, created_at, domain_name, 4 more }

A domain registration resource representing the current state of a registered domain.

auto_renew: boolean

Whether the domain will be automatically renewed before expiration.

created_at: string

When the domain was registered. Present when the registration resource exists.

formatdate-time
domain_name: string

Fully qualified domain name (FQDN) including the extension (e.g., example.com, mybrand.app). The domain name uniquely identifies a registration — the same domain cannot be registered twice, making it a natural idempotency key for registration requests.

expires_at: string

When the domain registration expires. Present when the registration is ready; may be null only while status is registration_pending.

formatdate-time
locked: boolean

Whether the domain is locked for transfer.

privacy_mode: "redaction"

Current WHOIS privacy mode for the registration.

status: "active" or "registration_pending" or "expired" or 3 more

Current registration status.

  • active: Domain is registered and operational
  • registration_pending: Registration is in progress
  • expired: Domain has expired
  • suspended: Domain is suspended by the registry
  • redemption_period: Domain is in the redemption grace period
  • pending_delete: Domain is pending deletion by the registry
One of the following:
"active"
"registration_pending"
"expired"
"suspended"
"redemption_period"
"pending_delete"
RegistrationEditResponse object { completed, created_at, links, 4 more }

Status of an async registration workflow.

completed: boolean

Whether the workflow has reached a terminal state. true when state is succeeded or failed. false for pending, in_progress, action_required, and blocked.

created_at: string
formatdate-time
state: "pending" or "in_progress" or "action_required" or 3 more

Workflow lifecycle state.

  • pending: Workflow has been created but not yet started processing.
  • in_progress: Actively processing. Continue polling links.self. The workflow has an internal deadline and will not remain in this state indefinitely.
  • action_required: Paused — requires action by the user (not the system). See context.action for what is needed. An automated polling loop must break on this state; it will not resolve on its own without user intervention.
  • blocked: The workflow cannot make progress due to a third party such as the domain extension’s registry or a losing registrar. No user action will help. Continue polling — the block may resolve when the third party responds.
  • succeeded: Terminal. The operation completed successfully. completed will be true. For registrations, context.registration contains the resulting registration resource.
  • failed: Terminal. The operation failed. completed will be true. See error.code and error.message for the reason. Do not auto-retry without user review.
One of the following:
"pending"
"in_progress"
"action_required"
"blocked"
"succeeded"
"failed"
updated_at: string
formatdate-time
context: optional map[unknown]

Workflow-specific data for this workflow.

The workflow subject is identified by context.domain_name for domain-centric workflows.

error: optional object { code, message }

Error details when a workflow reaches the failed state. The specific error codes and messages depend on the workflow type (registration, update, etc.) and the underlying registry response. These workflow error codes are separate from immediate HTTP error errors[].code values returned by non-2xx responses. Surface error.message to the user for context.

code: string

Machine-readable error code identifying the failure reason.

message: string

Human-readable explanation of the failure. May include registry-specific details.

Registrar SandboxRegistration Status

Get Registration Status
GET/accounts/{account_id}/registrar-sandbox/registrations/{domain_name}/registration-status
ModelsExpand Collapse
RegistrationStatusGetResponse object { completed, created_at, links, 4 more }

Status of an async registration workflow.

completed: boolean

Whether the workflow has reached a terminal state. true when state is succeeded or failed. false for pending, in_progress, action_required, and blocked.

created_at: string
formatdate-time
state: "pending" or "in_progress" or "action_required" or 3 more

Workflow lifecycle state.

  • pending: Workflow has been created but not yet started processing.
  • in_progress: Actively processing. Continue polling links.self. The workflow has an internal deadline and will not remain in this state indefinitely.
  • action_required: Paused — requires action by the user (not the system). See context.action for what is needed. An automated polling loop must break on this state; it will not resolve on its own without user intervention.
  • blocked: The workflow cannot make progress due to a third party such as the domain extension’s registry or a losing registrar. No user action will help. Continue polling — the block may resolve when the third party responds.
  • succeeded: Terminal. The operation completed successfully. completed will be true. For registrations, context.registration contains the resulting registration resource.
  • failed: Terminal. The operation failed. completed will be true. See error.code and error.message for the reason. Do not auto-retry without user review.
One of the following:
"pending"
"in_progress"
"action_required"
"blocked"
"succeeded"
"failed"
updated_at: string
formatdate-time
context: optional map[unknown]

Workflow-specific data for this workflow.

The workflow subject is identified by context.domain_name for domain-centric workflows.

error: optional object { code, message }

Error details when a workflow reaches the failed state. The specific error codes and messages depend on the workflow type (registration, update, etc.) and the underlying registry response. These workflow error codes are separate from immediate HTTP error errors[].code values returned by non-2xx responses. Surface error.message to the user for context.

code: string

Machine-readable error code identifying the failure reason.

message: string

Human-readable explanation of the failure. May include registry-specific details.

Registrar SandboxUpdate Status

Get Update Status
GET/accounts/{account_id}/registrar-sandbox/registrations/{domain_name}/update-status
ModelsExpand Collapse
UpdateStatusGetResponse object { completed, created_at, links, 4 more }

Status of an async registration workflow.

completed: boolean

Whether the workflow has reached a terminal state. true when state is succeeded or failed. false for pending, in_progress, action_required, and blocked.

created_at: string
formatdate-time
state: "pending" or "in_progress" or "action_required" or 3 more

Workflow lifecycle state.

  • pending: Workflow has been created but not yet started processing.
  • in_progress: Actively processing. Continue polling links.self. The workflow has an internal deadline and will not remain in this state indefinitely.
  • action_required: Paused — requires action by the user (not the system). See context.action for what is needed. An automated polling loop must break on this state; it will not resolve on its own without user intervention.
  • blocked: The workflow cannot make progress due to a third party such as the domain extension’s registry or a losing registrar. No user action will help. Continue polling — the block may resolve when the third party responds.
  • succeeded: Terminal. The operation completed successfully. completed will be true. For registrations, context.registration contains the resulting registration resource.
  • failed: Terminal. The operation failed. completed will be true. See error.code and error.message for the reason. Do not auto-retry without user review.
One of the following:
"pending"
"in_progress"
"action_required"
"blocked"
"succeeded"
"failed"
updated_at: string
formatdate-time
context: optional map[unknown]

Workflow-specific data for this workflow.

The workflow subject is identified by context.domain_name for domain-centric workflows.

error: optional object { code, message }

Error details when a workflow reaches the failed state. The specific error codes and messages depend on the workflow type (registration, update, etc.) and the underlying registry response. These workflow error codes are separate from immediate HTTP error errors[].code values returned by non-2xx responses. Surface error.message to the user for context.

code: string

Machine-readable error code identifying the failure reason.

message: string

Human-readable explanation of the failure. May include registry-specific details.