Agent skill

Hostaway Webhooks Skill

Receive and authenticate Hostaway webhooks. Use when setting up a Hostaway (vacation rental software) webhook endpoint, verifying the HTTP Basic auth login and password, debugging 401s, or handling events like reservation.created, reservation.updated, message.received, task.created and task.updated.

Install this skill

npx skills add hookdeck/webhook-skills --skill hostaway-webhooks


Hostaway sends a webhook when something changes in your account: a reservation is created or updated, a guest message arrives, a task changes. Webhooks are not signed. If you set a login and password on the webhook (Settings > Integrations, unified webhook, or the legacy reservation and message webhooks), Hostaway sends them as HTTP Basic auth, and your endpoint authenticates the request by checking the Authorization header.

Set a login and password on the Hostaway webhook. Webhooks without them send nothing to verify.

When to Use This Skill

  • How do I receive Hostaway webhooks?
  • How do I verify a Hostaway webhook? (HTTP Basic auth, there is no signature)
  • Why does my Hostaway webhook endpoint return 401?
  • How do I handle reservation.created, reservation.updated or message.received events?
  • Which HTTP method does Hostaway use for webhooks?

Verification (core)

const crypto = require('crypto');

const sha = (s) => crypto.createHash('sha256').update(s).digest(); // equal-length buffers
const safeEqual = (a, b) => crypto.timingSafeEqual(sha(a), sha(b));

function verifyHostawayRequest(headers, user = process.env.HOSTAWAY_WEBHOOK_USERNAME,
                               pass = process.env.HOSTAWAY_WEBHOOK_PASSWORD) {
  if (!user || !pass) return false;                          // never accept when unconfigured
  const m = /^basic +([A-Za-z0-9+/]+={0,2})$/i.exec((headers.authorization || '').trim());
  if (!m) return false;                                      // scheme is case-insensitive
  const buf = Buffer.from(m[1], 'base64');
  if (buf.toString('base64') !== m[1]) return false;         // strict: no junk after valid base64
  const text = buf.toString('utf8');
  const i = text.indexOf(':');                               // split on the FIRST colon
  if (i === -1) return false;
  const userOk = safeEqual(text.slice(0, i), user);          // evaluate both, no short-circuit
  const passOk = safeEqual(text.slice(i + 1), pass);
  return userOk && passOk;
}
  • Header: Authorization: Basic base64(username:password), built from the login and password you set on the webhook. Both are optional in Hostaway; without them there is nothing to verify.
  • Missing or malformed header, or a mismatch: return 401. Check the credential first, for every HTTP method, before reading the body.
  • Compare the username and the password each in constant time. Node: crypto.timingSafeEqual on equal-length buffers (SHA-256 digests here). Python: hmac.compare_digest on bytes (encode both sides; str raises on non-ASCII). Decode strictly (validate=True in Python) so valid credentials followed by junk are rejected.
  • A static shared credential authenticates the sender, not the body. There is no signature and no timestamp, so it gives no replay protection. Use HTTPS only, and rotate the login and password in Hostaway if they leak.
  • Hookdeck never sends a 401 challenge (no WWW-Authenticate round trip), so the credentials must arrive with every request. Don't rely on the sender retrying with credentials after a challenge.
  • Read the body raw (express.raw({ type: '*/*' })) so any content type works, and parse it only after the check.

For complete handlers with tests, see examples/express/, examples/nextjs/, examples/fastapi/.

HTTP Methods and Body

Hostaway's docs don't name the HTTP method or the body format. The examples therefore accept GET, POST, PUT, PATCH and DELETE on the webhook route (Express app.all, a Next.js handler per method, FastAPI api_route), check the credential first for every method, and handle an empty body. Hookdeck's Hostaway source pre-selects POST without managing the method, so any other method the sender uses must also be allowed on the source.

Event Types

The unified webhook payload is not documented field by field, so treat the payload below as illustrative and read the event name defensively (event, eventType, or object + action), logging unknown shapes.

EventSent When
reservation.createdA reservation is created
reservation.updatedA reservation changes
message.receivedA guest message arrives
task.createdA task is created
task.updatedA task changes
{ "event": "reservation.created", "data": { "id": 1001, "listingMapId": 2002, "guestName": "Jane Doe", "status": "new" } }

Hostaway times out after 20 seconds and retries transient failures up to 3 times, so acknowledge quickly and process idempotently. Only ports 80 and 443 are reachable.

Environment Variables

HOSTAWAY_WEBHOOK_USERNAME=your-webhook-login      # the login you set on the Hostaway webhook
HOSTAWAY_WEBHOOK_PASSWORD=your-webhook-password   # the password you set on the Hostaway webhook

Local Development

Hostaway can't reach localhost. Tunnel with the Hookdeck CLI (no account required):

npx hookdeck-cli listen 3000 hostaway --path /webhooks/hostaway

Use the printed URL as the webhook URL in Hostaway.

Resources


Repository

hookdeck/webhook-skills

v0.1.0 · MIT · Updated Nov 10, 2026

View on GitHub →