Getting a key
- The account owner signs in to Guestalizer and opens Settings, then API.
- They choose Create a key, give it a name (for example "Booking engine") and tick what it may do.
- 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/v1Every request and response is JSON. Send these headers:
Authorization: Bearer {your key}
Accept: application/json
Content-Type: application/jsonDates 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.
| Scope | Allows |
|---|---|
bookings:read | GET /bookings and GET /bookings/{id} |
bookings:write | POST /bookings and PATCH /bookings/{id} |
guests:read | GET /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"
}| Field | Meaning |
|---|---|
status | confirmed, cancelled, checked_in or checked_out |
channel | direct, airbnb, booking_com, vrbo, expedia or other |
is_test | true for a test booking the owner made from the dashboard ("Send a test link to yourself") |
verification.status | pending (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.progress | Percentage of the required steps that are approved |
verification.steps | One state per step: not_required, pending, submitted (waiting for the team), approved or rejected |
verification.deposit_status | not_started, card_saved, scheduled, authorized (held on the card), captured, partially_captured, released, expired or failed |
verification.guest_link | The 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 parameter | Meaning |
|---|---|
status | confirmed, cancelled, checked_in or checked_out |
verification | Overall verification status, for example completed or awaiting_review |
property_id | One property |
channel_reference | Your own reference, exactly as sent |
from, to | Check in date range, YYYY-MM-DD, both inclusive |
per_page | 1 to 100, default 25 |
page | Page 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 }.
| Field | Required | Meaning |
|---|---|---|
property_id | Yes | One of your properties |
guest | Yes, unless guest_id is sent | first_name and last_name (required), email and phone (optional). A guest with the same email is reused, so their history stays together |
guest_id | No | An existing guest from GET /guests, instead of guest |
check_in, check_out | Yes | YYYY-MM-DD; check out must be after check in |
adults | No | 1 to 50, default 1 |
children | No | 0 to 50, default 0 |
channel | No | direct (default), airbnb, booking_com, vrbo, expedia or other |
channel_reference | No | Your own reference, up to 80 characters |
total_amount | No | The stay price, for your records |
send_link | No | true 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
201and the headerIdempotent-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.
| Field | Meaning |
|---|---|
check_in, check_out | New 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, children | Party size |
channel_reference | Your reference |
total_amount | The stay price |
status | Only 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 parameter | Meaning |
|---|---|
email | Exact email address, not case sensitive |
search | Part of a first name, last name, email or phone number |
per_page, page | As 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."] }
}| Status | When |
|---|---|
401 | No key, a key that is wrong or revoked, or a dashboard sign in token instead of an API key |
402 | The organisation's Guestalizer plan or free trial has ended. The owner chooses a plan in Settings, Billing |
403 | The key does not have the scope for this request, or the account is paused or due to be deleted |
404 | The booking does not exist in this organisation |
409 | A request with the same Idempotency-Key is still being processed |
422 | Something in the request needs fixing; see errors |
429 | Too many requests; see Rate limits |
500 to 599 | A 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.