Skip to content
See how Guestalizer looks before you create an account

A preview filled with sample data. No account and no card needed.

Developers

API for developers

This guide is for a developer connecting an operator's own system to Guestalizer, for example a booking engine, a channel manager or an internal tool. With an API key you can add bookings (Guestalizer then creates the guest's verification and sends the secure link), change or cancel them, and read where each guest is with their checks.

Getting a key

  1. The account owner signs in to Guestalizer and opens Settings, then API.
  2. They choose Create a key, give it a name (for example "Booking engine") and tick what it may do.
  3. The key is shown once. Copy it into your system's secret store straight away. Guestalizer keeps only a fingerprint of it and cannot show it again.

Treat a key like a password. Never put it in a web page, a mobile app or a public code repository. If a key may have been seen by someone else, the owner revokes it in Settings, API and creates a new one: a revoked key stops working at once.

Each key belongs to one Guestalizer organisation and only ever sees that organisation's properties, bookings and guests.

Base address

https://guestalizer.io/api/v1

Every request and response is JSON. Send these headers:

Authorization: Bearer {your key}
Accept: application/json
Content-Type: application/json

Dates are YYYY-MM-DD (for example 2026-11-20). Times are ISO 8601 in UTC (for example 2026-11-02T09:15:00+00:00). Money is a number in pounds sterling, with currency alongside.

Permissions (scopes)

The owner chooses what each key may do. A request outside the key's permissions is refused with 403.

ScopeAllows
bookings:readGET /bookings and GET /bookings/{id}
bookings:writePOST /bookings and PATCH /bookings/{id}
guests:readGET /guests

API keys only work under /api/v1. They cannot sign in to the dashboard or use any other part of Guestalizer.

Quick start

Add a booking. Guestalizer creates the verification with the property's rules and sends the guest their link at the usual time:

curl -X POST https://guestalizer.io/api/v1/bookings \
  -H "Authorization: Bearer $GUESTALIZER_KEY" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: booking-engine-order-48213" \
  -d '{
    "property_id": 12,
    "guest": { "first_name": "Sam", "last_name": "Lee", "email": "sam@example.com", "phone": "+447700900123" },
    "check_in": "2026-11-20",
    "check_out": "2026-11-23",
    "adults": 2,
    "channel": "direct",
    "channel_reference": "ORDER-48213"
  }'

Then check on the guest:

curl https://guestalizer.io/api/v1/bookings/431 \
  -H "Authorization: Bearer $GUESTALIZER_KEY" \
  -H "Accept: application/json"

Settings, API lists every property with its id, and each booking returned by GET /bookings carries its property's id too.

The booking object

{
  "id": 431,
  "reference": "GZ-000431",
  "status": "confirmed",
  "channel": "direct",
  "channel_reference": "ORDER-48213",
  "check_in": "2026-11-20",
  "check_out": "2026-11-23",
  "nights": 3,
  "adults": 2,
  "children": 0,
  "total_amount": null,
  "currency": "GBP",
  "is_test": false,
  "property": { "id": 12, "name": "Riverside House" },
  "guest": { "id": 88, "first_name": "Sam", "last_name": "Lee", "email": "sam@example.com", "phone": "+447700900123" },
  "verification": {
    "status": "in_progress",
    "progress": 50,
    "steps": { "contact": "approved", "id": "submitted", "deposit": "pending", "agreement": "not_required" },
    "deposit_status": "card_saved",
    "deposit_amount": 250.0,
    "link_sent_at": "2026-11-13T09:00:04+00:00",
    "link_opened_at": "2026-11-13T18:42:10+00:00",
    "completed_at": null,
    "guest_link": "https://guestalizer.io/v/...",
    "link_expires_at": "2026-12-07T23:59:59+00:00"
  },
  "created_at": "2026-11-02T09:15:00+00:00",
  "updated_at": "2026-11-02T09:15:00+00:00"
}
FieldMeaning
statusconfirmed, cancelled, checked_in or checked_out
channeldirect, airbnb, booking_com, vrbo, expedia or other
is_testtrue for a test booking the owner made from the dashboard ("Send a test link to yourself")
verification.statuspending (nothing done yet), in_progress, awaiting_review (the team must check something), completed (every required step is done), rejected (the guest must try a step again) or cancelled
verification.progressPercentage of the required steps that are approved
verification.stepsOne state per step: not_required, pending, submitted (waiting for the team), approved or rejected
verification.deposit_statusnot_started, card_saved, scheduled, authorized (held on the card), captured, partially_captured, released, expired or failed
verification.guest_linkThe guest's secure link. Only on a single booking (GET /bookings/{id}, POST, PATCH), never in lists. It is a secret: send it only to the guest

List bookings

GET /bookings (scope bookings:read), soonest check in first.

Query parameterMeaning
statusconfirmed, cancelled, checked_in or checked_out
verificationOverall verification status, for example completed or awaiting_review
property_idOne property
channel_referenceYour own reference, exactly as sent
from, toCheck in date range, YYYY-MM-DD, both inclusive
per_page1 to 100, default 25
pagePage number, starting at 1
curl "https://guestalizer.io/api/v1/bookings?from=2026-11-01&to=2026-11-30&verification=completed" \
  -H "Authorization: Bearer $GUESTALIZER_KEY" \
  -H "Accept: application/json"
{
  "data": [ { "id": 431, "reference": "GZ-000431", "...": "..." } ],
  "meta": { "current_page": 1, "last_page": 3, "per_page": 25, "total": 61 }
}

