Pattern: read and update prices
Developers (API)REST API v1
This pattern keeps the daily prices in Effective Tours in line with the prices in your PMS. It is for distributor companies: only a distributor may write prices. Read the other principles in Integration patterns, and map your rooms and rates first with Pattern: map rooms and rates.
Write calls are real. There is no sandbox: a price you write is saved immediately, can reach the connected channels, and cannot be undone through the API. The only "undo" is to write the previous price again. Test on dates far in the future, and connect OTAs only after the integration works.
Steps
1. Find the rate to price
You need the rate id. If you stored it in your mapping table, skip this step. See GET /hotels/{id}/rates. Here {id} is the hotel id.
curl "https://api.effectivetours.com/v1/hotels/{id}/rates" \
-H "Authorization: Bearer $ET_API_KEY"Example response (abbreviated: one rate shown):
[
{
"id": 3001,
"name": "Standard rate",
"food": "RO",
"sgl": false,
"dbl": true,
"tpl": false,
"full": false,
"connections": {}
}
]2. Read the current prices
Read before you write, so you know what is there. GET .../prices takes no date parameters and returns every day held, not sorted: filter and sort on your side. For a distributor key the buy prices are null. See GET prices.
curl "https://api.effectivetours.com/v1/hotels/{id}/rates/{rate_id}/prices" \
-H "Authorization: Bearer $ET_API_KEY"Example response (abbreviated: one day shown):
[
{
"date": "2027-03-01",
"sgl_buy": null,
"sgl_sell": null,
"dbl_buy": null,
"dbl_sell": "120.00",
"tpl_buy": null,
"tpl_sell": null,
"full_buy": null,
"full_sell": null
}
]3. Write the new prices
Send a JSON array with one object per date. Each object has date and the prices sgl, dbl, tpl and full. Prices for occupancies that the rate does not support are set to null automatically. Entries are created or updated per date. See POST prices.
Request body and call:
curl "https://api.effectivetours.com/v1/hotels/{id}/rates/{rate_id}/prices" \
-X POST \
-H "Authorization: Bearer $ET_API_KEY" \
-H "Content-Type: application/json" \
-d '[{"date": "2027-03-01", "sgl": null, "dbl": "125.00", "tpl": null, "full": null}, {"date": "2027-03-02", "sgl": null, "dbl": "125.00", "tpl": null, "full": null}]'Example response (same format as the GET; abbreviated):
[
{
"date": "2027-03-01",
"sgl_buy": null,
"sgl_sell": null,
"dbl_buy": null,
"dbl_sell": "125.00",
"tpl_buy": null,
"tpl_sell": null,
"full_buy": null,
"full_sell": null
}
]4. Read the prices again
Do not trust the write answer alone. Read the prices again and compare the dates you sent with what is held. If a value differs, send the write again for that date. Use the same call as step 2.
curl "https://api.effectivetours.com/v1/hotels/{id}/rates/{rate_id}/prices" \
-H "Authorization: Bearer $ET_API_KEY"Example response (abbreviated):
[
{
"date": "2027-03-02",
"sgl_buy": null,
"sgl_sell": null,
"dbl_buy": null,
"dbl_sell": "125.00",
"tpl_buy": null,
"tpl_sell": null,
"full_buy": null,
"full_sell": null
}
]5. Ask for a channel update
To send the new dates to the connected channels, call POST /hotels/{hotel_id}/ota-update. It asks Effective Tours to send the dates to the channels. It only enqueues per-channel jobs: whether a channel accepts the push is decided later and is not in the response. end_date and channel_id are optional; channel_id is one of agoda, booking, expedia, airbnb, and start_date must be today or later. See POST ota-update.
curl "https://api.effectivetours.com/v1/hotels/{hotel_id}/ota-update" \
-X POST \
-H "Authorization: Bearer $ET_API_KEY" \
-H "Content-Type: application/json" \
-d '{"start_date": "2027-03-01", "end_date": "2027-03-02"}'Example response:
{
"success": true,
"ota_push": {
"sent": true,
"status": "success",
"message": null,
"reason": null,
"note": "OTA channels are updated asynchronously; per-channel results are not available in this response"
}
}success is true on any well-formed request. Look at ota_push: sent says whether the request reached the channel service, and reason (not_configured, http_error, timeout or invalid_response) says why nothing was sent. The note is always present: it says that per-channel results are not available in this response.
Related method pages: Daily prices and Channel update.
What can go wrong
| Status | Body | What to do |
|---|---|---|
| 403 | {"detail":"You are not allowed to access this hotel"} | Your key has no write access to this hotel, or your company is not a distributor (prices) or distributor/hotelier (ota-update). Check company_type with /auth/me. |
| 404 | {"detail":"Hotel not found"} | The hotel or the rate is not found, or not accessible to you. Re-read the lists. |
| 410 | {"detail":"Requested HotelID: <id> not found."} | The hotel was permanently removed. Remove it from your mapping. |
| 422 | standard validation error | A bad date, an unknown channel_id, or a start_date in the past. Fix the body and send again. |
| 401 | {"detail":"Invalid API key"} | Check the key. |
| 503 | {"detail":"Authentication backend unavailable"} | Back off. Reads can be retried. For a price write, re-read first, then repeat the write only for the dates that did not change. |
| 429 | not specified | There is no published rate limit. Back off and slow down. |
200 with "sent": false | ota_push.reason is set | Nothing was sent to the channels. Try again later, and contact us if not_configured stays. |