StayBindDevelopers
Connect a custom OTA

Expose your API

The six HTTP endpoints your OTA serves so StayBind can health-check it, pull reservations, and push availability, rates, and restrictions to it.

StayBind addresses your OTA at a single base URL (your baseUrl credential) and authenticates every request with your apiKey as a bearer token:

Authorization: Bearer <your apiKey>
Content-Type: application/json

Implement these six endpoints under that base URL. Paths are relative to it (a trailing slash on the base URL is ignored).

Success and retry

Return any 2xx for success. A 5xx (or a network error) is treated as retryable, StayBind backs off and tries again, and the nightly full sync re-pushes anyway. A 4xx is treated as a permanent rejection (for example a bad mapping) and is surfaced to the operator rather than retried forever.

Lifecycle

GET /health

A liveness probe used when the connection is set up and during health checks. Return 200 when the credentials are valid; a non-2xx flips the connection to an unhealthy state and pauses outbound pushes.

GET /health
Authorization: Bearer <apiKey>

Inbound pull (reconcile backup)

GET /reservations?since=<ISO-8601>

Return reservations created or changed since the given instant, as a JSON array of your raw reservation objects. StayBind calls this on a schedule (~every 15 minutes) to catch any reservation whose webhook was missed. The objects are the same shape you post to the webhook, StayBind runs each through mapReservation.

GET /reservations?since=2026-02-19T00:00:00.000Z
Authorization: Bearer <apiKey>
Response (your raw shape)
[
  { "id": "R-1001", "status": "new", "roomTypeId": "deluxe", "checkIn": "2026-02-20", "checkOut": "2026-02-22", "guest": { "name": "Aarav Sharma" } }
]

Idempotency makes this safe: any reservation already ingested (matched by its id) is a no-op, so overlapping pull windows never duplicate a booking.

Outbound push (StayBind → you)

When a booking lands on any other channel, StayBind pushes the changed availability (and, where relevant, rates and restrictions) to these endpoints so your OTA mirrors the ledger. Apply each update as an upsert keyed by date, the latest value wins.

POST /listings

Sent when a unit/rate-plan mapping is established. The body is a ChannelListing.

POST /availability

Body
{
  "updates": [
    { "unitId": "unit_courtyard", "date": "2026-02-20", "available": 0 },
    { "unitId": "unit_courtyard", "date": "2026-02-21", "available": 0 }
  ]
}

available is the count of sellable units for that unit on that date (0 means blocked). See AvailabilityUpdate.

POST /rates

Body
{
  "updates": [
    { "ratePlanId": "rp_standard", "date": "2026-02-20", "amount": 750000, "currency": "INR" }
  ]
}

amount is integer paise. See RateUpdate.

POST /restrictions

Body
{
  "updates": [
    { "ratePlanId": "rp_standard", "date": "2026-02-20", "minStay": 2, "stopSell": false }
  ]
}

See Restriction.

Summary

Method · pathDirectionPurpose
GET /healthStayBind → youcredential / liveness check
GET /reservations?since=StayBind → youpull reservations (reconcile backup)
POST /listingsStayBind → youa unit/rate-plan mapping
POST /availabilityStayBind → youavailability changed for some dates
POST /ratesStayBind → yourate changed for some dates
POST /restrictionsStayBind → youstay rules changed for some dates

Next: how your OTA pushes reservations into StayBind, in Receive bookings.

On this page