Cut a house over from its source PMS
const url = 'https://api.aerandil.com/v1/switchover/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0/cut-over';const options = { method: 'POST', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"channel_connection_ids":["2489E9AD-2EE2-8E00-8EC9-32D5F69181C0"],"reason":"example"}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://api.aerandil.com/v1/switchover/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0/cut-over \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "channel_connection_ids": [ "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0" ], "reason": "example" }'The switchover’s decision: stop treating the connector’s source PMS as the system of record. Refused unless it is safe: the route first reads the shadow comparison (GET /v1/analytics/switchover-shadow) and answers 409 cutover_blocked — the counts in the message, the blocking discrepancies (at most 50) and the summary in parameters — while anything blocks; it never asks the caller to underwrite an unsafe cutover. A connector already cut over answers 409 already_cut_over (with its cut_over_at), a retired one 409 connector_retired, any other not active one 409 connector_not_active.
Then, in one transaction (cut_over_connector): the connector is paused with a reason naming the decision and stamped cut_over_at / cut_over_by / cut_over_summary (the pre-flight it was taken on), and each named channel conduit is brought live (paused → active; a conduit pending mapping, suspended, closed or unmapped refuses the whole gesture, 422, before anything is written). In-house guests are never re-keyed.
Then each conduit is published in full: a full channel_publication_run over today to the conduit’s horizon, its cells seeded so the dispatcher sends the whole of the house’s availability, rates and restrictions — clearing closures the partner still holds from the old PMS. A conduit the partner’s 24-hour floor refuses is reported skipped (the cutover stands; publish later), one that fails failed.
Needs the catch-all actions:apply or the route’s own grant; not from a desk bound to one property. Accepts an Idempotency-Key. Live data: Cache-Control: no-store.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Path Parameters
Section titled “Path Parameters”The connector object’s id.
Header Parameters
Section titled “Header Parameters”Opaque idempotency token (Stripe-shape). Repeated POSTs with the same key replay the original response within the cache TTL rather than creating a duplicate object.
Request Body
Section titled “Request Body”object
The channel conduits to bring live with the cutover: each mapped and paused (or already active).
Why, recorded on the connector.
Examplegenerated
{ "channel_connection_ids": [ "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0" ], "reason": "example"}Responses
Section titled “Responses”Cut over; each conduit’s full publication reported.
object
object
Outbox cells the horizon seed wrote.
Why a publication was skipped or failed.
The full channel_publication_run opened.
Present (true) when an Idempotency-Key replay answered.
The shadow comparison the decision was taken on, as recorded on the connector.
object
Per staged stream, its rows by load outcome. A staged row with no load outcome yet is pending.
object
The connector’s mapping for the stream (name@version); null when it carries none.
object
Example
{ "conduits": [ { "full_publication": "started" } ], "status": "paused"}Headers
Section titled “Headers”Always no-store. Object and link state is live data and is never cacheable.
Token lacks actions:apply and the route’s own grant, or is a desk session bound to one property.
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" }}No such connector, or no such channel conduit.
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" }}The cutover is refused: cutover_blocked (the shadow comparison has blocking discrepancies — parameters.blocking, parameters.by_kind, parameters.summary), already_cut_over, connector_retired, connector_not_active, connector_pipeline_invalid, or an Idempotency-Key still in flight.
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" }}Malformed body, or a named conduit cannot be brought live (pending mapping, suspended, closed or unmapped).
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" }}