Introduction
Webhooks allow external services to be notified by iGMS when certain events happen. When a specified event happens, we send a POST request to the URL you've provided. To register a webhook you should email us to support@igms.com and provide the following information:
- Client ID of your iGMS API Application
- Webhook type (Calendar data change, Booking change, Guest data change, or Properties change)
- a URL (or URLs) to send requests to. You may provide different URLs for different types of webhooks
- (optional) a shared secret if you want webhook requests to be signed — see the Authentication section
Authentication (optional)
If you provided a shared secret when registering your webhook, every request iGMS sends will include the following headers:
| Header | Description |
|---|---|
X-iGMS-Webhook-Id | Unique identifier of the webhook delivery. Useful for deduplication. |
X-iGMS-Webhook-Type | Webhook type, mirrors the type field in the body. |
X-iGMS-App-Id | Client ID of the iGMS API Application the webhook is registered for. Use it to pick the matching secret or to filter deliveries when the same URL receives webhooks for several applications. Not part of the signed payload. |
X-iGMS-Timestamp | Unix timestamp at which the request was signed. |
X-iGMS-Signature | Signature in the form sha256=<hex>, see below. |
The signature is computed as:
signature = HMAC_SHA256(secret, timestamp + "." + raw_request_body)
To verify a request, recompute the HMAC using the timestamp from X-iGMS-Timestamp, a dot, and the raw request body, then compare it (constant-time) with the value after sha256= in X-iGMS-Signature. Reject requests whose timestamp is older than a few minutes to prevent replay attacks.
Example (PHP):
$expected = 'sha256=' . hash_hmac('sha256', $_SERVER['HTTP_X_IGMS_TIMESTAMP'] . '.' . file_get_contents('php://input'), $secret);
if (!hash_equals($expected, $_SERVER['HTTP_X_IGMS_SIGNATURE'])) {
http_response_code(401);
exit;
}
If you did not provide a secret, only the X-iGMS-Webhook-Id, X-iGMS-Webhook-Type, and X-iGMS-App-Id headers are sent and the request is unsigned.
Webhooks general info
Every webhook request will have the following body schema:
| Key | Type | Description |
|---|---|---|
| type | string | Webhook type. One of booking_data, calendar_data, guest_data, properties_data, reservation_alteration |
| data | object[] | Array of webhook data objects |
The schema of objects in the data field depends on the webhook type.
The response to the webhook request must be 200 OK, other codes would trigger a series of retries with exponential backoff.
List of webhooks
| Name | Description |
|---|---|
| Booking change | Notify about reservation change |
| Reservation alteration | Notify about an Airbnb alteration request created or finalized |
| Calendar data change | Notify about calendar data change |
| Guest data change | Notify about guest details change |
| Properties change | Notify about created\deleted properties |
| Property calendar control change | Notify a partner pricing-suggestion app about enabling/disabling calendar control for property |
| Connection revoked | Notify about revoking connection |
| Message edited or unsent | Notify about a guest editing or unsending an Airbnb message, or about the files of an Airbnb guest photo message becoming available |
| Message reactions changed | Notify about a change of the reactions on an Airbnb message |
Booking change
This webhook is sent when a booking is changed. For this webhook data objects will be in the following format:
| Key | Type | Description |
|---|---|---|
| company_uid | string | UID of company |
| booking_uid | string | UID of booking |
| reservation_code | string | Reservation code |
| booking_status | string | One of available booking statuses (see the corresponding filters section) |
| reservation_type | string | regular for a booking, or owner_block for an Owner's Block |
| platform_type | string | One of available platform types (see the corresponding filters section) |
| listing_uid | string | UID of booked listing |
| property_uid | string | UID of booked property |
| guest_uid | string | UID of guest |
| host_uid | string | UID of host |
| number_of_guests | int | Number of guests |
| guests_breakdown | object | Guests breakdown object, present only when a breakdown is available |
| price | object | Pricing data object |
| local_checkin_dttm | string | Local checkin datetime in Y-m-d H:i:s format |
| local_checkout_dttm | string | Local checkout datetime in Y-m-d H:i:s format |
| created_dttm | string | Creation datetime in Y-m-d H:i:s format |
| updated_dttm | string | Last update datetime in Y-m-d H:i:s format |
Pricing data
| Key | Type | Description |
|---|---|---|
| currency | string | Currency code (3 symbols) |
| price_base | string | Numeric string with fraction |
| price_extras | string | Numeric string with fraction |
| price_fee | string | Numeric string with fraction |
| price_tax | string | Numeric string with fraction |
| price_total | string | Numeric string with fraction |
price_fee is the channel's host fee. On most platforms the channel withholds it, so price_total is the host payout net of price_fee. Vrbo and sometimes Booking.com invoice their host fee to the host after the stay instead of withholding it, so on vrbo bookings price_total is not net of price_fee: it equals price_base + price_extras + price_tax, and price_fee is reported for information.
Guests breakdown
guests_breakdown and each of its keys appear only when iGMS holds a value for that reservation. Treat an absent key as unknown rather than zero. A present 0 is likewise not proof the platform reported zero — some integrations store 0 as a default for a category the platform never sent. The categories do not necessarily sum to number_of_guests, which some platforms count over adults and children only.
| Key | Type | Description |
|---|---|---|
| adults | int | Number of adults |
| children | int | Number of children |
| infants | int | Number of infants |
| pets | int | Number of pets |
Request body sample
{
"type": "booking_data",
"data": [
{
"company_uid": "581919935819928467",
"booking_uid": "DR3RS5S6_airgms_GT0QUEMAKFD400FS",
"reservation_code": "DR3RS5S6",
"booking_status": "accepted",
"reservation_type": "regular",
"platform_type": "airgms",
"listing_uid": "GT0QUEMUFT28YBID_airgms_GT0QUEMAKFD400FS",
"property_uid": "5804533058085162365",
"guest_uid": "9WO7Y5I9C4WSCKCWG4KKWKWK0_airgms",
"host_uid": "GT0QUEMAKFD400FS_airgms",
"number_of_guests": 1,
"guests_breakdown": {
"adults": 1,
"children": 0,
"infants": 0
},
"price": {
"currency": "USD",
"price_base": "10.00",
"price_extras": "0.00",
"price_fee": "0.00",
"price_tax": "0.00",
"price_total": "10.00"
},
"local_checkin_dttm": "2021-10-10 13:00:00",
"local_checkout_dttm": "2021-10-11 11:00:00",
"created_dttm": "2021-10-06 20:14:10",
"updated_dttm": "2021-10-06 20:14:15"
}
]
}
Reservation alteration
(Available upon request, with the airbnb-reservations scope)
This webhook is sent when a guest or a host creates an Airbnb alteration request, and when the request reaches a final status. For this webhook data objects will be in the following format:
| Key | Type | Description |
|---|---|---|
| company_uid | string | UID of company |
| alteration_id | string | Airbnb alteration ID. Send it as alteration_id to v2/accept-reservation-alteration or v2/decline-reservation-alteration |
| reservation_code | string | Reservation code |
| booking_uid | string | UID of booking |
| status | string | One of pending, accepted, declined, canceled, expired |
| initiated_by | string | One of guest, host, admin |
| checkin_date | string | Checkin date requested by the alteration, in Y-m-d format |
| checkout_date | string | Checkout date requested by the alteration, in Y-m-d format |
| guests | int | Number of guests requested by the alteration |
| price | number | Host payout for the booking as the alteration changes it, the Payout the iGMS Inbox shows |
| currency | string | Currency code (3 symbols) |
| updated_at | string | Datetime of the alteration's last update on Airbnb |
Every request carries the latest state of the alteration, not a log of changes. Deliveries can arrive more than once or out of order: treat them as idempotent, and keep the one with the latest updated_at for each company_uid and alteration_id.
Request body sample
{
"type": "reservation_alteration",
"data": [
{
"company_uid": "581919935819928467",
"alteration_id": "1234567",
"reservation_code": "HMABCDEFGH",
"booking_uid": "HMABCDEFGH_airbnb_123456789",
"status": "pending",
"initiated_by": "guest",
"checkin_date": "2026-11-01",
"checkout_date": "2026-11-05",
"guests": 3,
"price": 450.5,
"currency": "USD",
"updated_at": "2026-10-10 12:00:00"
}
]
}
Calendar data change
(Available upon request)
This webhook is sent when calendar data for a date (or dates) are changed. For this webhook data objects will be in the following format:
| Key | Type | Description |
|---|---|---|
| company_uid | string | UID of company |
| listing_uid | string | UID of listing |
| property_uid | string | UID of property |
| date | string | Calendar date in Y-m-d format |
| rate_id | string | Platform rate ID ('0' for the platforms which do not support rates and also for rate agnostic calendar data (e. g. listing availability)) |
| currency | string | Currency code (3 symbols) |
| price | string | Numeric string with fraction |
| is_available | int | Is listing available (1) or not (0) |
| min_stay | int | Minimum nights value |
| base_price | string | deprecated |
| base_min_stay | int | deprecated |
Request body sample
{
"type": "calendar_data",
"data": [
{
"company_uid": "581919935819928467",
"listing_uid": "51477991_airbnb_411957375",
"date": "2021-10-11",
"rate_id": "0",
"currency": "USD",
"is_available": 1,
"price": "100.00",
"min_stay": 2
}
]
}
Guest details change
This webhook is sent when the guest details of one of the future bookings are changed. For this webhook data objects will be in the following format:
| Key | Type | Description |
|---|---|---|
| company_uid | string | UID of company |
| guest_uid | string | UID of guest |
| platform_type | string | One of available platform types (see the corresponding filters section) |
| name | string | Guest full name |
| string[] | Array of guest emails | |
| phone_number | string[] | Array of phone numbers |
Request body sample
{
"type": "guest_data",
"data": [
{
"company_uid": "581919935819928467",
"guest_uid": "EOJTEMLW5IOS4GWWWOGOCOS88_airgms",
"platform_type": "airgms",
"name": "Pavel",
"email": [
"pavel@example.com"
],
"phone_number": [
"+79123456789"
]
}
]
}
Properties change
This webhook is sent when user's properties list has changed: either a property has been changed or deleted, or a property has been merged into another property, or a new property has been created.
For this webhook data objects will be in the following format:
| Key | Type | Description |
|---|---|---|
| company_uid | string | UID of company |
| operation | string | create or delete or update |
| property_uid | string | UID of removed\created property |
Request body sample
{
"type": "properties_data",
"data": [
{
"company_uid": "4674080625695383552",
"operation": "create",
"property_uid": "6848864665656201326"
"name": "Superior Single Room with Sea View",
"address": "402 W Georgia St, Vancouver, V6B 5A2",
"checkin_time": "15",
"checkout_time": "12",
"beds": 1,
"bedrooms": 0,
"bathrooms": 0,
"is_active": 1,
"comment": null,
"clean_hr": 1.5,
"clean_tm": null,
"clean_beds_k": 0,
"clean_beds_q": 1,
"clean_beds_d": 0,
"clean_beds_s": 0,
"clean_specials": null,
"is_inbox_enabled": 1,
"are_auto_reviews_enabled": 1,
"ical_token": null,
"location": {
"country_code": "ca",
"postal_code": "V6B 5A2",
"lat": 49.279616,
"lng": -123.1122527,
"street": "402 W Georgia St",
"city": "Vancouver"
},
"selected_insurance_settings": {
"future_reservation_coverage": "newlyBookedReservations",
"content_and_dwelling_amount": 25000,
"bodily_insurance_amount": 500000,
"channel_coverage": [
"airgms"
],
"include_screening_information": true,
"insurance_company_name": "CompanyName",
"is_insurance_coverage_active": true
},
"listings": [
"660689604_booking_6606896",
"GHA78D5I705LYHGA_airgms_4OXKYWD7RB8KSK8GK8K4SS8K0"
],
"door_access_code": null,
"calendar_control_allowed": false,
"currency": "CAD"
}
]
}
Property calendar control change
This webhook is sent to a partner pricing-suggestion app when user changes whether that app controls property calendar.
Even if control is not allowed, we save received calendar data to be applied if user re-enables the app.
For this webhook data objects will be in following format:
| Key | Type | Description |
|---|---|---|
| company_uid | string | UID of company |
| property_uid | string | UID of property |
| calendar_control_allowed | bool | Is app controls property calendar |
Request body sample
{
"type": "property_calendar_control_changed",
"data": [
{
"company_uid": "4674080625695383552",
"property_uid": "6848864665656201326",
"calendar_control_allowed": false
}
]
}
Connection revoked
This webhook is sent when user revokes access to app.
For this webhook data objects will be in following format:
| Key | Type | Description |
|---|---|---|
| company_uid | string | UID of company |
Request body sample
{
"type": "connection_revoked",
"data": [
{
"company_uid": "4674080625695383552"
}
]
}
New message received
This webhook is sent when a new message is received in a conversation thread. For this webhook, the data object will be in the following format:
| Key | Type | Description |
|---|---|---|
| messageId | string | Unique ID of the message |
| threadId | string | Unique ID for threads |
| platformSenderUserId | string | ID of the user who sent the message on the platform |
| senderUid | string | Composite identifier combining sender ID and platform type |
| messageText | string | The content of the message |
| messageDttm | string | Timestamp of when the message was created |
| platformMessageDttm | string | Timestamp of when the message was sent on the channel |
| files | array | List of files attached to the message (if any). An Airbnb photo message can arrive with empty files; its files follow in the message_updated webhook, unless it reached iGMS 24 hours or more after it was sent |
| messageType | string | One of guest, host, self_service_request |
| selfServiceTopic | string or null | Present only when messageType is self_service_request: the self-service topic of the request, null when the guest picked none |
| editedAt | string or null | UTC time (Y-m-d H:i:s) the sender last edited an Airbnb message, null when it was never edited or is not from Airbnb |
| deletedAt | string or null | UTC time (Y-m-d H:i:s) the sender unsent an Airbnb message, null otherwise. An unsent message has an empty messageText and files |
A self_service_request is a structured request a Booking.com guest sends through Booking.com's self-service options (check-in time, parking and so on); messageText holds the guest's text.
A self-service request that is already older than one hour when it is received is stored quietly and does not send this webhook.
Each new guest message and self-service request gets its own webhook, whose data list holds that one message, even when the same sync brings several messages of the thread or a newer host message. Webhooks of one thread can arrive out of order. When a conversation is first synced, only its messages from the last hour and its newest message are sent.
Self-service topics
| selfServiceTopic | Label | Note |
|---|---|---|
| checkin | Check-in time | |
| checkout | Check-out time | |
| change_dates_nr | Change dates | Extranet only: answer this request in the Booking.com extranet |
| cancel_booking | Cancel booking | |
| booking_basic_waive_fee | Waive cancellation fee | Extranet only: answer this request in the Booking.com extranet |
| parking | Parking | |
| free_text_parking | Parking (free text) | |
| bed_type | Bed type | |
| extra_crib | Extra crib | |
| extra_bed | Extra bed |
Other values may appear as Booking.com adds topics.
Request body sample
{
"type": "new_message",
"data": [
{
"messageId": "msg_123456",
"threadId" => "13234",
"platformSenderUserId": "user_456789",
"senderUid": "user_456789_airbnb",
"messageText": "Hi, I'm interested in your listing.",
"messageDttm": "2025-04-15T12:45:30Z",
"platformMessageDttm": "2025-04-15T12:43:30Z",
"files": [
{
"url": "https://example.com/image1.jpg",
"name": "image1.jpg",
"type": "image/jpeg"
}
],
"messageType": "guest",
"editedAt": null,
"deletedAt": null
}
]
}
Request body sample: self-service request
{
"type": "new_message",
"data": [
{
"messageId": "msg_123457",
"threadId": "13235",
"platformSenderUserId": "user_456790",
"senderUid": "user_456790_booking",
"messageText": "We will arrive around 10 am, can we check in early?",
"messageDttm": "2025-04-15T12:50:00Z",
"platformMessageDttm": "2025-04-15T12:48:00Z",
"files": [],
"messageType": "self_service_request",
"selfServiceTopic": "checkin",
"editedAt": null,
"deletedAt": null
}
]
}
Message edited or unsent
This webhook (type message_updated) is sent when an Airbnb guest edits a message or unsends it. Airbnb lets a guest edit a message within 15 minutes and unsend it within 24 hours. The app needs the messaging scope.
For this webhook, the data object is the message in the same format as in the New message received webhook, holding the message's current content:
- after an edit,
messageTextholds the new text andeditedAtis set; - after an unsend,
messageTextis empty,filesis empty anddeletedAtis set.
It is also sent once the files of an Airbnb guest photo message are available, with files holding them. A photo message that a sync brings in 24 hours or more after it was sent sends nothing.
The message keeps its messageId, so replace the message you already have. It always carries the message's latest content, so edits made in quick succession may arrive as one webhook; a host's own edits do not send it.
Request body sample
{
"type": "message_updated",
"data": [
{
"messageId": "msg_123456",
"threadId": "13234",
"platformSenderUserId": "user_456789",
"senderUid": "user_456789_airbnb",
"messageText": "",
"messageDttm": "2025-04-15 12:45:30",
"platformMessageDttm": "2025-04-15 12:43:30",
"files": [],
"messageType": "guest",
"editedAt": null,
"deletedAt": "2025-04-15 13:02:11"
}
]
}
Message reactions changed
This webhook is sent when Airbnb reports a change of the reactions on a message in an Airbnb thread, whether the host or the guest reacted. It comes with the messaging scope.
For this webhook, the data object will be in the following format:
| Key | Type | Description |
|---|---|---|
| messageId | int | ID of the message, as messageId in get-threads |
| threadId | int | ID of the thread, as threadId in get-threads |
| reactions | object[] | Every reaction now on the message, in the format of reactions in get-threads: emoji, reactionCreatorUid, updatedDttm |
Each event carries the full current list of reactions on the message, so an event may repeat a list that has not changed. When the last reaction is removed, reactions is an empty array.
Request body sample
{
"type": "message_reactions_changed",
"data": [
{
"messageId": 1409176420,
"threadId": 1033512,
"reactions": [
{
"emoji": "❤️",
"reactionCreatorUid": "123456789_airbnb",
"updatedDttm": "2024-11-20 10:35:12"
}
]
}
]
}