# Guide to Hostaway Webhooks: Features and Best Practices

Hostaway webhooks push changes in your vacation rental business to the systems around it. A booking comes in from any channel, a reservation's dates or price change, a guest sends a message, or a cleaning task is created or updated, and Hostaway calls your endpoint so your smart-lock, messaging, accounting or operations software can react without polling the API.

This guide covers Hostaway's unified webhooks, the events they send, how to protect them with HTTP Basic credentials, how Hostaway retries and disables failing webhooks, and the practices that keep a receiver dependable.

## What are Hostaway webhooks?

Hostaway's current webhook system is the **unified webhook**. You configure one or more endpoints, choose the events each one should receive, and Hostaway calls them when something changes. Before April 2022, Hostaway had separate reservation and guest message webhooks. Those still work, but they are scheduled to be removed in 2027, and if you have both old and unified webhooks configured, Hostaway triggers both.

Hostaway doesn't sign webhook requests. Each webhook can have an optional login and password; when both are set, Hostaway sends them as an HTTP Basic `Authorization` header. Hostaway also publishes the three IP addresses its webhooks come from.

## Hostaway webhook features

| Feature | Details |
| --- | --- |
| Configuration | **Settings** > **Integrations** (admin account owner), or the API |
| Events | `reservation.created`, `reservation.updated`, `message.received`, `task.created`, `task.updated` |
| Filters | Events (at least one), plus optional listings and channels |
| URL rules | HTTP or HTTPS, port 80 or 443, not an internal network |
| Authentication | Optional login and password, sent as HTTP Basic |
| Signature and timestamp | None |
| HTTP method and body format | Not documented |
| Response window | 20 seconds |
| Retries | Transient failures (connection errors, `5xx`, `429`) up to 3 times within about an hour |
| Not retried | Other `4xx` responses, such as `400`, `401`, `403` or `404` |
| Failure alerts | Email to a configured address, or to the account owner |
| Auto-disable | A webhook failing for 5 consecutive days may be disabled |
| Ordering and duplicates | Events can arrive out of order and more than once |
| Source IPs | `52.37.159.97`, `52.32.104.6`, `54.212.209.218` |

## Events

| Event | Fires when |
| --- | --- |
| `reservation.created` | A reservation is created in Hostaway, from any channel |
| `reservation.updated` | Key details of a reservation change |
| `message.received` | A guest sends a message. Host messages don't trigger it |
| `task.created` | A task is created |
| `task.updated` | A task is updated |

`reservation.updated` covers status, dates, listing, total price, payment status and door code changes, as well as changes to the cancellation policy, custom fees (upsells, late check-out or damage charges), Booking.com cancellation fees and Booking.com no-show reports. Owner stays are the exception: you only get a webhook when an owner stay is created or cancelled.

Hostaway's two pages disagree on filtering. The help article says unified webhooks only trigger for the events you select. The API documentation says Hostaway "will not filter events for you" and asks you to filter on your side and handle new events as they're added. Filter in your receiver either way, and return a `200` for any event you don't handle.

Hostaway doesn't document the unified webhook payload field by field, and it notes that complex fields that arrive later may be missing when the webhook fires. Use the webhook as a trigger and fetch the full reservation, conversation or task from the API when you need details.

