Custom integration (your own API)

If your hotel runs its own system, connect it through an API: you expose two endpoints in the WeSpeak format, and the assistant quotes with your live prices and loads chat reservations into your system.

Last updated: October 6, 2026

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

WhatRequired?What it's for
An availability and prices GET endpoint, over HTTPS and reachable from the internet✅ YesThe assistant quotes with your system's data
A reservation creation POST endpointOnly to bookThe chat reservation goes into your system. Requires WeSpeak Payments
An API keyRecommendedYour 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✅ YesWeSpeak 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

  1. Ask your advisor to activate it. The WeSpeak team turns on the Custom integration for your property and the section appears in your dashboard.
  2. 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.
  3. 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.
  4. Run a real quote in the chat and compare the prices with your system's.
  5. 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&currency=USD&persons=2&adults=2&kids=1&childrenAge=8
X-API-Key: your-api-key
ParameterWhat it is
checkinDate, checkoutDateStay dates, in YYYY-MM-DD format
adults, kidsNumber of adults and children
childrenAgeChildren's ages separated by commas (4,8). Only sent when there are children
currencyCurrency the guest asked for, 3-letter ISO code
usernameYour property's identifier, agreed with your advisor. Useful when one endpoint serves several hotels
persons, channel, channelPassSent 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" }
      ]
    }
  ]
}
FieldRequired?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[].codeTo bookStable codes from your system. We send them back as-is when creating the reservation
rooms[].bookable, unitsLeftRecommendedWhether it can be booked and how many units are left
minStay, maxStayOptionalMinimum and maximum nights, for information

Rules worth following from day one:

  • "No availability" is not an error. Respond 200 with available: false. Keep 4xx and 5xx codes 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: false instead of leaving it out. If none can be booked, respond available: 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 sees rates[].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 rooms is one room. A two-room reservation has two elements, each with its occupancy and its priceAmount.
  • 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, rateName and rateCode are the ones your system returned in the GET. If you didn't send a code, it arrives as null.
  • The code is the identifier. Everything your system needs to book, such as a promotion, must be derivable from the room and rate code. 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 200 with success: false and a message explaining 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. Respond success: false explaining it and write to us at tecnologia@wespeak.pro, so it's reviewed before anyone loads it by hand and duplicates it.
  • reservationId is the reservation number in your system. We store it so your team can find it.

Amounts and currency:

  • rooms[].priceAmount is the total for the stay in that room, in the currency currency.
  • totalPrice, amountPaid, amountToPay and depositAmount are in the currency the guest paid in. If it differs from currency, currencyConversion carries that currency and the rate, for example { "currency": "ARS", "conversionRate": 1450 }. To convert those amounts to the currency currency, divide them by the rate.
  • amountPaid + amountToPay = totalPrice. amountPaid is what was charged in the chat and amountToPay what the hotel collects under its policy. depositAmount is the deposit the policy asks for, not what was charged.
  • Taxes: the sum of priceAmount matches totalPrice when there was no conversion and your prices already include taxes. If taxes that add to the price are configured in WeSpeak, totalPrice includes them and priceAmount doesn't. The simplest setup is to return final prices and not add taxes in WeSpeak.
  • paymentDetails carries the payment gateway references and is empty when nothing was charged online. If paymentDetails.gateway.name is Zru Token, it's a card guarantee: nothing has been charged yet, even if amountPaid has 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 with 401 or 403.
  • 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

SymptomMost common causeWhat to do
Your endpoint responds 401 even though the key is correctMany hosting providers drop the Authorization header before it reaches your codeRead the key from the X-API-Key header, which is the one WeSpeak sends
The test passes but the assistant doesn't show a roomThe name doesn't match the one in WeSpeakUse the room's WeSpeak name in rooms[].name
Prices come out much lower than on your websiteYour endpoint returns the price per nightReturn the total for the stay in totalPrice
Two identical reservations were createdYour endpoint doesn't deduplicateLook up the weSpeakReservationId before creating
Reservations paid in another currency don't match your systemtotalPrice and the paid amounts come in the payment currencyUse currencyConversion to convert them to your currency
Some rates always fail when bookingThe rate requires a payment different from what WeSpeak Payments chargesAlign the rate's policy with the payment setup, or don't return it
The guest sees several rates with the same namerates[].name carries a promotion's name instead of the plan'sUse names that distinguish refundability and payment terms
The test says the endpoint didn't respond in timeYour system takes more than 15 secondsOptimize the query or add a cache
You can't enter the reservations URLYour account doesn't have WeSpeak PaymentsAsk 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.