If your hotel runs a custom-built system, or a PMS or booking engine that WeSpeak doesn't integrate yet, you can connect it through an API. Your tech team publishes two endpoints in the WeSpeak format and, from then on, the assistant checks prices and availability live in your system and loads the reservations closed in the chat into it.
ℹ️ This is not the same as WeSpeak Rates without a PMS or a Channel Manager: there, WeSpeak is your system. Here, your system stays in charge and WeSpeak queries it.
In this article
- What you need
- How to connect, step by step
- The contract: availability (GET)
- The contract: reservations (POST)
- Before you open sales
- What it doesn't do
- Common errors
- Frequently asked questions
What you need
| What | Required? | What it's for |
|---|---|---|
| An availability and prices GET endpoint, over HTTPS and reachable from the internet | ✅ Yes | The assistant quotes with your system's data |
| A reservation creation POST endpoint | Only to book | The chat reservation goes into your system. Requires WeSpeak Payments |
| An API key | Recommended | Your system knows the call comes from WeSpeak. It arrives in the X-API-Key header |
| Your rooms loaded in WeSpeak, with the same name your system returns | ✅ Yes | WeSpeak joins your prices with each room's photos, descriptions and capacities |
💡 If your PMS or Channel Manager is already integrated with WeSpeak, you don't need this: ask your advisor for the native connection. See Get to Know WeSpeak Rates.
How to connect, step by step
- Ask your advisor to activate it. The WeSpeak team turns on the Custom integration for your property and the section appears in your dashboard.
- Enter your endpoints in Settings → Custom integration: the availability URL, the reservations URL and the API key. Each field saves itself when you leave it.
- Test from the same screen. Test availability calls your endpoint live and flags, field by field, what doesn't match the format. Test reservation creation sends a test reservation that your system must not create.
- Run a real quote in the chat and compare the prices with your system's.
- Validate reservations with the checklist in Before you open sales.
On the same screen, View expected format shows the contract with examples: it's the same one as in this article.
🛠️ Technical questions about the contract? Your development team can write directly to ours at tecnologia@wespeak.pro.
The contract: availability (GET)
Every time the assistant needs to quote, WeSpeak calls your URL adding these parameters:
GET https://api.yourhotel.com/wespeak/availability?channel=custom&username=your-hotel&channelPass=&checkinDate=2026-11-10&checkoutDate=2026-11-12¤cy=USD&persons=2&adults=2&kids=1&childrenAge=8 X-API-Key: your-api-key
| Parameter | What it is |
|---|---|
checkinDate, checkoutDate | Stay dates, in YYYY-MM-DD format |
adults, kids | Number of adults and children |
childrenAge | Children's ages separated by commas (4,8). Only sent when there are children |
currency | Currency the guest asked for, 3-letter ISO code |
username | Your property's identifier, agreed with your advisor. Useful when one endpoint serves several hotels |
persons, channel, channelPass | Sent for compatibility; you can ignore them. persons repeats the number of adults |
Your endpoint responds with this JSON:
{
"available": true,
"rooms": [
{
"name": "Superior Double",
"code": "DBL",
"currency": "USD",
"bookable": true,
"unitsLeft": 3,
"minStay": 2,
"maxStay": 14,
"rates": [
{ "name": "Flexible Rate", "code": "FLEX", "totalPrice": "300.00" },
{ "name": "Non-refundable", "code": "NR", "totalPrice": "260.00" }
]
}
]
}
| Field | Required? | Rule |
|---|---|---|
available | ✅ | true if at least one room can be booked for those dates |
rooms[].name | ✅ | Same as the room's name in WeSpeak. Not case-sensitive, but the text must match: "Superior Double" is not "Superior" |
rooms[].currency | ✅ | 3-letter ISO code. Use the same currency for every room |
rooms[].rates[].totalPrice | ✅ | Total price for the whole stay in that room, not per night |
rooms[].code, rates[].code | To book | Stable codes from your system. We send them back as-is when creating the reservation |
rooms[].bookable, unitsLeft | Recommended | Whether it can be booked and how many units are left |
minStay, maxStay | Optional | Minimum and maximum nights, for information |
Rules worth following from day one:
- "No availability" is not an error. Respond
200withavailable: false. Keep4xxand5xxcodes for real failures, such as an invalid key or your system being down. - Apply your restrictions to the requested dates. If a room can't be booked, return it with
bookable: falseinstead of leaving it out. If none can be booked, respondavailable: false. - Respond in your system's currency. If the guest asked for another one, WeSpeak converts the price.
- The price must match the requested occupancy, children included.
- Only return the rates you want to sell in the chat. The assistant offers every rate in
rates, and the guest seesrates[].name: if two rates differ in refundability or payment terms, the name should say so, for example "Non-refundable" or "Flexible, pay at the hotel". - Each rate must accept the payment setup you configured in WeSpeak Payments. If a rate requires full prepayment and the hotel charges a deposit or payment at the hotel, the reservation will fail.
- Every query is live. We don't cache, and before charging we query again to confirm price and availability. If a query fails, we retry it.
- Respond fast. Ideally under 5 seconds. The dashboard test times out at 15.
- Always return valid JSON. If your endpoint fails or returns another format, the assistant stops quoting and alerts the WeSpeak team, so the guest doesn't get a wrong price.
- Let WeSpeak's calls through. If you use Cloudflare or another firewall with bot blocking, exempt these routes: WeSpeak calls from servers, not from a browser.
The contract: reservations (POST)
When the guest confirms the reservation with WeSpeak Payments, whether by online payment, bank transfer or paying at the hotel, WeSpeak sends the reservation to your URL:
{
"weSpeakReservationId": "8f2c1a7e-4b1d-4c55-9a51-2f6c0d9e1b3a",
"username": "your-hotel",
"checkinDate": "2026-11-10",
"checkoutDate": "2026-11-12",
"currency": "USD",
"currencyConversion": null,
"rooms": [
{
"name": "Superior Double",
"code": "DBL",
"rateName": "Flexible Rate",
"rateCode": "FLEX",
"adults": 2,
"kids": 1,
"kidAges": [8],
"priceAmount": "300.00"
}
],
"totalPrice": 300,
"amountPaid": 90,
"amountToPay": 210,
"depositAmount": 90,
"paymentMethod": "...",
"paymentDetails": {
"orderId": "...",
"gateway": { "name": "..." }
},
"customerName": "Ana",
"customerSurname": "Pérez",
"customerEmail": "ana@example.com",
"customerPhone": "+5491100000000",
"customerCountry": "AR",
"reservationNote": "Arriving late, around 11 pm"
}
Your endpoint responds:
{
"success": true,
"reservationId": "ABC123",
"status": "confirmed",
"message": "Reservation created"
}
POST rules:
- Each element of
roomsis one room. A two-room reservation has two elements, each with its occupancy and itspriceAmount. - Ignore the fields you don't use. The body may gain new fields over time: don't reject the reservation because of a field you don't know.
- Codes come back as-is.
rooms[].name,code,rateNameandrateCodeare the ones your system returned in the GET. If you didn't send a code, it arrives asnull. - The
codeis the identifier. Everything your system needs to book, such as a promotion, must be derivable from the room and ratecode. The name travels as a reference. - Don't duplicate reservations. If your endpoint doesn't respond or responds with an HTTP error, we retry once with the same
weSpeakReservationId. If that id already exists in your system, return the reservation you already created instead of creating another one. A rejection must also repeat the same way, and the same id with different data is rejected. - Test mode. If the body includes
"isTest": true, validate the format and respond as usual, but don't create the reservation. The dashboard's test button uses it. - Take the inventory at that moment. Two guests can pay for the last room almost at the same time: your system must accept only one reservation.
- If the reservation was created, respond
success: true, even if something secondary fails, such as recording the payment in your system. Solve that step on your side. - To reject, respond
200withsuccess: falseand amessageexplaining why, for example that the price changed or there's no more availability. The reservation stays in WeSpeak's Reservations as not synced, so your team can handle it. - If you don't know whether the reservation was created, don't respond
success: true. Respondsuccess: falseexplaining it and write to us at tecnologia@wespeak.pro, so it's reviewed before anyone loads it by hand and duplicates it. reservationIdis the reservation number in your system. We store it so your team can find it.
Amounts and currency:
rooms[].priceAmountis the total for the stay in that room, in thecurrencycurrency.totalPrice,amountPaid,amountToPayanddepositAmountare in the currency the guest paid in. If it differs fromcurrency,currencyConversioncarries that currency and the rate, for example{ "currency": "ARS", "conversionRate": 1450 }. To convert those amounts to thecurrencycurrency, divide them by the rate.amountPaid + amountToPay = totalPrice.amountPaidis what was charged in the chat andamountToPaywhat the hotel collects under its policy.depositAmountis the deposit the policy asks for, not what was charged.- Taxes: the sum of
priceAmountmatchestotalPricewhen there was no conversion and your prices already include taxes. If taxes that add to the price are configured in WeSpeak,totalPriceincludes them andpriceAmountdoesn't. The simplest setup is to return final prices and not add taxes in WeSpeak. paymentDetailscarries the payment gateway references and is empty when nothing was charged online. IfpaymentDetails.gateway.nameisZru Token, it's a card guarantee: nothing has been charged yet, even ifamountPaidhas an amount.
Before you open sales
This is how we validated with the partners who are already connected. It's best to start with your test environment URLs and a test property, and switch to the production URLs at the end:
- Availability: dates with availability, dates without it, with children and for a large group.
- Security: an invalid key and another property's
username, which your endpoint rejects with401or403. - A new reservation, the same request sent again, which must return the same reservation, and the same id with different data, which must be rejected.
- A price that changed or availability that ran out between the quote and the payment: your system rejects it with a clear reason.
- A multi-room reservation, with full payment, with a deposit and without payment.
- The last unit: two simultaneous reservations, and only one is confirmed.
- Cleanup: cancel the test reservations, because they take up inventory.
- One controlled reservation in production on a single property, which you cancel afterwards, before opening sales on the rest.
What it doesn't do
- It doesn't send changes or cancellations. If a reservation changes in WeSpeak, your team updates it in your system by hand.
- It doesn't write prices or availability into your system. It only reads them and, when booking, sends the reservation.
- It doesn't bring photos or descriptions. Those are loaded once in WeSpeak, on each room. Your endpoint only provides what changes: price, availability and whether it can be booked.
Common errors
| Symptom | Most common cause | What to do |
|---|---|---|
Your endpoint responds 401 even though the key is correct | Many hosting providers drop the Authorization header before it reaches your code | Read the key from the X-API-Key header, which is the one WeSpeak sends |
| The test passes but the assistant doesn't show a room | The name doesn't match the one in WeSpeak | Use the room's WeSpeak name in rooms[].name |
| Prices come out much lower than on your website | Your endpoint returns the price per night | Return the total for the stay in totalPrice |
| Two identical reservations were created | Your endpoint doesn't deduplicate | Look up the weSpeakReservationId before creating |
| Reservations paid in another currency don't match your system | totalPrice and the paid amounts come in the payment currency | Use currencyConversion to convert them to your currency |
| Some rates always fail when booking | The rate requires a payment different from what WeSpeak Payments charges | Align the rate's policy with the payment setup, or don't return it |
| The guest sees several rates with the same name | rates[].name carries a promotion's name instead of the plan's | Use names that distinguish refundability and payment terms |
| The test says the endpoint didn't respond in time | Your system takes more than 15 seconds | Optimize the query or add a cache |
| You can't enter the reservations URL | Your account doesn't have WeSpeak Payments | Ask your advisor to activate it |
Frequently asked questions
Do I need WeSpeak Payments to quote?
No. Payments is only needed for the reservation to go into your system. Without it, the assistant quotes with your prices and your team loads the reservations.
Does it work for several properties?
Yes. Each property has its own configuration, and the username parameter tells your endpoint which hotel it is.
Can I use WeSpeak Rates on top?
Yes. Availability comes from your endpoint and the rates you create in Rates are applied on top. For that you need the room and rate code values.
What happens if my system goes down?
The assistant stops quoting and alerts the WeSpeak team, so the guest doesn't get a wrong price. When your endpoint responds again, everything carries on as before.
Do I need to send you availability or change notifications?
No. We query your endpoint live every time, and the only thing we send is the reservation.
How do I share the API key?
Don't send it by email: you enter it yourself in Settings → Custom integration and it's never shown again.
Can I use HTTP or an internal IP?
No. Only HTTPS URLs reachable from the internet are accepted.
Who do I contact if something doesn't work?
For technical questions about the contract or your endpoints, our development team: tecnologia@wespeak.pro. To activate the integration or WeSpeak Payments, your advisor.