Read a PMS switchover's shadow comparison
const url = 'https://api.aerandil.com/v1/analytics/switchover-shadow?connector_id=2489E9AD-2EE2-8E00-8EC9-32D5F69181C0';const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request GET \ --url 'https://api.aerandil.com/v1/analytics/switchover-shadow?connector_id=2489E9AD-2EE2-8E00-8EC9-32D5F69181C0' \ --header 'Authorization: Bearer <token>'One connector’s source PMS against Aerandil during the shadow run before cutover: per stream, what the loader has loaded, has still to load, rejected or deferred (and the newest rejects with their reasons); for the business date and the nine days after it, arrivals and departures on both sides (and in-house guests for the day); and per folio, the vendor’s status, dates, room and balance (charges less payments plus settled refunds, over every staged row naming the reservation, loaded or not) against the reservation’s own (its stays’ folios and rooms). Every disagreement is a named discrepancy: not_loaded, status_mismatch, dates_mismatch, balance_mismatch and room_mismatch block a cutover; aerandil_only (a booking at a house this connector feeds that the source never sent) is advisory. Only discrepant folios are listed; summary counts them all. ready_to_cut_over is no blocking discrepancy on an active connector.
Mapping-driven. The vendor side is read through the connector’s own mapping files — the pointers they declare, the loader’s coercion, the lifecycle their update variants dispatch — so it sees what the loader sees. blind_spots names, per provider, what the connector deliberately does not carry.
Live data: always Cache-Control: no-store.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Query Parameters
Section titled “Query Parameters”The connector object’s id.
The business date, YYYY-MM-DD. Defaults to today in the property’s timezone when the connector feeds one property, else today in UTC.
Responses
Section titled “Responses”The shadow comparison.
object
When the comparison was read.
What this provider’s feed cannot show, so the comparison cannot either (company accounts, pre-arrival deposits, refund legs, …) — the checks the house makes by hand.
The connector’s business id (CN-…): the source of its staged rows and the prefix of every external_ref it lands.
When the house cut over from this source; absent while shadowing.
The business date’s movement counts, computed identically both sides: arrivals and departures are non-cancelled reservations arriving / departing that day; in_house is reservations in house.
object
Every count matches across the two sides.
object
object
object
Every disagreement, named. Blocking: not_loaded (a pending, rejected or deferred row — detail carries the load error), status_mismatch, dates_mismatch, balance_mismatch, room_mismatch (an in-house reservation whose source room differs from its Aerandil stay’s). Advisory: aerandil_only (a non-cancelled reservation at a property this connector feeds that the source never sent).
object
Only the folios with a discrepancy — one per reservation the source sent; summary carries the counts over all of them. The source balance is its charges less its payments over every staged row referencing the reservation, loaded or not; the Aerandil balance is the sum of the reservation’s stays’ folio balances.
object
object
The room code of the reservation’s stay, when one is assigned.
object
The reservation’s status; null when it never loaded.
The reservation’s id in the source PMS.
The Aerandil reservation; null when it never loaded.
object
The room code the source assigns, when its feed carries one.
object
The lifecycle the source row reads as through the mapping: confirmed, in_house, checked_out, cancelled or no_show.
The mapping’s update variant the row matched (its own name), or null for a create-only row.
The business date and the nine days after it — the go-live check for overbookings in the next days: arrivals and departures both sides, per date, ascending.
object
object
object
No blocking discrepancy and the connector is active.
The rejected rows, newest first, at most 200.
object
When the row was last tried and refused.
The connector’s lifecycle status.
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
{ "discrepancies": [ { "kind": "not_loaded", "severity": "blocking" } ], "folios": [ { "discrepancies": [ "not_loaded" ] } ], "status": "active"}Headers
Section titled “Headers”Always no-store — live data.
Token lacks the analytics:read scope, or is a desk session bound to one property (a connector spans the houses it feeds).
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.
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 connector’s mappings do not form a runnable pipeline (connector_pipeline_invalid) — the worker pauses such a connector; repoint it first.
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 business_date.
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" }}