Set a tenant's write-mode (relocation quiesce / ownership flip)
const url = 'https://api.aerandil.com/v1/tenant-write-mode?tenant_id=2489E9AD-2EE2-8E00-8EC9-32D5F69181C0';const options = { method: 'PUT', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"mode":"active","reason":"example"}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request PUT \ --url 'https://api.aerandil.com/v1/tenant-write-mode?tenant_id=2489E9AD-2EE2-8E00-8EC9-32D5F69181C0' \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "mode": "active", "reason": "example" }'Set the tenant’s write-mode. Setting read_only is the quiesce step of a cross-cell relocation cutover (cloud proposal 0007 §4 step 3): while read_only, the tenant’s writes are refused at the store’s write-gate and surface as 503 + Retry-After on every write endpoint, while reads stay live. Setting relocated is the post-cutover ownership flip (0007 §5): the Hub flips the source cell to not-owner once the tenant has been rebound to its new cell, and a straggler write that still resolves here is refused with 421 Misdirected Request (terminal — re-resolve to the owning cell), while reads stay live. Setting active lifts either state.
Idempotent: PUT replaces a singleton operational state, so it carries no Idempotency-Key, and no If-Match (this is operator state, not a versioned object — last writer wins).
Operator-level scope: tenant_admin:write.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Query Parameters
Section titled “Query Parameters”The tenant whose write-mode is read or set.
Request Bodyrequired
Section titled “Request Bodyrequired”Set a tenant’s write-mode, with an optional operator note.
object
read_only quiesces the tenant (writes refused with 503 + Retry-After; reads live) — the transient cutover freeze; relocated marks this cell as no longer the owner after a relocation cuts over (writes refused with 421 Misdirected Request; reads live) — the §5 ownership flip, terminal at this cell; active lifts either state.
Operator note recorded for audit (e.g. the relocation job id).
Responses
Section titled “Responses”The persisted write-mode record.
A tenant’s write-mode plus the provenance of the last change. A tenant that was never set reads back active with null provenance.
object
Operator note from the last set, if any.
The principal that last set the mode (serialised).
When the mode was last set; null for a synthesised default.
Example
{ "mode": "active"}Missing the tenant_admin:write scope. Tenant-level tokens MUST NOT carry this scope.
Structured error wrapper. Every non-2xx response from any Aerandil endpoint serialises to this shape; the HTTP status carries the failure class (4xx/5xx), the body adds a stable code for programmatic dispatch plus a human-readable message.
object
object
Stable, programmatic error code (e.g. unauthorized, forbidden, not_found, invalid_body, invalid_url, precondition_failed, no_secondary_key). Clients dispatch on code, not on the message (which may be localised or contextualised in future versions).
Request-id correlation handle echoed on the request-id response header — support teams correlate without scraping logs.
Human-readable explanation of the failure.
Per-error structured detail. The shape varies by code (e.g. forbidden_action carries {"action": "..."}; precondition_failed carries {"current_version": N}).
Examplegenerated
{ "error": { "code": "example", "instance_id": "example", "message": "example", "parameters": "example" }}Body invalid — unknown field or unrecognised mode.
Structured error wrapper. Every non-2xx response from any Aerandil endpoint serialises to this shape; the HTTP status carries the failure class (4xx/5xx), the body adds a stable code for programmatic dispatch plus a human-readable message.
object
object
Stable, programmatic error code (e.g. unauthorized, forbidden, not_found, invalid_body, invalid_url, precondition_failed, no_secondary_key). Clients dispatch on code, not on the message (which may be localised or contextualised in future versions).
Request-id correlation handle echoed on the request-id response header — support teams correlate without scraping logs.
Human-readable explanation of the failure.
Per-error structured detail. The shape varies by code (e.g. forbidden_action carries {"action": "..."}; precondition_failed carries {"current_version": N}).
Examplegenerated
{ "error": { "code": "example", "instance_id": "example", "message": "example", "parameters": "example" }}