Staylah

Introduction

Staylah Connectivity API

What this API is, and what is live today.

Partner-facing reference for /api/connectivity/v1, plus the Staylah-side key administration routes at /api/connectivity-keys.

Source of truth for this document:

  • routes/api/connectivity/pull.php — partners reading from Staylah
  • routes/api/connectivity/push.php — partners writing into Staylah
  • routes/api/connectivity/keys.php — our own key admin (not partner-facing)
  • routes/api/connectivity/mappings.php — our own partner-code catalogue (not partner-facing)

0. Implementation status — read this first#

Every endpoint on this surface now serves live data. Nothing returns 501 not_implemented any more.

EndpointStatus
GET /ping✅ Live
GET /whoami✅ Live
GET /mapping/hotels✅ Live
GET /mapping/hotels/{hotelCode}✅ Live
POST /availability/search✅ Live
POST /availability/rates✅ Live
POST /bookings/quote✅ Live
POST /bookings✅ Live
GET /bookings/{reference}✅ Live
POST /bookings/{reference}/cancel✅ Live
PUT /ari✅ Live
PUT /ari/restrictions✅ Live
GET /ari/batches/{batchId}✅ Live
POST /reservations✅ Live
POST /reservations/{reference}/cancel✅ Live
POST /reservations/{reference}/modify✅ Live

The request contract did not change when the data went live. A payload that passed validation against the 501 build passes validation now, and nothing in your client needs to change — which was the point of publishing the contract first.

not_implemented stays in the error-code table because it remains part of the envelope's vocabulary, but no route emits it today.

What "live" does and does not promise#

Live means the endpoint reads real data and refuses honestly when it cannot. It does not mean every property will return offers on day one. An offer is sellable only when four things are all true for every night of the stay:

  1. your code is mapped, and the property is switched on for you;
  2. inventory has been loaded and has enough rooms left;
  3. no stop-sell, CTA/CTD or length-of-stay rule blocks it;
  4. a rate exists for you on that date.

When one fails, the offer comes back with sellable: false and a reason naming which. It is never dropped silently and a price is never invented to fill a gap — so no_rate on every offer means "talk to Staylah", and no_inventory means the hotel is genuinely full. Those need completely different follow-up, which is why they are different strings.

Two of those reasons are Staylah-side data gaps, not full hotels. inventory_not_loaded means nobody has loaded a calendar for that date, and no_rate means no rate has been loaded for your partner account. Both read as "unavailable" from the outside and neither is something you can fix. During onboarding, expect them — and report them rather than retrying.

Live endpoints need your codes mapped first#

The reservations endpoints translate your codes into Staylah properties, room types and rate plans. Until Staylah has recorded that mapping for your account, a delivery is accepted and stored — it is never lost — but it does not become a live booking:

json
{
  "success": true,
  "data": {
    "intake_state": "unmapped",
    "staylah_booking_id": null,
    "needs_reconciliation": true,
    "warnings": [
      { "code": "unknown_code", "message": "…No mapping exists for the code \"TAN-KL-77\"." }
    ]
  },
  "request_id": "…"
}

So: watch data.intake_state, and treat anything other than "mapped" as an integration alert. During onboarding, send one reservation per property and check the response before switching your live feed on. Staylah's side of this is managed at Connectivity → Code mappings in the admin.