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| Name | In | Type | Required | Description |
|---|
page | query | integer | No | — |
|---|
limit | query | integer | No | — |
|---|
domain | query | string | No | Case-insensitive domain substring; a positive decimal also matches the site display ID exactly. |
|---|
domains | query | string | No | Comma- or whitespace-separated exact domains, at most 50. |
|---|
origin_ip | query | string | No | — |
|---|
site_ids | query | string | No | Comma- or whitespace-separated UUIDs, at most 100. |
|---|
owner | query | string | No | — |
|---|
package_id | query | string(uuid) | No | — |
|---|
package | query | string | No | Case-insensitive substring of the site's package name (the name form of package_id). |
|---|
site | query | string | No | Case-insensitive domain substring or exact site display ID (the name form of site_ids). |
|---|
group_id | query | string(uuid) | No | — |
|---|
region_id | query | string(uuid) | No | — |
|---|
node_group_id | query | string(uuid) | No | — |
|---|
cname_domain | query | string | No | — |
|---|
cname_hostname | query | string | No | — |
|---|
http_port | query | string | No | — |
|---|
https_port | query | string | No | — |
|---|
https_enabled | query | boolean | No | — |
|---|
enabled | query | boolean | No | — |
|---|
status | query | string: active / disabled / package_expired / traffic_exceeded / locked / syncing / sync_failed | No | — |
|---|
is_default | query | boolean | No | — |
|---|
sync_status | query | string: synced / pending / failed | No | — |
|---|
Responses
listSites Responses| Status | Description |
|---|
200 | Stable page ordered by creation time and ID descending. Fields:items: array<SiteListItem> total: integer(int64) page: integer limit: integer |
|---|
400 | Invalid JSON, field, or query input. |
|---|
401 | Authentication is required. |
|---|
403 | The principal lacks sites.read or sites.manage. |
|---|
500 | The 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| Name | In | Type | Required | Description |
|---|
Idempotency-Key | header | string | Yes | Stable per-actor key. Reuse with different normalized input returns 409 idempotency_conflict. |
|---|
Request body
application/json · Required:Yes
createSite Request body| Name | Type | Required | Description |
|---|
target_scope_id | string(uuid) | No | — |
|---|
owner_id | string(uuid) | No | — |
|---|
basic | SiteBasicRequest | Yes | — |
|---|
origin_pool | OriginPool | No | Optional 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_id | string(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| Status | Description |
|---|
201 | Created, 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 |
|---|
400 | Invalid JSON, field, or query input. |
|---|
401 | Authentication is required. |
|---|
403 | The principal lacks sites.read or sites.manage. |
|---|
409 | Domain, version, idempotency, website lock-state, or origin-section conflict. |
|---|
500 | The 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| Name | In | Type | Required | Description |
|---|
Idempotency-Key | header | string | Yes | Stable per-actor key. Reuse with different normalized input returns 409 idempotency_conflict. |
|---|
Request body
application/json · Required:Yes
batchSiteAction Request body| Name | Type | Required | Description |
|---|
action | string: enable / disable / delete / regenerate_cname / set_protocols | Yes | — |
|---|
items | array<BatchSiteActionItem> | Yes | Site IDs must be unique even when expected versions differ. |
|---|
protocols | BatchSiteProtocols | No | Required 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| Status | Description |
|---|
200 | Ordered per-item results, or the stored result of an identical idempotent retry. Fields:items: array<BatchSiteActionItemResult> |
|---|
400 | Invalid JSON, field, or query input. |
|---|
401 | Authentication is required. |
|---|
403 | The principal lacks sites.read or sites.manage. |
|---|
409 | Domain, version, idempotency, website lock-state, or origin-section conflict. |
|---|
500 | The 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| Name | In | Type | Required | Description |
|---|
target_scope_id | query | string(uuid) | No | Required for platform principals; tenants may omit their own scope. |
|---|
domain | query | string | No | Optional case-insensitive domain substring filter. |
|---|
domains | query | string | No | Comma- or whitespace-separated exact domains, at most 50. |
|---|
origin_ip | query | string | No | — |
|---|
site_ids | query | string | No | Comma- or whitespace-separated UUIDs, at most 100. |
|---|
owner | query | string | No | — |
|---|
package_id | query | string(uuid) | No | — |
|---|
package | query | string | No | Case-insensitive substring of the site's package name (the name form of package_id). |
|---|
site | query | string | No | Case-insensitive domain substring or exact site display ID (the name form of site_ids). |
|---|
group_id | query | string(uuid) | No | — |
|---|
region_id | query | string(uuid) | No | — |
|---|
node_group_id | query | string(uuid) | No | — |
|---|
cname_domain | query | string | No | — |
|---|
cname_hostname | query | string | No | — |
|---|
http_port | query | string | No | — |
|---|
https_port | query | string | No | — |
|---|
https_enabled | query | boolean | No | — |
|---|
enabled | query | boolean | No | — |
|---|
status | query | string: active / disabled / package_expired / traffic_exceeded / locked / syncing / sync_failed | No | — |
|---|
is_default | query | boolean | No | — |
|---|
sync_status | query | string: synced / pending / failed | No | — |
|---|
Responses
exportSiteDomains Responses| Status | Description |
|---|
200 | Immutable site-domain snapshot in deterministic order. |
|---|
400 | Invalid JSON, field, or query input. |
|---|
401 | Authentication is required. |
|---|
403 | The principal lacks sites.read or sites.manage. |
|---|
500 | The 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| Name | In | Type | Required | Description |
|---|
id | path | string(uuid) | Yes | — |
|---|
Responses
getSite Responses| Status | Description |
|---|
200 | Website 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 |
|---|
400 | Invalid JSON, field, or query input. |
|---|
401 | Authentication is required. |
|---|
403 | The principal lacks sites.read or sites.manage. |
|---|
404 | The site is absent, deleted, or outside the tenant scope. |
|---|
500 | The 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| Name | In | Type | Required | Description |
|---|
id | path | string(uuid) | Yes | — |
|---|
Idempotency-Key | header | string | Yes | Stable per-actor key. Reuse with different normalized input returns 409 idempotency_conflict. |
|---|
Request body
application/json · Required:Yes
Responses
updateSiteSettings Responses| Status | Description |
|---|
200 | Updated, 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 |
|---|
400 | Invalid JSON, field, or query input. |
|---|
401 | Authentication is required. |
|---|
403 | The principal lacks sites.read or sites.manage. |
|---|
404 | The site is absent, deleted, or outside the tenant scope. |
|---|
409 | Domain, version, idempotency, website lock-state, or origin-section conflict. |
|---|
500 | The 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| Name | In | Type | Required | Description |
|---|
id | path | string(uuid) | Yes | — |
|---|
Idempotency-Key | header | string | Yes | Stable per-actor key. Reuse with different normalized input returns 409 idempotency_conflict. |
|---|
If-Match | header | string | Yes | Quoted decimal version returned by ETag. |
|---|
Responses
deleteSite Responses| Status | Description |
|---|
204 | Deleted, or an identical delete retry was replayed. |
|---|
400 | Invalid JSON, field, or query input. |
|---|
401 | Authentication is required. |
|---|
403 | The principal lacks sites.read or sites.manage. |
|---|
404 | The site is absent, deleted, or outside the tenant scope. |
|---|
409 | Domain, version, idempotency, website lock-state, or origin-section conflict. |
|---|
500 | The 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| Name | In | Type | Required | Description |
|---|
id | path | string(uuid) | Yes | — |
|---|
Responses
checkSiteAccess Responses| Status | Description |
|---|
200 | The site's access readiness after the check. Fields:state: string: ready / pending / blocked checks: array<SiteAccessCheck> |
|---|
400 | Invalid JSON, field, or query input. |
|---|
401 | Authentication is required. |
|---|
403 | The principal lacks sites.read or sites.manage. |
|---|
404 | The site is absent, deleted, or outside the tenant scope. |
|---|
429 | Rate limited; Retry-After gives the seconds to wait. |
|---|
500 | The 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| Name | In | Type | Required | Description |
|---|
id | path | string(uuid) | Yes | — |
|---|
Request body
application/json · Required:Yes
syncSiteAutoDNS Request body| Name | Type | Required | Description |
|---|
provider_id | string(uuid) | No | another account of the owner; omitted keeps the task's |
|---|
Responses
syncSiteAutoDNS Responses| Status | Description |
|---|
202 | Task 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) |
|---|
400 | Invalid JSON, field, or query input. |
|---|
401 | Authentication is required. |
|---|
403 | The principal lacks sites.read or sites.manage. |
|---|
404 | The site is absent, deleted, or outside the tenant scope. |
|---|
422 | Domain, version, idempotency, website lock-state, or origin-section conflict. |
|---|
500 | The 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| Name | In | Type | Required | Description |
|---|
id | path | string(uuid) | Yes | — |
|---|
Idempotency-Key | header | string | Yes | Stable per-actor key. Reuse with different normalized input returns 409 idempotency_conflict. |
|---|
Request body
application/json · Required:Yes
lockSite Request body| Name | Type | Required | Description |
|---|
expected_version | integer(int64) | Yes | — |
|---|
reason | string | Yes | — |
|---|
Responses
lockSite Responses| Status | Description |
|---|
200 | Locked, 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 |
|---|
400 | Invalid JSON, field, or query input. |
|---|
401 | Authentication is required. |
|---|
403 | The principal lacks sites.read or sites.manage. |
|---|
404 | The site is absent, deleted, or outside the tenant scope. |
|---|
409 | Domain, version, idempotency, website lock-state, or origin-section conflict. |
|---|
500 | The 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| Name | In | Type | Required | Description |
|---|
id | path | string(uuid) | Yes | — |
|---|
Idempotency-Key | header | string | Yes | Stable per-actor key. Reuse with different normalized input returns 409 idempotency_conflict. |
|---|
Responses
failbackSiteOrigin Responses| Status | Description |
|---|
200 | State 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) |
|---|
401 | Authentication is required. |
|---|
403 | The principal lacks sites.read or sites.manage. |
|---|
404 | The site is absent, deleted, or outside the tenant scope. |
|---|
409 | Domain, version, idempotency, website lock-state, or origin-section conflict. |
|---|
500 | The 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| Name | In | Type | Required | Description |
|---|
id | path | string(uuid) | Yes | — |
|---|
Responses
getSiteOriginRouting Responses| Status | Description |
|---|
200 | Current 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) |
|---|
400 | Invalid JSON, field, or query input. |
|---|
401 | Authentication is required. |
|---|
403 | The principal lacks sites.read or sites.manage. |
|---|
404 | The site is absent, deleted, or outside the tenant scope. |
|---|
500 | The 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| Name | In | Type | Required | Description |
|---|
id | path | string(uuid) | Yes | — |
|---|
Idempotency-Key | header | string | Yes | Stable per-actor key. Reuse with different normalized input returns 409 idempotency_conflict. |
|---|
If-Match | header | string | Yes | Quoted decimal version returned by ETag. |
|---|
Request body
application/json · Required:Yes
replaceSiteOriginRouting Request body| Name | Type | Required | Description |
|---|
schema | string | Yes | — |
|---|
ingress_source_enabled | boolean | Yes | — |
|---|
pools | array<ConditionalOriginPool> | Yes | — |
|---|
default_pool_id | string | Yes | — |
|---|
default_fallback_pool_id | string | No | — |
|---|
routes | array<ConditionalOriginRoute> | Yes | — |
|---|
retry | ConditionalOriginRetry | Yes | — |
|---|
Responses
replaceSiteOriginRouting Responses| Status | Description |
|---|
200 | Updated 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) |
|---|
400 | Invalid JSON, field, or query input. |
|---|
401 | Authentication is required. |
|---|
403 | The principal lacks sites.read or sites.manage. |
|---|
404 | The site is absent, deleted, or outside the tenant scope. |
|---|
409 | Domain, version, idempotency, website lock-state, or origin-section conflict. |
|---|
500 | The 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| Name | In | Type | Required | Description |
|---|
id | path | string(uuid) | Yes | — |
|---|
Responses
getSiteOriginStatus Responses| Status | Description |
|---|
200 | Current 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) |
|---|
401 | Authentication is required. |
|---|
403 | The principal lacks sites.read or sites.manage. |
|---|
404 | The site is absent, deleted, or outside the tenant scope. |
|---|
500 | The 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| Name | In | Type | Required | Description |
|---|
id | path | string(uuid) | Yes | — |
|---|
Responses
getSiteSchedule302 Responses| Status | Description |
|---|
200 | Current 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) |
|---|
400 | Invalid JSON, field, or query input. |
|---|
401 | Authentication is required. |
|---|
403 | The principal lacks sites.read or sites.manage. |
|---|
404 | The site is absent, deleted, or outside the tenant scope. |
|---|
500 | The 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| Name | In | Type | Required | Description |
|---|
id | path | string(uuid) | Yes | — |
|---|
Idempotency-Key | header | string | Yes | Stable per-actor key. Reuse with different normalized input returns 409 idempotency_conflict. |
|---|
If-Match | header | string | Yes | Quoted decimal version returned by ETag. |
|---|
Request body
application/json · Required:Yes
replaceSiteSchedule302 Request body| Name | Type | Required | Description |
|---|
enabled | boolean | Yes | — |
|---|
target | string: address / hostname | Yes | Redirect to the node's line-group endpoint address, or to its direct hostname (nodes without one are skipped). |
|---|
keep_path | boolean | Yes | — |
|---|
keep_query | boolean | Yes | — |
|---|
signature_ttl_seconds | integer | Yes | — |
|---|
https_to_http | boolean | Yes | Also redirect HTTPS requests; they land on plain HTTP (nodes hold no certificate for their address). |
|---|
extensions | array<string> | Yes | — |
|---|
path_prefixes | array<string> | Yes | — |
|---|
min_size_bytes | integer | Yes | Redirect only URLs whose response the node already served at least this large (0 off). |
|---|
Responses
replaceSiteSchedule302 Responses| Status | Description |
|---|
200 | Updated 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) |
|---|
400 | Invalid JSON, field, or query input. |
|---|
401 | Authentication is required. |
|---|
403 | The principal lacks sites.read or sites.manage. |
|---|
404 | The site is absent, deleted, or outside the tenant scope. |
|---|
409 | Domain, version, idempotency, website lock-state, or origin-section conflict. |
|---|
422 | Invalid JSON, field, or query input. |
|---|
500 | The 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| Name | In | Type | Required | Description |
|---|
id | path | string(uuid) | Yes | — |
|---|
Idempotency-Key | header | string | Yes | Stable per-actor key. Reuse with different normalized input returns 409 idempotency_conflict. |
|---|
Request body
application/json · Required:Yes
transferSite Request body| Name | Type | Required | Description |
|---|
expected_version | integer(int64) | Yes | — |
|---|
target_user_id | string(uuid) | Yes | — |
|---|
target_package_subscription_id | string(uuid) | null(uuid) | No | — |
|---|
Responses
transferSite Responses| Status | Description |
|---|
201 | Moved, 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> |
|---|
400 | Invalid JSON, field, or query input. |
|---|
401 | Authentication is required. |
|---|
403 | The principal lacks sites.read or sites.manage. |
|---|
404 | The site is absent, deleted, or outside the tenant scope. |
|---|
409 | domain_verified_by_other, domain_ownership_required, site_locked, version_conflict or idempotency_conflict. |
|---|
422 | site_transfer_target_invalid or domain_blocked. |
|---|
500 | The 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| Name | In | Type | Required | Description |
|---|
id | path | string(uuid) | Yes | — |
|---|
Idempotency-Key | header | string | Yes | Stable per-actor key. Reuse with different normalized input returns 409 idempotency_conflict. |
|---|
Request body
application/json · Required:Yes
unlockSite Request body| Name | Type | Required | Description |
|---|
expected_version | integer(int64) | Yes | — |
|---|
Responses
unlockSite Responses| Status | Description |
|---|
200 | Unlocked, 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 |
|---|
400 | Invalid JSON, field, or query input. |
|---|
401 | Authentication is required. |
|---|
403 | The principal lacks sites.read or sites.manage. |
|---|
404 | The site is absent, deleted, or outside the tenant scope. |
|---|
409 | Domain, version, idempotency, website lock-state, or origin-section conflict. |
|---|
500 | The 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| Name | In | Type | Required | Description |
|---|
site_id | path | string(uuid) | Yes | — |
|---|
Responses
getSiteAccess Responses| Status | Description |
|---|
200 | The 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) |
|---|
400 | Error |
|---|
401 | Error |
|---|
403 | Error |
|---|
404 | Error |
|---|
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| Name | In | Type | Required | Description |
|---|
site_id | path | string(uuid) | Yes | — |
|---|
Idempotency-Key | header | string | Yes | — |
|---|
If-Match | header | string | Yes | The quoted site version (GET ETag) |
|---|
Request body
application/json · Required:Yes
replaceSiteAccess Request body| Name | Type | Required | Description |
|---|
host_redirects | array<HostRedirect> | No | — |
|---|
hsts | HSTS | null | No | — |
|---|
compression | Compression | null | No | — |
|---|
limits | Limits | null | No | — |
|---|
basic_auth | BasicAuth | null | No | — |
|---|
maintenance | Maintenance | null | No | — |
|---|
webp | WebP | null | No | — |
|---|
response_rules | array<ResponseRule> | No | Response 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_https | ForceHTTPS | No | — |
|---|
Responses
replaceSiteAccess Responses| Status | Description |
|---|
200 | The 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) |
|---|
400 | Error |
|---|
401 | Error |
|---|
403 | Error |
|---|
404 | Error |
|---|
409 | site_locked, version_conflict or idempotency_conflict |
|---|
422 | validation_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| Name | In | Type | Required | Description |
|---|
site_id | path | string(uuid) | Yes | — |
|---|
target_scope_id | query | string(uuid) | No | Required 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-ID | header | string | No | — |
|---|
Responses
getCertificateSiteBinding Responses| Status | Description |
|---|
200 | Active site certificate binding and version Fields:binding: CertificateAssetBinding version: CertificateAssetVersion |
|---|
400 | Invalid request, metadata or certificate material |
|---|
401 | Bearer session missing or invalid |
|---|
403 | Tenant scope or live permission denied |
|---|
404 | Certificate asset or version not found |
|---|
405 | Method not allowed |
|---|
500 | Sanitized 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| Name | In | Type | Required | Description |
|---|
site_id | path | string(uuid) | Yes | Canonical lower-case UUID of a site in the authenticated tenant. |
|---|
X-Request-ID | header | string | Yes | — |
|---|
traceparent | header | string | Yes | — |
|---|
Idempotency-Key | header | string | Yes | Stable command key; retry only with the same route and payload. |
|---|
If-Match | header | string | Yes | Strong quoted decimal provider/task revision, for example `"7"`. |
|---|
Request body
application/json · Required:Yes
applyDNSReconciliation Request body| Name | Type | Required | Description |
|---|
name | string | Yes | — |
|---|
expected | array<ExpectedRecord> | Yes | — |
|---|
authoritative_ns | array<string> | Yes | — |
|---|
ttl | integer | Yes | — |
|---|
line | string | No | Provider routing line. Empty/default values preserve the provider default line. |
|---|
weight | integer | No | Provider record weight; zero is the provider default. |
|---|
propagation_started_at | string(date-time) | No | — |
|---|
propagation_window_seconds | integer | Yes | — |
|---|
provider | ProviderSnapshot | Yes | — |
|---|
Responses
applyDNSReconciliation Responses| Status | Description |
|---|
202 | Durable 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 |
|---|
400 | Non-canonical path/header, unsupported media type, oversized body, unknown field, or invalid JSON. |
|---|
401 | Exactly one valid Bearer session is required. |
|---|
403 | Live IAM permission or DNS reconciliation entitlement denied. |
|---|
405 | Method is not supported by this route. |
|---|
409 | Idempotency payload conflict or task state does not permit the command. |
|---|
412 | If-Match or provider revision is stale. |
|---|
408 | Mutation result is unknown; retry only with the same key and payload. |
|---|
503 | Mutation result is unknown; retry only with the same key and payload. |
|---|
504 | Mutation 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| Name | In | Type | Required | Description |
|---|
site_id | path | string(uuid) | Yes | Canonical lower-case UUID of a site in the authenticated tenant. |
|---|
X-Request-ID | header | string | Yes | — |
|---|
traceparent | header | string | Yes | — |
|---|
Request body
application/json · Required:Yes
dryRunDNSReconciliation Request body| Name | Type | Required | Description |
|---|
name | string | Yes | — |
|---|
expected | array<ExpectedRecord> | Yes | — |
|---|
authoritative_ns | array<string> | Yes | — |
|---|
ttl | integer | Yes | — |
|---|
line | string | No | Provider routing line. Empty/default values preserve the provider default line. |
|---|
weight | integer | No | Provider record weight; zero is the provider default. |
|---|
propagation_started_at | string(date-time) | No | — |
|---|
propagation_window_seconds | integer | Yes | — |
|---|
provider | ProviderSnapshot | Yes | — |
|---|
Responses
dryRunDNSReconciliation Responses| Status | Description |
|---|
200 | Deterministic 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 |
|---|
400 | Non-canonical path/header, unsupported media type, oversized body, unknown field, or invalid JSON. |
|---|
401 | Exactly one valid Bearer session is required. |
|---|
403 | Live IAM permission or DNS reconciliation entitlement denied. |
|---|
405 | Method is not supported by this route. |
|---|
408 | Read-only request was cancelled. |
|---|
503 | Required runtime dependency is unavailable. |
|---|
504 | Read-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| Name | In | Type | Required | Description |
|---|
site_id | path | string(uuid) | Yes | Canonical lower-case UUID of a site in the authenticated tenant. |
|---|
task_id | path | string(uuid) | Yes | Canonical lower-case UUID of a dns_reconcile job. |
|---|
X-Request-ID | header | string | No | — |
|---|
traceparent | header | string | No | — |
|---|
Responses
getDNSReconciliationTask Responses| Status | Description |
|---|
200 | Current 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 |
|---|
400 | Non-canonical path/header, unsupported media type, oversized body, unknown field, or invalid JSON. |
|---|
401 | Exactly one valid Bearer session is required. |
|---|
403 | Live IAM permission or DNS reconciliation entitlement denied. |
|---|
404 | Task is absent or outside the authenticated tenant/site scope. |
|---|
405 | Method is not supported by this route. |
|---|
408 | Read-only request was cancelled. |
|---|
503 | Required runtime dependency is unavailable. |
|---|
504 | Read-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| Name | In | Type | Required | Description |
|---|
site_id | path | string(uuid) | Yes | Canonical lower-case UUID of a site in the authenticated tenant. |
|---|
task_id | path | string(uuid) | Yes | Canonical lower-case UUID of a dns_reconcile job. |
|---|
X-Request-ID | header | string | Yes | — |
|---|
traceparent | header | string | Yes | — |
|---|
Idempotency-Key | header | string | Yes | Stable command key; retry only with the same route and payload. |
|---|
If-Match | header | string | Yes | Strong quoted decimal provider/task revision, for example `"7"`. |
|---|
Request body
application/json · Required:Yes
Responses
cancelDNSReconciliationTask Responses| Status | Description |
|---|
200 | Current 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 |
|---|
400 | Non-canonical path/header, unsupported media type, oversized body, unknown field, or invalid JSON. |
|---|
401 | Exactly one valid Bearer session is required. |
|---|
403 | Live IAM permission or DNS reconciliation entitlement denied. |
|---|
404 | Task is absent or outside the authenticated tenant/site scope. |
|---|
405 | Method is not supported by this route. |
|---|
409 | Idempotency payload conflict or a provider operation is still in flight. |
|---|
412 | If-Match or provider revision is stale. |
|---|
408 | Mutation result is unknown; retry only with the same key and payload. |
|---|
503 | Mutation result is unknown; retry only with the same key and payload. |
|---|
504 | Mutation 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| Name | In | Type | Required | Description |
|---|
site_id | path | string(uuid) | Yes | Canonical lower-case UUID of a site in the authenticated tenant. |
|---|
task_id | path | string(uuid) | Yes | Canonical lower-case UUID of a dns_reconcile job. |
|---|
X-Request-ID | header | string | Yes | — |
|---|
traceparent | header | string | Yes | — |
|---|
Idempotency-Key | header | string | Yes | Stable command key; retry only with the same route and payload. |
|---|
If-Match | header | string | Yes | Strong quoted decimal provider/task revision, for example `"7"`. |
|---|
Request body
application/json · Required:Yes
Responses
commitDNSReconciliationTask Responses| Status | Description |
|---|
200 | Current 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 |
|---|
400 | Non-canonical path/header, unsupported media type, oversized body, unknown field, or invalid JSON. |
|---|
401 | Exactly one valid Bearer session is required. |
|---|
403 | Live IAM permission or DNS reconciliation entitlement denied. |
|---|
404 | Task is absent or outside the authenticated tenant/site scope. |
|---|
405 | Method is not supported by this route. |
|---|
409 | Idempotency payload conflict or task state does not permit the command. |
|---|
412 | If-Match or provider revision is stale. |
|---|
408 | Mutation result is unknown; retry only with the same key and payload. |
|---|
503 | Mutation result is unknown; retry only with the same key and payload. |
|---|
504 | Mutation 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| Name | In | Type | Required | Description |
|---|
site_id | path | string(uuid) | Yes | — |
|---|
Responses
getSiteTrafficLimit Responses| Status | Description |
|---|
200 | The 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) |
|---|
400 | validation_error, site_not_found, site_locked, version_conflict or idempotency_conflict. |
|---|
403 | validation_error, site_not_found, site_locked, version_conflict or idempotency_conflict. |
|---|
404 | validation_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| Name | In | Type | Required | Description |
|---|
site_id | path | string(uuid) | Yes | — |
|---|
Idempotency-Key | header | string | Yes | — |
|---|
If-Match | header | string | Yes | The quoted site version. |
|---|
Request body
application/json · Required:Yes
putSiteTrafficLimit Request body| Name | Type | Required | Description |
|---|
enabled | boolean | Yes | An enabled limit needs at least one cap. |
|---|
daily_bytes | integer | null | Yes | — |
|---|
monthly_bytes | integer | null | Yes | — |
|---|
total_bytes | integer | null | Yes | Counted from total_since (set when the total cap is set or changed). |
|---|
time_zone | string | Yes | IANA zone the daily and monthly periods start in ("" means Asia/Shanghai). |
|---|
notice_html | string | Yes | Page served with status 509 while exceeded ("" the default page). |
|---|
Responses
putSiteTrafficLimit Responses| Status | Description |
|---|
200 | The 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) |
|---|
400 | validation_error, site_not_found, site_locked, version_conflict or idempotency_conflict. |
|---|
403 | validation_error, site_not_found, site_locked, version_conflict or idempotency_conflict. |
|---|
404 | validation_error, site_not_found, site_locked, version_conflict or idempotency_conflict. |
|---|
409 | validation_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