Pattern: reservation sync
Developers (API)REST API v1
This pattern copies the reservations held in Effective Tours (including those that come from Booking.com, Expedia, Agoda, Airbnb and other connected channels) into your PMS, and keeps the copy current. You need it if your PMS must show every booking of a property. The principles are in Integration patterns. All calls here are reads, so they are safe at any time.
There is no push or webhook feed, no "changed since" filter and no pagination. You poll, you compare with your copy, and you decide what changed. Poll a property no more often than every 2-5 minutes, and keep the date window to what you need. There is no published rate limit; back off on 429 and 503.
Steps
1. List the reservations in a window
Always send both start and end. Without start the list holds stays that end after today, and without end there is no upper bound; the list has no pagination and no cap, so a wide window can be very large. A stay is included when its check-out is after start and its check-in is before end. Use windows (for example, 30 days at a time) and move the window forward. full=true adds guest details, price, revenue, comment and reference_code. See GET /hotels/{hotel_id}/reservations.
curl "https://api.effectivetours.com/v1/hotels/{hotel_id}/reservations?full=true&start=2027-03-01&end=2027-03-31" \
-H "Authorization: Bearer $ET_API_KEY"Example response (abbreviated: one reservation shown, and not every field):
[
{
"id": 4001,
"checkin": "2027-03-10",
"checkout": "2027-03-12",
"is_accepted": true,
"adults": 2,
"children": 0,
"is_fake": false,
"room": {
"id": 2001,
"name": "Double Room 1",
"sgl": false,
"dbl": true,
"tpl": false,
"apartment": false,
"is_virtual": false
},
"rate": {
"id": 3001,
"name": "Standard rate",
"food": "RO"
},
"channel": null,
"first_name": "Jane",
"last_name": "Example",
"price": "250.00",
"revenue": null,
"comment": "",
"reference_code": "PMS-2027-0001",
"client": {
"id": 7001,
"name": "Jane Example",
"first_name": "Jane",
"last_name": "Example",
"email": "[email protected]",
"phone": ""
}
}
]Guest data depends on who you are. A hotel owner sees guest data on every reservation. An agent or distributor company sees it only on reservations it created. On all others first_name, last_name and client are null and comment is "". Without full=true the list carries no guest data for any caller.
2. Read the cancelled channel bookings
A cancelled channel booking leaves the reservations list, so read the cancelled list too. It answers with a bookings array. The start and end filter returns bookings where checkin < end and checkout > start. Without dates it returns bookings where checkout is today or later. The guest fields are empty for a company that does not own the hotel. See GET /hotels/{hotel_id}/bookings/cancelled.
curl "https://api.effectivetours.com/v1/hotels/{hotel_id}/bookings/cancelled?start=2027-03-01&end=2027-03-31" \
-H "Authorization: Bearer $ET_API_KEY"Example response (abbreviated: one booking shown, and not every field):
{
"bookings": [
{
"channel": "booking",
"channel_id": "5550001",
"rate_plan_id": null,
"room_type": "Double Room",
"checkin": "2027-03-20",
"checkout": "2027-03-22",
"room_count": 1,
"adults": 2,
"children": 0,
"currency": "EUR",
"price": "240.00"
}
]
}An empty bookings list is a normal answer.
3. Reconcile with your copy
Compare each item with the rows you already hold:
- A reservation
idyou have not seen is a new booking. Insert it. - An
idyou hold with changed dates, room, rate, head count oris_acceptedis a modification. Update your row. - If you wrote the reservation yourself, its
reference_codeis thereferenceyou sent at create time. Match on it so you do not import your own booking twice. - A booking in the cancelled list marks the matching reservation in your copy as cancelled. Match it on the channel booking id (
channel_id) together with the dates. - A reservation you hold that is missing from the window may have been cancelled, or may be outside the window. Read it by id before you delete anything:
GET /hotels/{hotel_id}/reservations/{id}.
Related method page: Reservations.
4. Run it on a schedule
Run the window loop every 2-5 minutes per property. Store the time of the last successful run, and if a run fails, repeat the same window, not a later one. Starting a window a few days before today is cheap insurance for late changes.
What can go wrong
| Status | Body | What to do |
|---|---|---|
| 404 | {"detail":"Hotel not found"} | The hotel id is wrong, or your key has no access. |
| 404 | {"detail":"Reservation not found"} | When you read one reservation by id: it does not exist, or it is not yours to see. |
| 410 | {"detail":"Requested HotelID: <id> not found."} | The hotel was permanently removed. Stop polling it. |
| 401 | {"detail":"Invalid API key"} | Check the key. |
| 503 | {"detail":"Authentication backend unavailable"} | Retry the same window after a growing pause. |
| 429 | not specified | There is no published rate limit. Back off and poll less often. |
| 422 | standard validation error | A date is not YYYY-MM-DD, or start is after end on the cancelled list. Fix the query. |
200 with [] | [] | Normal. No reservation in this window. |