> **Inspect Hostaway webhooks as they arrive.** Point a unified webhook at a [Hookdeck Inspect](https://inspect.hookdeck.com) URL and make a test direct booking to see the method, headers and body Hostaway sends, with no account or setup required.

## Setting up Hostaway webhooks

Choose a login and a long random password first, for example with `openssl rand -hex 32` for the password.

1. Log in to the Hostaway Dashboard as the admin account owner.
2. Go to **Settings** > **Integrations** and add a webhook.
3. Enter your endpoint URL. Use HTTPS on the default port.
4. Select the events this webhook should receive. At least one is required.
5. Optionally limit it to certain listings and channels.
6. Enter the login and password. Hostaway only sends a Basic header if both are set.
7. Save, then make a test direct booking under **Reservations** to trigger a delivery.

Hostaway's help article says a booking can take 5 to 10 minutes to reach a third party. The webhook section of **Settings** > **Integrations** keeps delivery logs that you can export as CSV, with the response status your endpoint returned.

**With Hookdeck.** Hostaway is a supported source in Hookdeck. Its setup note reads: "Set a login and password on the Hostaway webhook. Webhooks without them send nothing to verify." Create a source with the **Hostaway** type, enter the same **Username** and **Password**, and use the source URL as the webhook URL. Hookdeck never answers with a `401` challenge, so the credentials have to arrive with each request; Hostaway's API documentation says it sends the Basic header whenever both are set.

Hostaway doesn't document the HTTP method, so the source pre-selects `POST` without managing it. After your test booking, look at the request in Hookdeck. If its method isn't `POST`, allow that method on the source as well, or requests with it won't be accepted. A request with missing or wrong credentials still gets a `200` from Hookdeck, but Hookdeck marks it as failed verification and doesn't deliver it to your service.

For local development, `hookdeck listen 3000 hostaway --path /webhooks/hostaway` gives you a public URL that forwards to your machine.

## Securing Hostaway webhooks

Decode the Basic header, split on the first colon, and compare the username and password with your stored values in constant time. Check credentials before you read the body, whatever the method.

```javascript
const crypto = require('crypto');
const express = require('express');

const USERNAME = process.env.HOSTAWAY_WEBHOOK_USERNAME;
const PASSWORD = process.env.HOSTAWAY_WEBHOOK_PASSWORD;

function safeEqual(a, b) {
  // timingSafeEqual throws on unequal lengths, so check first.
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}

function verifyBasicAuth(header) {
  if (!USERNAME || !PASSWORD || typeof header !== 'string') return false;
  const match = /^basic\s+([A-Za-z0-9+/]+={0,2})\s*$/i.exec(header);
  if (!match) return false;
  const decoded = Buffer.from(match[1], 'base64');
  const colon = decoded.indexOf(0x3a); // split on the first colon
  if (colon === -1) return false;
  const userOk = safeEqual(decoded.subarray(0, colon), Buffer.from(USERNAME, 'utf8'));
  const passOk = safeEqual(decoded.subarray(colon + 1), Buffer.from(PASSWORD, 'utf8'));
  return userOk && passOk;
}

const app = express();

// The method isn't documented, so accept any and check credentials first.
app.all('/webhooks/hostaway', express.raw({ type: '*/*' }), (req, res) => {
  if (!verifyBasicAuth(req.get('authorization'))) {
    return res.sendStatus(401);
  }

  // Store req.body and process it in a background job.
  res.sendStatus(200);
});

```

The same check in Python:

```python
import base64
import binascii
import hmac
import os

USERNAME = os.environ.get("HOSTAWAY_WEBHOOK_USERNAME", "")
PASSWORD = os.environ.get("HOSTAWAY_WEBHOOK_PASSWORD", "")

def verify_basic_auth(header) -> bool:
    if not USERNAME or not PASSWORD or not header:
        return False
    scheme, _, encoded = header.partition(" ")
    if scheme.lower() != "basic":
        return False
    try:
        decoded = base64.b64decode(encoded.strip(), validate=True)
    except (binascii.Error, ValueError):
        return False
    user, sep, password = decoded.partition(b":")
    if not sep:
        return False
    user_ok = hmac.compare_digest(user, USERNAME.encode("utf-8"))
    pass_ok = hmac.compare_digest(password, PASSWORD.encode("utf-8"))
    return user_ok and pass_ok

```

Basic credentials are static. They authenticate the sender, not the body, so a modified payload still passes, and with no timestamp a captured request can be replayed. Hostaway still allows plain HTTP, so make sure your URL uses HTTPS: over HTTP the credentials travel in the clear. For a second layer, allow only Hostaway's three published IP addresses.

> **Make Hostaway webhooks production-ready.** [Hookdeck Event Gateway](/event-gateway) checks the Basic credentials, answers Hostaway within its 20-second window, and keeps every reservation and message event so a failing service doesn't get your webhook disabled.

## Hostaway webhook limitations and pain points

### A 4xx ends delivery

**The Problem:** Returning `404` for a reservation you haven't seen yet loses that event.

**Why It Happens:** Hostaway treats `4xx` responses other than `429` as permanent and doesn't retry them. Its API documentation also says events can arrive out of order, for example a message before the reservation it belongs to, and suggests returning an error so the delivery is retried later.

**Workarounds:**

* Return a `5xx` or `429`, not a `4xx`, when you want Hostaway to retry.
* Better still, accept every authenticated event and resolve ordering in your own queue.

**How Hookdeck Can Help:** Hookdeck accepts each event as it arrives, and your service's responses only affect Hookdeck's delivery to you. If your service returns an error because a dependency hasn't landed yet, Hookdeck [retries](/docs/retries) on the schedule you set.

### Three retries in an hour, then disabling

**The Problem:** An outage of more than an hour loses events, and a longer one can switch the webhook off.

**Why It Happens:** Hostaway retries transient failures up to 3 times within roughly an hour, then emails an alert. A webhook that fails for 5 consecutive days may be disabled.

**Workarounds:**

* Set an alerting email address on the webhook so failures reach someone who can act.
* After an outage, use the exported delivery logs to find the affected reservations and fetch them from the API.

**How Hookdeck Can Help:** Hookdeck answers Hostaway as soon as the request is stored, so Hostaway sees successful deliveries even while your service is down. You then replay events to your service once it recovers.

### Undocumented method and payload

**The Problem:** You can't write a strict parser, or a strict route, from the docs alone.

**Why It Happens:** Hostaway documents the events and the Basic credentials, but not the HTTP method or the unified webhook body.

**Workarounds:**

* Capture a test booking in a request inspector before you write the handler.
* Treat the webhook as a notification and read details from the API.

**How Hookdeck Can Help:** Hookdeck stores every request with its method, headers and body, so you can replay a captured booking against your handler as often as you need.

### Old and new webhooks both fire

**The Problem:** During a migration, the same reservation change arrives twice, in two different formats.

**Why It Happens:** Hostaway triggers both the legacy webhooks and the unified webhook when both are configured.

**Workarounds:**

* Point the legacy and unified webhooks at different paths, and switch off the legacy ones once your unified handler is live.

**How Hookdeck Can Help:** With a source per webhook, Hookdeck [filters](/docs/filters) can drop or route one stream while you migrate.

## Best practices

### Always set both login and password

Without both, Hostaway sends no `Authorization` header, and neither your receiver nor Hookdeck has anything to check.

### Deduplicate deliveries

Hostaway says you can receive more than one notification for the same update. Once you've captured a real payload, build a key from the event name, the object's ID and a field that changes with each real update, and skip repeats. See our [guide to webhook idempotency](/webhooks/guides/implement-webhook-idempotency).

### Acknowledge fast and process asynchronously

Hostaway expects an answer within 20 seconds and suggests logging the request, returning `200` and processing later. See [why to process webhooks asynchronously](/webhooks/guides/why-implement-asynchronous-processing-webhooks).

### Expect new events

Hostaway adds events over time and asks receivers to return `200` for any event they don't support yet. Log unknown events instead of rejecting them.

## Conclusion

Hostaway's unified webhooks report reservations, guest messages and tasks, with an optional login and password sent as HTTP Basic and no signature. Set both credentials, use HTTPS, compare them in constant time, filter and deduplicate in your receiver, and never answer with a `4xx` you want retried, because Hostaway gives up on those and allows only three retries for anything else.

[Hookdeck Event Gateway](https://hookdeck.com) checks the credentials, answers Hostaway straight away, and retries and replays delivery to your service, so your webhook stays healthy while you fix what's behind it.

[Get started with Hookdeck](https://dashboard.hookdeck.com/signup) for free and handle Hostaway webhooks reliably in minutes.