MethodPathSummaryAuth
GET/v1/sitesList websites visible in the authenticated scopeSession
POST/v1/sitesCreate a websiteSession
POST/v1/sites/batch-actionEnable, disable, soft-delete, queue CNAME regeneration for, or set the HTTPS protocols of websitesSession
GET/v1/sites/exportExport an immutable snapshot of site domainsSession
GET/v1/sites/{id}Get one website and its basic settingsSession
PATCH/v1/sites/{id}Replace the complete basic or origin settings sectionSession
DELETE/v1/sites/{id}Soft-delete a websiteSession
POST/v1/sites/{id}/access-check接入状态 > 立即检查 (resolve the site's domains now)Session
POST/v1/sites/{id}/auto-dns/sync解析检测 > 同步解析 (run the site's automatic DNS records again)Session
POST/v1/sites/{id}/lockLock a website against tenant writesSession
POST/v1/sites/{id}/origin-failbackSwitch the pool back to the highest healthy level (manual failback)Session
GET/v1/sites/{id}/origin-routingGet the normalized conditional origin-routing documentSession
PUT/v1/sites/{id}/origin-routingReplace the complete conditional origin-routing documentSession
GET/v1/sites/{id}/origin-statusOrigin pool probe state and the active origin levelSession
GET/v1/sites/{id}/schedule302Get the site's HTTP 302 scheduling settingsSession
PUT/v1/sites/{id}/schedule302Replace the site's HTTP 302 scheduling settingsSession
POST/v1/sites/{id}/transferMove a website to another userSession
POST/v1/sites/{id}/unlockRestore tenant write access to a websiteSession
GET/v1/sites/{site_id}/accessGet a site's request handling settingsSession
PUT/v1/sites/{site_id}/accessReplace a site's request handling settingsSession
GET/v1/sites/{site_id}/certificate-bindingGet the active certificate binding for one siteSession
POST/v1/sites/{site_id}/dns-reconcile/applyPersist and enqueue a DNS reconciliation taskSession
POST/v1/sites/{site_id}/dns-reconcile/dry-runBuild a deterministic repair plan without provider side effectsSession
GET/v1/sites/{site_id}/dns-reconcile/tasks/{task_id}Read one durable DNS reconciliation taskSession
POST/v1/sites/{site_id}/dns-reconcile/tasks/{task_id}/cancelPersist a cancellation request for a DNS reconciliation taskSession
POST/v1/sites/{site_id}/dns-reconcile/tasks/{task_id}/commitDelete superseded records after propagation is healthySession
GET/v1/sites/{site_id}/traffic-limitRead a website's traffic caps and their enforcement (sites.read)Session
PUT/v1/sites/{site_id}/traffic-limitReplace a website's traffic caps (sites.manage)Session

Contract file:api/openapi/v1/sites.yaml api/control-site-access.openapi.yaml api/control-certificate-assets.openapi.yaml api/control-dns-reconcile.openapi.yaml api/control-site-traffic-limit.openapi.yaml

Operation details

GET /v1/sites

List websites visible in the authenticated scope

operationId
listSites
Auth
  • Session: the Bearer session of a signed-in control plane user, used by the customer in their own control plane; a plugin must never ask for it.
Required permissions

The contract has no separate permission annotation; see the description below and the 403 response.

Description (from the contract)

Platform administrators can list all tenant scopes. Tenant principals are always restricted by the server to their active tenant scope, and owner and region are redacted in their response. The owner, region_id, and node_group_id filters are platform-only to prevent count-based disclosure of redacted metadata.

Parameters

listSites Parameters
NameInTypeRequiredDescription
pagequeryintegerNo—
limitqueryintegerNo—
domainquerystringNoCase-insensitive domain substring; a positive decimal also matches the site display ID exactly.
domainsquerystringNoComma- or whitespace-separated exact domains, at most 50.
origin_ipquerystringNo—
site_idsquerystringNoComma- or whitespace-separated UUIDs, at most 100.
ownerquerystringNo—
package_idquerystring(uuid)No—
packagequerystringNoCase-insensitive substring of the site's package name (the name form of package_id).
sitequerystringNoCase-insensitive domain substring or exact site display ID (the name form of site_ids).
group_idquerystring(uuid)No—
region_idquerystring(uuid)No—
node_group_idquerystring(uuid)No—
cname_domainquerystringNo—
cname_hostnamequerystringNo—
http_portquerystringNo—
https_portquerystringNo—
https_enabledquerybooleanNo—
enabledquerybooleanNo—
statusquerystring: active / disabled / package_expired / traffic_exceeded / locked / syncing / sync_failedNo—
is_defaultquerybooleanNo—
sync_statusquerystring: synced / pending / failedNo—

Responses

listSites Responses
StatusDescription
200Stable page ordered by creation time and ID descending.

Fields:items: array<SiteListItem> total: integer(int64) page: integer limit: integer

400Invalid JSON, field, or query input.
401Authentication is required.
403The principal lacks sites.read or sites.manage.
500The operation failed without exposing internal details.

What to do on failure

  • 400 Fix the parameters or body per the field list; do not retry unchanged.
  • 401 Check the credential format and whether it expired or was rotated.
  • 403 Check the key scopes, the owner’s current permissions and the tenant scope; never switch to a more privileged account.
  • 500 Outcome unknown: read back by ID or list first, then decide whether to retry with the original Idempotency-Key.

↑ Back to list

POST /v1/sites

Create a website

operationId
createSite
Auth
  • Session: the Bearer session of a signed-in control plane user, used by the customer in their own control plane; a plugin must never ask for it.
Required permissions

The contract has no separate permission annotation; see the description below and the 403 response.

Description (from the contract)

Requires sites.manage and Idempotency-Key. A platform principal must provide target_scope_id and owner_id. A tenant principal is forced to its active scope and own user ID even if those fields are supplied.

Parameters

createSite Parameters
NameInTypeRequiredDescription
Idempotency-KeyheaderstringYesStable per-actor key. Reuse with different normalized input returns 409 idempotency_conflict.

Request body

application/json · Required:Yes

createSite Request body
NameTypeRequiredDescription
target_scope_idstring(uuid)No—
owner_idstring(uuid)No—
basicSiteBasicRequestYes—
origin_poolOriginPoolNoOptional atomic rich origin configuration. When omitted, the server derives a pool from basic.origins. When present, its canonical host and port sequence must exactly match basic.origins. A missing balance_method follows the owner's site default (balance_way), then the platform website default, then round_robin. Missing connect_timeout_ms / read_timeout_ms follow the owner's site defaults, then 3000 / 30000.
dns_provider_idstring(uuid)No建站「DNS API(自动添加记录)」: a verified DNS API account of the owner (needs dns.manage). After the site is created, every domain gets a CNAME to the site CNAME through it (site.auto_dns). A failure there never fails the create; it shows in auto_dns and is retried. 422 dns_provider_unusable: not a verified account of the owner.

Responses

createSite Responses
StatusDescription
201Created, or the stored result of an identical idempotent retry.

Fields:id: string(uuid) scope_id: string(uuid) display_id: string version: integer(int64) owner: OwnerReference | null created_at: string(date-time) updated_at: string(date-time) lock: SiteLockState listener_state: SiteListenerState https_certificate_bound?: boolean basic: SiteBasicResponse origin_pool: OriginPool package_expires_at?: string(date-time) | null(date-time) package_expired_days?: integer | null package_remaining_days?: integer | null access_readiness?: SiteAccessReadiness | null package_unavailable_reason?: string: no_package / package_disabled / package_deleted / null | null: no_package / package_disabled / package_deleted / null

400Invalid JSON, field, or query input.
401Authentication is required.
403The principal lacks sites.read or sites.manage.
409Domain, version, idempotency, website lock-state, or origin-section conflict.
500The operation failed without exposing internal details.

What to do on failure

  • 400 Fix the parameters or body per the field list; do not retry unchanged.
  • 401 Check the credential format and whether it expired or was rotated.
  • 403 Check the key scopes, the owner’s current permissions and the tenant scope; never switch to a more privileged account.
  • 409 Read the current state first; a retry of the same operation keeps the original Idempotency-Key and body.
  • 500 Outcome unknown: read back by ID or list first, then decide whether to retry with the original Idempotency-Key.

↑ Back to list

POST /v1/sites/batch-action

Enable, disable, soft-delete, queue CNAME regeneration for, or set the HTTPS protocols of websites

operationId
batchSiteAction
Auth
  • Session: the Bearer session of a signed-in control plane user, used by the customer in their own control plane; a plugin must never ask for it.
Required permissions

The contract has no separate permission annotation; see the description below and the 403 response.

Description (from the contract)

Requires sites.manage and Idempotency-Key. The response preserves input order while rows are locked in UUID order. Business failures are reported per item and do not undo successful items; a database or audit failure rolls back the complete batch. Tenant principals see resources outside their active scope as site_not_found. Tenant actions against a platform-locked site fail with site_locked, while platform principals retain maintenance access. Enable performs the same local entitlement feature, state, and domains.count checks as a single website update. Disable and delete remain available while entitlement is in grace or expired state. These actions change control-plane desired state only and do not claim that an edge configuration has been activated. regenerate_cname applies only to failed CNAME allocations, requires sites.manage and dns.manage, and transactionally creates one durable CNAME job per accepted site. Its per-item result is queued; the returned site.cname_task_id is the durable task identity and site.cname_state remains pending until provider reconciliation plus authoritative and public recursive convergence completes. set_protocols (网站协议批量设置) writes basic.http2_enabled, basic.http3_enabled and basic.tls_prefer_server_ciphers of each selected site at its expected_version, as a single-site basic update would; keys left out of protocols keep each site's value. Each changed site records site.tls_profile.update, and every scope with an updated site queues its automatic publication (site.update). Its per-item result is updated.

Parameters

batchSiteAction Parameters
NameInTypeRequiredDescription
Idempotency-KeyheaderstringYesStable per-actor key. Reuse with different normalized input returns 409 idempotency_conflict.

Request body

application/json · Required:Yes

batchSiteAction Request body
NameTypeRequiredDescription
actionstring: enable / disable / delete / regenerate_cname / set_protocolsYes—
itemsarray<BatchSiteActionItem>YesSite IDs must be unique even when expected versions differ.
protocolsBatchSiteProtocolsNoRequired with set_protocols and rejected with every other action. An omitted key keeps each site's value; tls_prefer_server_ciphers null follows the cipher preset again.

Responses

batchSiteAction Responses
StatusDescription
200Ordered per-item results, or the stored result of an identical idempotent retry.

Fields:items: array<BatchSiteActionItemResult>

400Invalid JSON, field, or query input.
401Authentication is required.
403The principal lacks sites.read or sites.manage.
409Domain, version, idempotency, website lock-state, or origin-section conflict.
500The operation failed without exposing internal details.

What to do on failure

  • 400 Fix the parameters or body per the field list; do not retry unchanged.
  • 401 Check the credential format and whether it expired or was rotated.
  • 403 Check the key scopes, the owner’s current permissions and the tenant scope; never switch to a more privileged account.
  • 409 Read the current state first; a retry of the same operation keeps the original Idempotency-Key and body.
  • 500 Outcome unknown: read back by ID or list first, then decide whether to retry with the original Idempotency-Key.

↑ Back to list

GET /v1/sites/export

Export an immutable snapshot of site domains

operationId
exportSiteDomains
Auth
  • Session: the Bearer session of a signed-in control plane user, used by the customer in their own control plane; a plugin must never ask for it.
Required permissions

The contract has no separate permission annotation; see the description below and the 403 response.

Description (from the contract)

Requires sites.export. Tenant principals are restricted to their active tenant scope. Platform principals must provide target_scope_id. The response is a UTF-8 CSV produced from an immutable, actor- and filter-bound snapshot; cells that could be interpreted as spreadsheet formulas are escaped.

Parameters

exportSiteDomains Parameters
NameInTypeRequiredDescription
target_scope_idquerystring(uuid)NoRequired for platform principals; tenants may omit their own scope.
domainquerystringNoOptional case-insensitive domain substring filter.
domainsquerystringNoComma- or whitespace-separated exact domains, at most 50.
origin_ipquerystringNo—
site_idsquerystringNoComma- or whitespace-separated UUIDs, at most 100.
ownerquerystringNo—
package_idquerystring(uuid)No—
packagequerystringNoCase-insensitive substring of the site's package name (the name form of package_id).
sitequerystringNoCase-insensitive domain substring or exact site display ID (the name form of site_ids).
group_idquerystring(uuid)No—
region_idquerystring(uuid)No—
node_group_idquerystring(uuid)No—
cname_domainquerystringNo—
cname_hostnamequerystringNo—
http_portquerystringNo—
https_portquerystringNo—
https_enabledquerybooleanNo—
enabledquerybooleanNo—
statusquerystring: active / disabled / package_expired / traffic_exceeded / locked / syncing / sync_failedNo—
is_defaultquerybooleanNo—
sync_statusquerystring: synced / pending / failedNo—

Responses

exportSiteDomains Responses
StatusDescription
200Immutable site-domain snapshot in deterministic order.
400Invalid JSON, field, or query input.
401Authentication is required.
403The principal lacks sites.read or sites.manage.
500The operation failed without exposing internal details.

What to do on failure

  • 400 Fix the parameters or body per the field list; do not retry unchanged.
  • 401 Check the credential format and whether it expired or was rotated.
  • 403 Check the key scopes, the owner’s current permissions and the tenant scope; never switch to a more privileged account.
  • 500 Outcome unknown: read back by ID or list first, then decide whether to retry with the original Idempotency-Key.

↑ Back to list

GET /v1/sites/{id}

Get one website and its basic settings

operationId
getSite
Auth
  • Session: the Bearer session of a signed-in control plane user, used by the customer in their own control plane; a plugin must never ask for it.
Required permissions

The contract has no separate permission annotation; see the description below and the 403 response.

Parameters

getSite Parameters
NameInTypeRequiredDescription
idpathstring(uuid)Yes—

Responses

getSite Responses
StatusDescription
200Website detail. Tenant responses redact owner.

Fields:id: string(uuid) scope_id: string(uuid) display_id: string version: integer(int64) owner: OwnerReference | null created_at: string(date-time) updated_at: string(date-time) lock: SiteLockState listener_state: SiteListenerState https_certificate_bound?: boolean basic: SiteBasicResponse origin_pool: OriginPool package_expires_at?: string(date-time) | null(date-time) package_expired_days?: integer | null package_remaining_days?: integer | null access_readiness?: SiteAccessReadiness | null package_unavailable_reason?: string: no_package / package_disabled / package_deleted / null | null: no_package / package_disabled / package_deleted / null

400Invalid JSON, field, or query input.
401Authentication is required.
403The principal lacks sites.read or sites.manage.
404The site is absent, deleted, or outside the tenant scope.
500The operation failed without exposing internal details.

What to do on failure

  • 400 Fix the parameters or body per the field list; do not retry unchanged.
  • 401 Check the credential format and whether it expired or was rotated.
  • 403 Check the key scopes, the owner’s current permissions and the tenant scope; never switch to a more privileged account.
  • 404 The resource does not exist or belongs to another tenant.
  • 500 Outcome unknown: read back by ID or list first, then decide whether to retry with the original Idempotency-Key.

↑ Back to list

PATCH /v1/sites/{id}

Replace the complete basic or origin settings section

operationId
updateSiteSettings
Auth
  • Session: the Bearer session of a signed-in control plane user, used by the customer in their own control plane; a plugin must never ask for it.
Required permissions

The contract has no separate permission annotation; see the description below and the 403 response.

Description (from the contract)

section=basic and section=origin are writable discriminated variants. expected_version is a shared optimistic concurrency guard, so basic and origin writes against one website serialize on the same version. The complete selected section is required. Origin writes update control-plane desired state and the legacy basic.origins compatibility projection in one transaction; no edge configuration is generated or activated in this slice. A basic write may preserve an identical rich origin projection, but replacing origins while non-default origin metadata exists returns 409 origin_section_conflict. Identical retries require the same normalized payload and Idempotency-Key.

Parameters

updateSiteSettings Parameters
NameInTypeRequiredDescription
idpathstring(uuid)Yes—
Idempotency-KeyheaderstringYesStable per-actor key. Reuse with different normalized input returns 409 idempotency_conflict.

Request body

application/json · Required:Yes

Responses

updateSiteSettings Responses
StatusDescription
200Updated, or the stored result of an identical retry.

Fields:id: string(uuid) scope_id: string(uuid) display_id: string version: integer(int64) owner: OwnerReference | null created_at: string(date-time) updated_at: string(date-time) lock: SiteLockState listener_state: SiteListenerState https_certificate_bound?: boolean basic: SiteBasicResponse origin_pool: OriginPool package_expires_at?: string(date-time) | null(date-time) package_expired_days?: integer | null package_remaining_days?: integer | null access_readiness?: SiteAccessReadiness | null package_unavailable_reason?: string: no_package / package_disabled / package_deleted / null | null: no_package / package_disabled / package_deleted / null

400Invalid JSON, field, or query input.
401Authentication is required.
403The principal lacks sites.read or sites.manage.
404The site is absent, deleted, or outside the tenant scope.
409Domain, version, idempotency, website lock-state, or origin-section conflict.
500The operation failed without exposing internal details.

What to do on failure

  • 400 Fix the parameters or body per the field list; do not retry unchanged.
  • 401 Check the credential format and whether it expired or was rotated.
  • 403 Check the key scopes, the owner’s current permissions and the tenant scope; never switch to a more privileged account.
  • 404 The resource does not exist or belongs to another tenant.
  • 409 Read the current state first; a retry of the same operation keeps the original Idempotency-Key and body.
  • 500 Outcome unknown: read back by ID or list first, then decide whether to retry with the original Idempotency-Key.

↑ Back to list

DELETE /v1/sites/{id}

Soft-delete a website

operationId
deleteSite
Auth
  • Session: the Bearer session of a signed-in control plane user, used by the customer in their own control plane; a plugin must never ask for it.
Required permissions

The contract has no separate permission annotation; see the description below and the 403 response.

Parameters

deleteSite Parameters
NameInTypeRequiredDescription
idpathstring(uuid)Yes—
Idempotency-KeyheaderstringYesStable per-actor key. Reuse with different normalized input returns 409 idempotency_conflict.
If-MatchheaderstringYesQuoted decimal version returned by ETag.

Responses

deleteSite Responses
StatusDescription
204Deleted, or an identical delete retry was replayed.
400Invalid JSON, field, or query input.
401Authentication is required.
403The principal lacks sites.read or sites.manage.
404The site is absent, deleted, or outside the tenant scope.
409Domain, version, idempotency, website lock-state, or origin-section conflict.
500The operation failed without exposing internal details.

What to do on failure

  • 400 Fix the parameters or body per the field list; do not retry unchanged.
  • 401 Check the credential format and whether it expired or was rotated.
  • 403 Check the key scopes, the owner’s current permissions and the tenant scope; never switch to a more privileged account.
  • 404 The resource does not exist or belongs to another tenant.
  • 409 Read the current state first; a retry of the same operation keeps the original Idempotency-Key and body.
  • 500 Outcome unknown: read back by ID or list first, then decide whether to retry with the original Idempotency-Key.

↑ Back to list

POST /v1/sites/{id}/access-check

接入状态 > 立即检查 (resolve the site's domains now)

operationId
checkSiteAccess
Auth
  • Session: the Bearer session of a signed-in control plane user, used by the customer in their own control plane; a plugin must never ask for it.
Required permissions

The contract has no separate permission annotation; see the description below and the 403 response.

Description (from the contract)

Requires sites.read. Resolves every domain of the site through the control plane host's resolver now (no DNS provider or third-party API), stores the result as the background check does and returns the site's access_readiness. Once a minute per site: 429 access_check_throttled with Retry-After (seconds) within the minute.

Parameters

checkSiteAccess Parameters
NameInTypeRequiredDescription
idpathstring(uuid)Yes—

Responses

checkSiteAccess Responses
StatusDescription
200The site's access readiness after the check.

Fields:state: string: ready / pending / blocked checks: array<SiteAccessCheck>

400Invalid JSON, field, or query input.
401Authentication is required.
403The principal lacks sites.read or sites.manage.
404The site is absent, deleted, or outside the tenant scope.
429Rate limited; Retry-After gives the seconds to wait.
500The operation failed without exposing internal details.

What to do on failure

  • 400 Fix the parameters or body per the field list; do not retry unchanged.
  • 401 Check the credential format and whether it expired or was rotated.
  • 403 Check the key scopes, the owner’s current permissions and the tenant scope; never switch to a more privileged account.
  • 404 The resource does not exist or belongs to another tenant.
  • 429 Rate limited: wait, then retry with lower concurrency.
  • 500 Outcome unknown: read back by ID or list first, then decide whether to retry with the original Idempotency-Key.

↑ Back to list

POST /v1/sites/{id}/auto-dns/sync

解析检测 > 同步解析 (run the site's automatic DNS records again)

operationId
syncSiteAutoDNS
Auth
  • Session: the Bearer session of a signed-in control plane user, used by the customer in their own control plane; a plugin must never ask for it.
Required permissions

The contract has no separate permission annotation; see the description below and the 403 response.

Description (from the contract)

Requires sites.manage and dns.manage. Resets the site's auto_dns task to pending (creating it with provider_id when the site has none) and returns at once; the records are written in the background. Repeating the call is harmless. 422 dns_provider_unusable: not a verified account of the site owner.

Parameters

syncSiteAutoDNS Parameters
NameInTypeRequiredDescription
idpathstring(uuid)Yes—

Request body

application/json · Required:Yes

syncSiteAutoDNS Request body
NameTypeRequiredDescription
provider_idstring(uuid)Noanother account of the owner; omitted keeps the task's

Responses

syncSiteAutoDNS Responses
StatusDescription
202Task scheduled.

Fields:provider_id: string(uuid) provider_name: string state: string: pending / done / failed failure_code: string | null attempts: integer results: array<object> updated_at: string(date-time)

400Invalid JSON, field, or query input.
401Authentication is required.
403The principal lacks sites.read or sites.manage.
404The site is absent, deleted, or outside the tenant scope.
422Domain, version, idempotency, website lock-state, or origin-section conflict.
500The operation failed without exposing internal details.

What to do on failure

  • 400 Fix the parameters or body per the field list; do not retry unchanged.
  • 401 Check the credential format and whether it expired or was rotated.
  • 403 Check the key scopes, the owner’s current permissions and the tenant scope; never switch to a more privileged account.
  • 404 The resource does not exist or belongs to another tenant.
  • 500 Outcome unknown: read back by ID or list first, then decide whether to retry with the original Idempotency-Key.

↑ Back to list

POST /v1/sites/{id}/lock

Lock a website against tenant writes

operationId
lockSite
Auth
  • Session: the Bearer session of a signed-in control plane user, used by the customer in their own control plane; a plugin must never ask for it.
Required permissions

The contract has no separate permission annotation; see the description below and the 403 response.

Description (from the contract)

Requires sites.manage in a platform scope. The expected version is checked atomically. Locking changes only control-plane lock metadata and the website version; it does not disable or republish the active edge configuration. Tenant edit, enable/disable, and delete attempts return 409 site_locked until a platform administrator unlocks the site.

Parameters

lockSite Parameters
NameInTypeRequiredDescription
idpathstring(uuid)Yes—
Idempotency-KeyheaderstringYesStable per-actor key. Reuse with different normalized input returns 409 idempotency_conflict.

Request body

application/json · Required:Yes

lockSite Request body
NameTypeRequiredDescription
expected_versioninteger(int64)Yes—
reasonstringYes—

Responses

lockSite Responses
StatusDescription
200Locked, or the stored result of an identical retry.

Fields:id: string(uuid) scope_id: string(uuid) display_id: string version: integer(int64) owner: OwnerReference | null created_at: string(date-time) updated_at: string(date-time) lock: SiteLockState listener_state: SiteListenerState https_certificate_bound?: boolean basic: SiteBasicResponse origin_pool: OriginPool package_expires_at?: string(date-time) | null(date-time) package_expired_days?: integer | null package_remaining_days?: integer | null access_readiness?: SiteAccessReadiness | null package_unavailable_reason?: string: no_package / package_disabled / package_deleted / null | null: no_package / package_disabled / package_deleted / null

400Invalid JSON, field, or query input.
401Authentication is required.
403The principal lacks sites.read or sites.manage.
404The site is absent, deleted, or outside the tenant scope.
409Domain, version, idempotency, website lock-state, or origin-section conflict.
500The operation failed without exposing internal details.

What to do on failure

  • 400 Fix the parameters or body per the field list; do not retry unchanged.
  • 401 Check the credential format and whether it expired or was rotated.
  • 403 Check the key scopes, the owner’s current permissions and the tenant scope; never switch to a more privileged account.
  • 404 The resource does not exist or belongs to another tenant.
  • 409 Read the current state first; a retry of the same operation keeps the original Idempotency-Key and body.
  • 500 Outcome unknown: read back by ID or list first, then decide whether to retry with the original Idempotency-Key.

↑ Back to list

POST /v1/sites/{id}/origin-failback

Switch the pool back to the highest healthy level (manual failback)

operationId
failbackSiteOrigin
Auth
  • Session: the Bearer session of a signed-in control plane user, used by the customer in their own control plane; a plugin must never ask for it.
Required permissions

The contract has no separate permission annotation; see the description below and the 403 response.

Description (from the contract)

Requires sites.manage and Idempotency-Key. Moves the active level to the lowest-numbered level that is healthy (the primary when it is), records site.origin.failback and republishes the site. 409 origin_failback_unavailable: no higher level is healthy.

Parameters

failbackSiteOrigin Parameters
NameInTypeRequiredDescription
idpathstring(uuid)Yes—
Idempotency-KeyheaderstringYesStable per-actor key. Reuse with different normalized input returns 409 idempotency_conflict.

Responses

failbackSiteOrigin Responses
StatusDescription
200State after the switch.

Fields:site_id: string(uuid) failback_mode: string: auto / manual active_level: integer overall: string: healthy / unhealthy / unknown failback_ready: boolean levels: array<object> origins: array<object> switched_at: string(date-time) checked_at: string(date-time)

401Authentication is required.
403The principal lacks sites.read or sites.manage.
404The site is absent, deleted, or outside the tenant scope.
409Domain, version, idempotency, website lock-state, or origin-section conflict.
500The operation failed without exposing internal details.

What to do on failure

  • 401 Check the credential format and whether it expired or was rotated.
  • 403 Check the key scopes, the owner’s current permissions and the tenant scope; never switch to a more privileged account.
  • 404 The resource does not exist or belongs to another tenant.
  • 409 Read the current state first; a retry of the same operation keeps the original Idempotency-Key and body.
  • 500 Outcome unknown: read back by ID or list first, then decide whether to retry with the original Idempotency-Key.

↑ Back to list

GET /v1/sites/{id}/origin-routing

Get the normalized conditional origin-routing document

operationId
getSiteOriginRouting
Auth
  • Session: the Bearer session of a signed-in control plane user, used by the customer in their own control plane; a plugin must never ask for it.
Required permissions

The contract has no separate permission annotation; see the description below and the 403 response.

Description (from the contract)

Requires sites.read. Tenant principals can only read sites in their active scope. The document is ordered deterministically and represents control-plane desired state, not proof of edge activation. The response-only effective_retry and effective_l2_fallback objects expose the fixed fail-safe edge retry and L1-to-L2 direct-origin fallback guards. These guards are not caller-configurable and do not indicate that L2 routing is enabled for this site.

Parameters

getSiteOriginRouting Parameters
NameInTypeRequiredDescription
idpathstring(uuid)Yes—

Responses

getSiteOriginRouting Responses
StatusDescription
200Current normalized document and the shared site version.

Fields:site_id: string(uuid) version: integer(int64) document: ConditionalOriginDocument effective_retry: ConditionalOriginEffectiveRetry effective_l2_fallback: ConditionalOriginEffectiveL2Fallback updated_at: string(date-time)

400Invalid JSON, field, or query input.
401Authentication is required.
403The principal lacks sites.read or sites.manage.
404The site is absent, deleted, or outside the tenant scope.
500The operation failed without exposing internal details.

What to do on failure

  • 400 Fix the parameters or body per the field list; do not retry unchanged.
  • 401 Check the credential format and whether it expired or was rotated.
  • 403 Check the key scopes, the owner’s current permissions and the tenant scope; never switch to a more privileged account.
  • 404 The resource does not exist or belongs to another tenant.
  • 500 Outcome unknown: read back by ID or list first, then decide whether to retry with the original Idempotency-Key.

↑ Back to list

PUT /v1/sites/{id}/origin-routing

Replace the complete conditional origin-routing document

operationId
replaceSiteOriginRouting
Auth
  • Session: the Bearer session of a signed-in control plane user, used by the customer in their own control plane; a plugin must never ask for it.
Required permissions

The contract has no separate permission annotation; see the description below and the 403 response.

Description (from the contract)

Requires sites.manage, Idempotency-Key, and a strong If-Match value for the shared site version. The update, idempotency claim, automatic edge publication request, and site.origin_route.update audit event commit in one transaction. Identical semantic input is normalized before the idempotency digest is calculated. effective_retry and effective_l2_fallback are response-only and are rejected if supplied in this request document.

Parameters

replaceSiteOriginRouting Parameters
NameInTypeRequiredDescription
idpathstring(uuid)Yes—
Idempotency-KeyheaderstringYesStable per-actor key. Reuse with different normalized input returns 409 idempotency_conflict.
If-MatchheaderstringYesQuoted decimal version returned by ETag.

Request body

application/json · Required:Yes

replaceSiteOriginRouting Request body
NameTypeRequiredDescription
schemastringYes—
ingress_source_enabledbooleanYes—
poolsarray<ConditionalOriginPool>Yes—
default_pool_idstringYes—
default_fallback_pool_idstringNo—
routesarray<ConditionalOriginRoute>Yes—
retryConditionalOriginRetryYes—

Responses

replaceSiteOriginRouting Responses
StatusDescription
200Updated state, or the stored result of an identical retry.

Fields:site_id: string(uuid) version: integer(int64) document: ConditionalOriginDocument effective_retry: ConditionalOriginEffectiveRetry effective_l2_fallback: ConditionalOriginEffectiveL2Fallback updated_at: string(date-time)

400Invalid JSON, field, or query input.
401Authentication is required.
403The principal lacks sites.read or sites.manage.
404The site is absent, deleted, or outside the tenant scope.
409Domain, version, idempotency, website lock-state, or origin-section conflict.
500The operation failed without exposing internal details.

What to do on failure

  • 400 Fix the parameters or body per the field list; do not retry unchanged.
  • 401 Check the credential format and whether it expired or was rotated.
  • 403 Check the key scopes, the owner’s current permissions and the tenant scope; never switch to a more privileged account.
  • 404 The resource does not exist or belongs to another tenant.
  • 409 Read the current state first; a retry of the same operation keeps the original Idempotency-Key and body.
  • 500 Outcome unknown: read back by ID or list first, then decide whether to retry with the original Idempotency-Key.

↑ Back to list

GET /v1/sites/{id}/origin-status

Origin pool probe state and the active origin level

operationId
getSiteOriginStatus
Auth
  • Session: the Bearer session of a signed-in control plane user, used by the customer in their own control plane; a plugin must never ask for it.
Required permissions

The contract has no separate permission annotation; see the description below and the 403 response.

Description (from the contract)

Requires sites.read. The control plane probes every origin of the pool (origin address with the pool's origin Host / SNI and health check path, from the tenant's own nodes when they can, else from the control plane). An origin is unhealthy after 3 consecutive failures, healthy after 2 consecutive successes, unknown before that or when it cannot be probed. Aggregated edge scheduling reads overall.

Parameters

getSiteOriginStatus Parameters
NameInTypeRequiredDescription
idpathstring(uuid)Yes—

Responses

getSiteOriginStatus Responses
StatusDescription
200Current state.

Fields:site_id: string(uuid) failback_mode: string: auto / manual active_level: integer overall: string: healthy / unhealthy / unknown failback_ready: boolean levels: array<object> origins: array<object> switched_at: string(date-time) checked_at: string(date-time)

401Authentication is required.
403The principal lacks sites.read or sites.manage.
404The site is absent, deleted, or outside the tenant scope.
500The operation failed without exposing internal details.

What to do on failure

  • 401 Check the credential format and whether it expired or was rotated.
  • 403 Check the key scopes, the owner’s current permissions and the tenant scope; never switch to a more privileged account.
  • 404 The resource does not exist or belongs to another tenant.
  • 500 Outcome unknown: read back by ID or list first, then decide whether to retry with the original Idempotency-Key.

↑ Back to list

GET /v1/sites/{id}/schedule302

Get the site's HTTP 302 scheduling settings

operationId
getSiteSchedule302
Auth
  • Session: the Bearer session of a signed-in control plane user, used by the customer in their own control plane; a plugin must never ask for it.
Required permissions

The contract has no separate permission annotation; see the description below and the 403 response.

Description (from the contract)

Requires sites.read. HTTP 302 scheduling (together with DNS scheduling) lets the node a visitor reaches redirect large downloads and video to the best node for the visitor's carrier and region. Disabled sites return the default settings with enabled false. plain_http reports whether the site has a plain HTTP port, which scheduling needs.

Parameters

getSiteSchedule302 Parameters
NameInTypeRequiredDescription
idpathstring(uuid)Yes—

Responses

getSiteSchedule302 Responses
StatusDescription
200Current settings and the shared site version.

Fields:site_id: string(uuid) version: integer settings: SiteSchedule302Settings plain_http: boolean updated_at: string(date-time) | null(date-time)

400Invalid JSON, field, or query input.
401Authentication is required.
403The principal lacks sites.read or sites.manage.
404The site is absent, deleted, or outside the tenant scope.
500The operation failed without exposing internal details.

What to do on failure

  • 400 Fix the parameters or body per the field list; do not retry unchanged.
  • 401 Check the credential format and whether it expired or was rotated.
  • 403 Check the key scopes, the owner’s current permissions and the tenant scope; never switch to a more privileged account.
  • 404 The resource does not exist or belongs to another tenant.
  • 500 Outcome unknown: read back by ID or list first, then decide whether to retry with the original Idempotency-Key.

↑ Back to list

PUT /v1/sites/{id}/schedule302

Replace the site's HTTP 302 scheduling settings

operationId
replaceSiteSchedule302
Auth
  • Session: the Bearer session of a signed-in control plane user, used by the customer in their own control plane; a plugin must never ask for it.
Required permissions

The contract has no separate permission annotation; see the description below and the 403 response.

Description (from the contract)

Requires sites.manage, Idempotency-Key, and a strong If-Match value for the shared site version. The update, idempotency claim, automatic edge publication request and the site.schedule302.update audit event commit in one transaction; a refused write records the event with result denied and a reason code. Turning scheduling off deletes the settings and the site's signing key. 422 schedule302_no_plain_http: the site has no plain HTTP port.

Parameters

replaceSiteSchedule302 Parameters
NameInTypeRequiredDescription
idpathstring(uuid)Yes—
Idempotency-KeyheaderstringYesStable per-actor key. Reuse with different normalized input returns 409 idempotency_conflict.
If-MatchheaderstringYesQuoted decimal version returned by ETag.

Request body

application/json · Required:Yes

replaceSiteSchedule302 Request body
NameTypeRequiredDescription
enabledbooleanYes—
targetstring: address / hostnameYesRedirect to the node's line-group endpoint address, or to its direct hostname (nodes without one are skipped).
keep_pathbooleanYes—
keep_querybooleanYes—
signature_ttl_secondsintegerYes—
https_to_httpbooleanYesAlso redirect HTTPS requests; they land on plain HTTP (nodes hold no certificate for their address).
extensionsarray<string>Yes—
path_prefixesarray<string>Yes—
min_size_bytesintegerYesRedirect only URLs whose response the node already served at least this large (0 off).

Responses

replaceSiteSchedule302 Responses
StatusDescription
200Updated state, or the stored result of an identical retry.

Fields:site_id: string(uuid) version: integer settings: SiteSchedule302Settings plain_http: boolean updated_at: string(date-time) | null(date-time)

400Invalid JSON, field, or query input.
401Authentication is required.
403The principal lacks sites.read or sites.manage.
404The site is absent, deleted, or outside the tenant scope.
409Domain, version, idempotency, website lock-state, or origin-section conflict.
422Invalid JSON, field, or query input.
500The operation failed without exposing internal details.

What to do on failure

  • 400 Fix the parameters or body per the field list; do not retry unchanged.
  • 401 Check the credential format and whether it expired or was rotated.
  • 403 Check the key scopes, the owner’s current permissions and the tenant scope; never switch to a more privileged account.
  • 404 The resource does not exist or belongs to another tenant.
  • 409 Read the current state first; a retry of the same operation keeps the original Idempotency-Key and body.
  • 500 Outcome unknown: read back by ID or list first, then decide whether to retry with the original Idempotency-Key.

↑ Back to list

POST /v1/sites/{id}/transfer

Move a website to another user

operationId
transferSite
Auth
  • Session: the Bearer session of a signed-in control plane user, used by the customer in their own control plane; a plugin must never ask for it.
Required permissions

The contract has no separate permission annotation; see the description below and the 403 response.

Description (from the contract)

Requires sites.manage in a platform scope held by a platform administrator. In one transaction the website is re-created in the target user's tenant (new website ID, newly allocated CNAME) and the current website is deleted; the old CNAME retires by the delete rules and the customer must repoint DNS from from_cname to the new site's CNAME. Historical statistics, logs and bills stay with the previous owner. The target is another active user with a tenant of its own; target_package_subscription_id is one of that user's own package subscriptions, or null for no package. copied lists what was carried to the new website and released what the administrator must configure again; item names are http_policy, cache_policy, certificate, waf_policy, cc_policy, acl_policy, auto_defense and js_challenge (automatic DNS records are not moved). Without a carried certificate HTTPS is off on the new website. Errors: 422 site_transfer_target_invalid (target is not an active user with its own tenant, or is the current owner), 422 domain_blocked, 409 domain_verified_by_other (an apex is verified by another account, including the previous owner; domain ownership is not transferred), 409 domain_ownership_required, 409 site_locked, 409 version_conflict (stale expected_version) and 409 idempotency_conflict. Domain errors carry the refused domain and apex.

Parameters

transferSite Parameters
NameInTypeRequiredDescription
idpathstring(uuid)Yes—
Idempotency-KeyheaderstringYesStable per-actor key. Reuse with different normalized input returns 409 idempotency_conflict.

Request body

application/json · Required:Yes

transferSite Request body
NameTypeRequiredDescription
expected_versioninteger(int64)Yes—
target_user_idstring(uuid)Yes—
target_package_subscription_idstring(uuid) | null(uuid)No—

Responses

transferSite Responses
StatusDescription
201Moved, or the stored result of an identical idempotent retry. The ETag is the new website's version.

Fields:site: SiteDetail from_site_id: string(uuid) from_cname: string copied: array<string: http_policy / cache_policy / certificate / waf_policy / cc_policy / acl_policy / auto_defense / js_challenge> released: array<string: http_policy / cache_policy / certificate / waf_policy / cc_policy / acl_policy / auto_defense / js_challenge>

400Invalid JSON, field, or query input.
401Authentication is required.
403The principal lacks sites.read or sites.manage.
404The site is absent, deleted, or outside the tenant scope.
409domain_verified_by_other, domain_ownership_required, site_locked, version_conflict or idempotency_conflict.
422site_transfer_target_invalid or domain_blocked.
500The operation failed without exposing internal details.

What to do on failure

  • 400 Fix the parameters or body per the field list; do not retry unchanged.
  • 401 Check the credential format and whether it expired or was rotated.
  • 403 Check the key scopes, the owner’s current permissions and the tenant scope; never switch to a more privileged account.
  • 404 The resource does not exist or belongs to another tenant.
  • 409 Read the current state first; a retry of the same operation keeps the original Idempotency-Key and body.
  • 500 Outcome unknown: read back by ID or list first, then decide whether to retry with the original Idempotency-Key.

↑ Back to list

POST /v1/sites/{id}/unlock

Restore tenant write access to a website

operationId
unlockSite
Auth
  • Session: the Bearer session of a signed-in control plane user, used by the customer in their own control plane; a plugin must never ask for it.
Required permissions

The contract has no separate permission annotation; see the description below and the 403 response.

Description (from the contract)

Requires sites.manage in a platform scope. The expected version is checked atomically and the previous lock metadata is cleared. Existing edge traffic and operational website status are not changed.

Parameters

unlockSite Parameters
NameInTypeRequiredDescription
idpathstring(uuid)Yes—
Idempotency-KeyheaderstringYesStable per-actor key. Reuse with different normalized input returns 409 idempotency_conflict.

Request body

application/json · Required:Yes

unlockSite Request body
NameTypeRequiredDescription
expected_versioninteger(int64)Yes—

Responses

unlockSite Responses
StatusDescription
200Unlocked, or the stored result of an identical retry.

Fields:id: string(uuid) scope_id: string(uuid) display_id: string version: integer(int64) owner: OwnerReference | null created_at: string(date-time) updated_at: string(date-time) lock: SiteLockState listener_state: SiteListenerState https_certificate_bound?: boolean basic: SiteBasicResponse origin_pool: OriginPool package_expires_at?: string(date-time) | null(date-time) package_expired_days?: integer | null package_remaining_days?: integer | null access_readiness?: SiteAccessReadiness | null package_unavailable_reason?: string: no_package / package_disabled / package_deleted / null | null: no_package / package_disabled / package_deleted / null

400Invalid JSON, field, or query input.
401Authentication is required.
403The principal lacks sites.read or sites.manage.
404The site is absent, deleted, or outside the tenant scope.
409Domain, version, idempotency, website lock-state, or origin-section conflict.
500The operation failed without exposing internal details.

What to do on failure

  • 400 Fix the parameters or body per the field list; do not retry unchanged.
  • 401 Check the credential format and whether it expired or was rotated.
  • 403 Check the key scopes, the owner’s current permissions and the tenant scope; never switch to a more privileged account.
  • 404 The resource does not exist or belongs to another tenant.
  • 409 Read the current state first; a retry of the same operation keeps the original Idempotency-Key and body.
  • 500 Outcome unknown: read back by ID or list first, then decide whether to retry with the original Idempotency-Key.

↑ Back to list

GET /v1/sites/{site_id}/access

Get a site's request handling settings

operationId
getSiteAccess
Auth
  • Session: the Bearer session of a signed-in control plane user, used by the customer in their own control plane; a plugin must never ask for it.
Required permissions

All of:sites.read

Description (from the contract)

Basic auth users are returned by name only; passwords are never stored or returned. Tenant principals only reach sites of their scope. ETag is the site version.

Parameters

getSiteAccess Parameters
NameInTypeRequiredDescription
site_idpathstring(uuid)Yes—

Responses

getSiteAccess Responses
StatusDescription
200The site's settings

Fields:site_id: string(uuid) version: integer settings: SiteAccessSettings https_enabled: boolean force_https: boolean domains: array<string> updated_at: string(date-time) | null(date-time)

400Error
401Error
403Error
404Error

What to do on failure

  • 400 Fix the parameters or body per the field list; do not retry unchanged.
  • 401 Check the credential format and whether it expired or was rotated.
  • 403 Check the key scopes, the owner’s current permissions and the tenant scope; never switch to a more privileged account.
  • 404 The resource does not exist or belongs to another tenant.

↑ Back to list

PUT /v1/sites/{site_id}/access

Replace a site's request handling settings

operationId
replaceSiteAccess
Auth
  • Session: the Bearer session of a signed-in control plane user, used by the customer in their own control plane; a plugin must never ask for it.
Required permissions

All of:sites.manage

Description (from the contract)

Replaces every setting; an absent or null setting is off, and all off removes the site's row. A basic auth user without password keeps its stored secret (SHA-256 of site_id:username:password). HSTS and a forced HTTPS status other than 301 or excluded domains need the site's HTTPS. The write advances the site version: a manual scope shows it pending, an automatic scope publishes it. The write and its site.access.update audit event (changes, no secrets) commit together; a refused write is audited as denied with its reason code.

Parameters

replaceSiteAccess Parameters
NameInTypeRequiredDescription
site_idpathstring(uuid)Yes—
Idempotency-KeyheaderstringYes—
If-MatchheaderstringYesThe quoted site version (GET ETag)

Request body

application/json · Required:Yes

replaceSiteAccess Request body
NameTypeRequiredDescription
host_redirectsarray<HostRedirect>No—
hstsHSTS | nullNo—
compressionCompression | nullNo—
limitsLimits | nullNo—
basic_authBasicAuth | nullNo—
maintenanceMaintenance | nullNo—
webpWebP | nullNo—
response_rulesarray<ResponseRule>NoResponse phase rules, evaluated in order when the origin's response headers arrive (the body is never read). Absent or [] = none; a read always returns the list. Needs nodes declaring EDGE_RESPONSE_RULES (a release to others is refused and names them).
force_httpsForceHTTPSNo—

Responses

replaceSiteAccess Responses
StatusDescription
200The site's settings after the write

Fields:site_id: string(uuid) version: integer settings: SiteAccessSettings https_enabled: boolean force_https: boolean domains: array<string> updated_at: string(date-time) | null(date-time)

400Error
401Error
403Error
404Error
409site_locked, version_conflict or idempotency_conflict
422validation_error or site_access_https_required

What to do on failure

  • 400 Fix the parameters or body per the field list; do not retry unchanged.
  • 401 Check the credential format and whether it expired or was rotated.
  • 403 Check the key scopes, the owner’s current permissions and the tenant scope; never switch to a more privileged account.
  • 404 The resource does not exist or belongs to another tenant.
  • 409 Read the current state first; a retry of the same operation keeps the original Idempotency-Key and body.

↑ Back to list

GET /v1/sites/{site_id}/certificate-binding

Get the active certificate binding for one site

operationId
getCertificateSiteBinding
Auth
  • Session: the Bearer session of a signed-in control plane user, used by the customer in their own control plane; a plugin must never ask for it.
Required permissions

All of:certificates.read

Description (from the contract)

Returns the current bound fact and its active immutable certificate version in one tenant-scoped read. An unbound site returns the stable certificate_site_binding_not_found error code.

Parameters

getCertificateSiteBinding Parameters
NameInTypeRequiredDescription
site_idpathstring(uuid)Yes—
target_scope_idquerystring(uuid)NoRequired for platform detail and write operations; optional for the collection GET to list active tenants. Forbidden when it differs from a tenant actor scope.
X-Request-IDheaderstringNo—

Responses

getCertificateSiteBinding Responses
StatusDescription
200Active site certificate binding and version

Fields:binding: CertificateAssetBinding version: CertificateAssetVersion

400Invalid request, metadata or certificate material
401Bearer session missing or invalid
403Tenant scope or live permission denied
404Certificate asset or version not found
405Method not allowed
500Sanitized internal failure

What to do on failure

  • 400 Fix the parameters or body per the field list; do not retry unchanged.
  • 401 Check the credential format and whether it expired or was rotated.
  • 403 Check the key scopes, the owner’s current permissions and the tenant scope; never switch to a more privileged account.
  • 404 The resource does not exist or belongs to another tenant.
  • 500 Outcome unknown: read back by ID or list first, then decide whether to retry with the original Idempotency-Key.

↑ Back to list

POST /v1/sites/{site_id}/dns-reconcile/apply

Persist and enqueue a DNS reconciliation task

operationId
applyDNSReconciliation
Auth
  • Session: the Bearer session of a signed-in control plane user, used by the customer in their own control plane; a plugin must never ask for it.
Required permissions

All of:dns.manage

Description (from the contract)

Requires dns.manage and a live DNS reconciliation entitlement. The authenticated tenant, site path, idempotency key, canonical payload digest, and provider revision form the durable command identity. A same-key retry with a different payload returns 409.

Parameters

applyDNSReconciliation Parameters
NameInTypeRequiredDescription
site_idpathstring(uuid)YesCanonical lower-case UUID of a site in the authenticated tenant.
X-Request-IDheaderstringYes—
traceparentheaderstringYes—
Idempotency-KeyheaderstringYesStable command key; retry only with the same route and payload.
If-MatchheaderstringYesStrong quoted decimal provider/task revision, for example `"7"`.

Request body

application/json · Required:Yes

applyDNSReconciliation Request body
NameTypeRequiredDescription
namestringYes—
expectedarray<ExpectedRecord>Yes—
authoritative_nsarray<string>Yes—
ttlintegerYes—
linestringNoProvider routing line. Empty/default values preserve the provider default line.
weightintegerNoProvider record weight; zero is the provider default.
propagation_started_atstring(date-time)No—
propagation_window_secondsintegerYes—
providerProviderSnapshotYes—

Responses

applyDNSReconciliation Responses
StatusDescription
202Durable job created or replayed and available for workers.

Fields:id: string(uuid) tenant_id: string(uuid) site_id: string(uuid) revision: integer(int64) required_consecutive: integer job: Job request: CheckRequest result: ReconcileResult created_at: string(date-time) updated_at: string(date-time) replayed: boolean

400Non-canonical path/header, unsupported media type, oversized body, unknown field, or invalid JSON.
401Exactly one valid Bearer session is required.
403Live IAM permission or DNS reconciliation entitlement denied.
405Method is not supported by this route.
409Idempotency payload conflict or task state does not permit the command.
412If-Match or provider revision is stale.
408Mutation result is unknown; retry only with the same key and payload.
503Mutation result is unknown; retry only with the same key and payload.
504Mutation result is unknown; retry only with the same key and payload.

What to do on failure

  • 400 Fix the parameters or body per the field list; do not retry unchanged.
  • 401 Check the credential format and whether it expired or was rotated.
  • 403 Check the key scopes, the owner’s current permissions and the tenant scope; never switch to a more privileged account.
  • 409 Read the current state first; a retry of the same operation keeps the original Idempotency-Key and body.
  • 412 The revision changed: read the latest ETag, decide again, then send the new If-Match.
  • 503 A dependency is unavailable: retry later with the original Idempotency-Key.

↑ Back to list

POST /v1/sites/{site_id}/dns-reconcile/dry-run

Build a deterministic repair plan without provider side effects

operationId
dryRunDNSReconciliation
Auth
  • Session: the Bearer session of a signed-in control plane user, used by the customer in their own control plane; a plugin must never ask for it.
Required permissions

All of:dns.read

Parameters

dryRunDNSReconciliation Parameters
NameInTypeRequiredDescription
site_idpathstring(uuid)YesCanonical lower-case UUID of a site in the authenticated tenant.
X-Request-IDheaderstringYes—
traceparentheaderstringYes—

Request body

application/json · Required:Yes

dryRunDNSReconciliation Request body
NameTypeRequiredDescription
namestringYes—
expectedarray<ExpectedRecord>Yes—
authoritative_nsarray<string>Yes—
ttlintegerYes—
linestringNoProvider routing line. Empty/default values preserve the provider default line.
weightintegerNoProvider record weight; zero is the provider default.
propagation_started_atstring(date-time)No—
propagation_window_secondsintegerYes—
providerProviderSnapshotYes—

Responses

dryRunDNSReconciliation Responses
StatusDescription
200Deterministic side-effect-free reconciliation plan.

Fields:tenant_id: string(uuid) site_id: string(uuid) zone_id: string(uuid) payload_digest: string plan: RepairPlan status: string: dry_run / applying / propagating / ready_to_commit / committed / failed / cancelled / timed_out / commit_failed replayed: boolean started_at: string(date-time) updated_at: string(date-time) ready_at?: string(date-time) initial_revision: integer(int64) provider_revision: integer(int64) operations: array<OperationResult> deferred_deletes: array<OperationResult> compensation_plan: array<ProviderOperation> propagation: array<PropagationAttempt> last_check?: CheckResult error_class: string: / transient / permanent / revision_conflict / cancelled / timeout error_code: string

400Non-canonical path/header, unsupported media type, oversized body, unknown field, or invalid JSON.
401Exactly one valid Bearer session is required.
403Live IAM permission or DNS reconciliation entitlement denied.
405Method is not supported by this route.
408Read-only request was cancelled.
503Required runtime dependency is unavailable.
504Read-only request timed out.

What to do on failure

  • 400 Fix the parameters or body per the field list; do not retry unchanged.
  • 401 Check the credential format and whether it expired or was rotated.
  • 403 Check the key scopes, the owner’s current permissions and the tenant scope; never switch to a more privileged account.
  • 503 A dependency is unavailable: retry later with the original Idempotency-Key.

↑ Back to list

GET /v1/sites/{site_id}/dns-reconcile/tasks/{task_id}

Read one durable DNS reconciliation task

operationId
getDNSReconciliationTask
Auth
  • Session: the Bearer session of a signed-in control plane user, used by the customer in their own control plane; a plugin must never ask for it.
Required permissions

All of:dns.read

Description (from the contract)

Requires dns.read. Unknown, cross-tenant, and task/site mismatches all return the same 404 response. Tenant scope is never accepted from a path, query parameter, or request body.

Parameters

getDNSReconciliationTask Parameters
NameInTypeRequiredDescription
site_idpathstring(uuid)YesCanonical lower-case UUID of a site in the authenticated tenant.
task_idpathstring(uuid)YesCanonical lower-case UUID of a dns_reconcile job.
X-Request-IDheaderstringNo—
traceparentheaderstringNo—

Responses

getDNSReconciliationTask Responses
StatusDescription
200Current durable task facts.

Fields:id: string(uuid) tenant_id: string(uuid) site_id: string(uuid) revision: integer(int64) required_consecutive: integer job: Job request: CheckRequest result: ReconcileResult created_at: string(date-time) updated_at: string(date-time) replayed: boolean

400Non-canonical path/header, unsupported media type, oversized body, unknown field, or invalid JSON.
401Exactly one valid Bearer session is required.
403Live IAM permission or DNS reconciliation entitlement denied.
404Task is absent or outside the authenticated tenant/site scope.
405Method is not supported by this route.
408Read-only request was cancelled.
503Required runtime dependency is unavailable.
504Read-only request timed out.

What to do on failure

  • 400 Fix the parameters or body per the field list; do not retry unchanged.
  • 401 Check the credential format and whether it expired or was rotated.
  • 403 Check the key scopes, the owner’s current permissions and the tenant scope; never switch to a more privileged account.
  • 404 The resource does not exist or belongs to another tenant.
  • 503 A dependency is unavailable: retry later with the original Idempotency-Key.

↑ Back to list

POST /v1/sites/{site_id}/dns-reconcile/tasks/{task_id}/cancel

Persist a cancellation request for a DNS reconciliation task

operationId
cancelDNSReconciliationTask
Auth
  • Session: the Bearer session of a signed-in control plane user, used by the customer in their own control plane; a plugin must never ask for it.
Required permissions

All of:dns.manage

Parameters

cancelDNSReconciliationTask Parameters
NameInTypeRequiredDescription
site_idpathstring(uuid)YesCanonical lower-case UUID of a site in the authenticated tenant.
task_idpathstring(uuid)YesCanonical lower-case UUID of a dns_reconcile job.
X-Request-IDheaderstringYes—
traceparentheaderstringYes—
Idempotency-KeyheaderstringYesStable command key; retry only with the same route and payload.
If-MatchheaderstringYesStrong quoted decimal provider/task revision, for example `"7"`.

Request body

application/json · Required:Yes

Responses

cancelDNSReconciliationTask Responses
StatusDescription
200Current durable task facts.

Fields:id: string(uuid) tenant_id: string(uuid) site_id: string(uuid) revision: integer(int64) required_consecutive: integer job: Job request: CheckRequest result: ReconcileResult created_at: string(date-time) updated_at: string(date-time) replayed: boolean

400Non-canonical path/header, unsupported media type, oversized body, unknown field, or invalid JSON.
401Exactly one valid Bearer session is required.
403Live IAM permission or DNS reconciliation entitlement denied.
404Task is absent or outside the authenticated tenant/site scope.
405Method is not supported by this route.
409Idempotency payload conflict or a provider operation is still in flight.
412If-Match or provider revision is stale.
408Mutation result is unknown; retry only with the same key and payload.
503Mutation result is unknown; retry only with the same key and payload.
504Mutation result is unknown; retry only with the same key and payload.

What to do on failure

  • 400 Fix the parameters or body per the field list; do not retry unchanged.
  • 401 Check the credential format and whether it expired or was rotated.
  • 403 Check the key scopes, the owner’s current permissions and the tenant scope; never switch to a more privileged account.
  • 404 The resource does not exist or belongs to another tenant.
  • 409 Read the current state first; a retry of the same operation keeps the original Idempotency-Key and body.
  • 412 The revision changed: read the latest ETag, decide again, then send the new If-Match.
  • 503 A dependency is unavailable: retry later with the original Idempotency-Key.

↑ Back to list

POST /v1/sites/{site_id}/dns-reconcile/tasks/{task_id}/commit

Delete superseded records after propagation is healthy

operationId
commitDNSReconciliationTask
Auth
  • Session: the Bearer session of a signed-in control plane user, used by the customer in their own control plane; a plugin must never ask for it.
Required permissions

All of:dns.manage

Description (from the contract)

Requires dns.manage and a live DNS reconciliation entitlement. Commit rechecks convergence and provider revision before processing deferred deletes. Crash/retry reuses the same command identity and durable task.

Parameters

commitDNSReconciliationTask Parameters
NameInTypeRequiredDescription
site_idpathstring(uuid)YesCanonical lower-case UUID of a site in the authenticated tenant.
task_idpathstring(uuid)YesCanonical lower-case UUID of a dns_reconcile job.
X-Request-IDheaderstringYes—
traceparentheaderstringYes—
Idempotency-KeyheaderstringYesStable command key; retry only with the same route and payload.
If-MatchheaderstringYesStrong quoted decimal provider/task revision, for example `"7"`.

Request body

application/json · Required:Yes

Responses

commitDNSReconciliationTask Responses
StatusDescription
200Current durable task facts.

Fields:id: string(uuid) tenant_id: string(uuid) site_id: string(uuid) revision: integer(int64) required_consecutive: integer job: Job request: CheckRequest result: ReconcileResult created_at: string(date-time) updated_at: string(date-time) replayed: boolean

400Non-canonical path/header, unsupported media type, oversized body, unknown field, or invalid JSON.
401Exactly one valid Bearer session is required.
403Live IAM permission or DNS reconciliation entitlement denied.
404Task is absent or outside the authenticated tenant/site scope.
405Method is not supported by this route.
409Idempotency payload conflict or task state does not permit the command.
412If-Match or provider revision is stale.
408Mutation result is unknown; retry only with the same key and payload.
503Mutation result is unknown; retry only with the same key and payload.
504Mutation result is unknown; retry only with the same key and payload.

What to do on failure

  • 400 Fix the parameters or body per the field list; do not retry unchanged.
  • 401 Check the credential format and whether it expired or was rotated.
  • 403 Check the key scopes, the owner’s current permissions and the tenant scope; never switch to a more privileged account.
  • 404 The resource does not exist or belongs to another tenant.
  • 409 Read the current state first; a retry of the same operation keeps the original Idempotency-Key and body.
  • 412 The revision changed: read the latest ETag, decide again, then send the new If-Match.
  • 503 A dependency is unavailable: retry later with the original Idempotency-Key.

↑ Back to list

GET /v1/sites/{site_id}/traffic-limit

Read a website's traffic caps and their enforcement (sites.read)

operationId
getSiteTrafficLimit
Auth
  • Session: the Bearer session of a signed-in control plane user, used by the customer in their own control plane; a plugin must never ask for it.
Required permissions

The contract has no separate permission annotation; see the description below and the 403 response.

Parameters

getSiteTrafficLimit Parameters
NameInTypeRequiredDescription
site_idpathstring(uuid)Yes—

Responses

getSiteTrafficLimit Responses
StatusDescription
200The caps; ETag is the site version.

Fields:site_id: string(uuid) version: integer setting: SiteTrafficLimitSetting total_since: string(date-time) | null(date-time) exceeded_period: string: / daily / monthly / total exceeded_at: string(date-time) | null(date-time) evaluated_at: string(date-time) | null(date-time) updated_at: string(date-time) | null(date-time)

400validation_error, site_not_found, site_locked, version_conflict or idempotency_conflict.
403validation_error, site_not_found, site_locked, version_conflict or idempotency_conflict.
404validation_error, site_not_found, site_locked, version_conflict or idempotency_conflict.

What to do on failure

  • 400 Fix the parameters or body per the field list; do not retry unchanged.
  • 403 Check the key scopes, the owner’s current permissions and the tenant scope; never switch to a more privileged account.
  • 404 The resource does not exist or belongs to another tenant.

↑ Back to list

PUT /v1/sites/{site_id}/traffic-limit

Replace a website's traffic caps (sites.manage)

operationId
putSiteTrafficLimit
Auth
  • Session: the Bearer session of a signed-in control plane user, used by the customer in their own control plane; a plugin must never ask for it.
Required permissions

The contract has no separate permission annotation; see the description below and the 403 response.

Parameters

putSiteTrafficLimit Parameters
NameInTypeRequiredDescription
site_idpathstring(uuid)Yes—
Idempotency-KeyheaderstringYes—
If-MatchheaderstringYesThe quoted site version.

Request body

application/json · Required:Yes

putSiteTrafficLimit Request body
NameTypeRequiredDescription
enabledbooleanYesAn enabled limit needs at least one cap.
daily_bytesinteger | nullYes—
monthly_bytesinteger | nullYes—
total_bytesinteger | nullYesCounted from total_since (set when the total cap is set or changed).
time_zonestringYesIANA zone the daily and monthly periods start in ("" means Asia/Shanghai).
notice_htmlstringYesPage served with status 509 while exceeded ("" the default page).

Responses

putSiteTrafficLimit Responses
StatusDescription
200The stored caps; the site's next release enforces them.

Fields:site_id: string(uuid) version: integer setting: SiteTrafficLimitSetting total_since: string(date-time) | null(date-time) exceeded_period: string: / daily / monthly / total exceeded_at: string(date-time) | null(date-time) evaluated_at: string(date-time) | null(date-time) updated_at: string(date-time) | null(date-time)

400validation_error, site_not_found, site_locked, version_conflict or idempotency_conflict.
403validation_error, site_not_found, site_locked, version_conflict or idempotency_conflict.
404validation_error, site_not_found, site_locked, version_conflict or idempotency_conflict.
409validation_error, site_not_found, site_locked, version_conflict or idempotency_conflict.

What to do on failure

  • 400 Fix the parameters or body per the field list; do not retry unchanged.
  • 403 Check the key scopes, the owner’s current permissions and the tenant scope; never switch to a more privileged account.
  • 404 The resource does not exist or belongs to another tenant.
  • 409 Read the current state first; a retry of the same operation keeps the original Idempotency-Key and body.

↑ Back to list