Get one booking

GET /bookings/{id} (scope bookings:read) returns { "data": Booking }, including the guest link. An id that does not exist in your organisation returns 404.

Create a booking

POST /bookings (scope bookings:write) returns 201 and { "data": Booking }.

FieldRequiredMeaning
property_idYesOne of your properties
guestYes, unless guest_id is sentfirst_name and last_name (required), email and phone (optional). A guest with the same email is reused, so their history stays together
guest_idNoAn existing guest from GET /guests, instead of guest
check_in, check_outYesYYYY-MM-DD; check out must be after check in
adultsNo1 to 50, default 1
childrenNo0 to 50, default 0
channelNodirect (default), airbnb, booking_com, vrbo, expedia or other
channel_referenceNoYour own reference, up to 80 characters
total_amountNoThe stay price, for your records
send_linkNotrue emails the guest their link straight away (needs an email). Otherwise the link is sent automatically, on the schedule set in Settings, Verification rules, when the organisation sends links automatically

A booking created through the API behaves exactly like one typed into the dashboard: the verification steps, deposit amount and agreement come from the property's rules, channel rules apply (for example Airbnb guests skip ID and deposit unless the owner chose otherwise), and reminders follow.

Retrying safely (Idempotency-Key)

Networks fail. To retry a POST without making a second booking, send an Idempotency-Key header with a value that is unique to the booking in your system, for example your order number or a UUID (up to 255 visible characters, no spaces).

  • The first request with a key creates the booking.
  • The same key with the same body within 24 hours returns that booking again with 201 and the header Idempotent-Replayed: true. Nothing new is created.
  • The same key with a different body returns 422.
  • If the first request is still being processed, a repeat returns 409; wait a moment and retry.
  • If the first request failed (for example 422), nothing is kept and you can send the corrected request with the same key.

Keys are kept for 24 hours and are separate for each organisation.

Change or cancel a booking

PATCH /bookings/{id} (scope bookings:write) returns { "data": Booking }. Send only the fields that change.

FieldMeaning
check_in, check_outNew dates; check out must stay after check in. The deposit release date and the link's expiry move with them, and so does the hold date while no card has been saved
adults, childrenParty size
channel_referenceYour reference
total_amountThe stay price
statusOnly cancelled. The guest's link stops working and no more reminders are sent
curl -X PATCH https://guestalizer.io/api/v1/bookings/431 \
  -H "Authorization: Bearer $GUESTALIZER_KEY" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{ "status": "cancelled" }'

A cancelled booking cannot be changed again through the API (422). A booking cancelled through the API stays cancelled when a calendar or booking system import runs, the same as when a colleague cancels it.

List guests

GET /guests (scope guests:read), oldest first.

Query parameterMeaning
emailExact email address, not case sensitive
searchPart of a first name, last name, email or phone number
per_page, pageAs for bookings
{
  "data": [
    { "id": 88, "first_name": "Sam", "last_name": "Lee", "email": "sam@example.com", "phone": "+447700900123",
      "nationality": "GB", "tags": [], "bookings_count": 2, "last_stay": "2026-08-03", "verified_before": true,
      "created_at": "2026-07-28T10:02:11+00:00" }
  ],
  "meta": { "current_page": 1, "last_page": 1, "per_page": 25, "total": 1 }
}

Errors

Errors return a status code and a JSON body with a message you can show or log. Validation errors also list the fields concerned:

{
  "message": "The check out field must be a date after check in.",
  "errors": { "check_out": ["The check out field must be a date after check in."] }
}
StatusWhen
401No key, a key that is wrong or revoked, or a dashboard sign in token instead of an API key
402The organisation's Guestalizer plan or free trial has ended. The owner chooses a plan in Settings, Billing
403The key does not have the scope for this request, or the account is paused or due to be deleted
404The booking does not exist in this organisation
409A request with the same Idempotency-Key is still being processed
422Something in the request needs fixing; see errors
429Too many requests; see Rate limits
500 to 599A problem on our side. Retry later with the same Idempotency-Key

Rate limits

Each key can make 60 requests a minute. Every response carries X-RateLimit-Limit and X-RateLimit-Remaining. Over the limit you get 429 with a Retry-After header giving the seconds to wait. Keys are counted separately, so a busy integration does not slow another one down.

Webhooks

Webhooks are not available yet. To follow progress, read GET /bookings/{id} for the bookings you care about, or list GET /bookings?from=...&verification=completed every few minutes. Please do not poll the same booking more than once a minute.

Test bookings

There is no separate test environment. To try the API, create a booking at one of your properties with your own email, open the guest link from the response, then cancel it with PATCH and "status": "cancelled". Bookings the owner makes with "Send a test link to yourself" in the dashboard carry "is_test": true.

Help

Email support@guestalizer.io with the time of the request, the endpoint and the response status. Never send us the API key itself.