Skip to content

๐Ÿ’ก AI Bot Integration

Answer guest messages with your AI, using live reservation context from LIKE MAGIC

Important: This documentation describes the integration with our test environment. Test your integration thoroughly there before moving to production. Contact api-support@likemagic.tech to get onboarded and receive your test environment credentials.

The Idea

Guests write to the hotel on WhatsApp, SMS or Booking.com. LIKE MAGIC receives every message, matches it to the guest and their reservation and hands it to your AI together with that context. Your AI answers with text, an image or a document, and LIKE MAGIC delivers the answer to the guest on the same channel. When a request needs a person, your AI hands the conversation to the hotel team, and the team can hand it back.

How It Works

The Flow:

  1. Guest writes to the hotel on WhatsApp, SMS or Booking.com
  2. LIKE MAGIC receives the message through Bird and matches it to a guest identity and a reservation where possible
  3. LIKE MAGIC posts the message to your webhook with the guest and reservation context
  4. Your AI fetches more context from the LIKE MAGIC APIs if it needs it, for example booked services or open tasks
  5. Your AI posts its answer to the LIKE MAGIC callback: text, an image or a document
  6. LIKE MAGIC delivers the answer to the guest on the channel the guest used
  7. Your AI or the hotel team hands over whenever a person should take the conversation
sequenceDiagram
    participant Bird
    participant "LIKE MAGIC"
    participant "AI partner"

    Bird->>"LIKE MAGIC": 1: Incoming guest message
    activate "LIKE MAGIC"
    "LIKE MAGIC"->>"LIKE MAGIC": 2: Find guest identity & reservation
    "LIKE MAGIC"->>"AI partner": 3: Guest message with guest & reservation context
    activate "AI partner"
    "AI partner"->>"AI partner": 4: Create answer

    opt Fetch additional information
        "AI partner"->>"LIKE MAGIC": 5: API request
        "LIKE MAGIC"-->>"AI partner": response
    end

    "AI partner"-->>"LIKE MAGIC": 6: Answer via callback (text, image or document)
    deactivate "AI partner"

    "LIKE MAGIC"->>Bird: 7: Deliver answer to guest
    deactivate "LIKE MAGIC"

Matching a message to a guest identity does not always succeed, and the identity of a conversation can change later. Read Guest identity and conversation history before you design how you store guest state.

What You Get

  • Guest messages from WhatsApp, SMS and Booking.com in one webhook, with reservation and property context
  • Text, image and document answers delivered on the guest's own channel
  • Images and files sent by the guest, available through an authenticated download
  • Handover to the hotel team and back, with the full conversation history kept in LIKE MAGIC
  • Access to reservations, services, tasks and conversation history through the LIKE MAGIC APIs

Perfect For

  • AI agent vendors building guest messaging for hotels
  • Conversational AI platforms that want reservation aware answers
  • Hotel groups connecting their own AI to LIKE MAGIC messaging

Technical Details

Before You Start

You need four things before your first test message:

What Where it comes from
Test environment credentials and tenant api-support@likemagic.tech
lm-webhook-secret value for both directions Your technical contact at LIKE MAGIC
A service account for the LIKE MAGIC APIs Created by an Account Admin, see Manage Service Accounts
Your webhook URL You, shared with your technical contact at LIKE MAGIC

Request only the scopes your AI needs. A typical AI agent uses:

Scope Used for
reservation.read, property.read, unit.read, service.read Reservation and property context
guest_conversation.write Resolving conversations and changing their property
guest_message_attachment.read Downloading images and files sent by the guest
magic_id.read Guest links
order_item.write Selling upsells
task.read, task.write Raising and tracking service requests
webhook_subscription.write Subscribing to business events

Test Environment

The URLs below use your tenant specific Base URL (see Prerequisites & Configuration). They show as a pattern on the central docs and are filled in automatically on your own environment.

Open this page on your own environment

We strongly suggest heading over to your tenant's own copy of this page now, to see your real URLs instead of the patterns below and eliminate any guessing:

https://monitoring.<your-domain>/api-doc/use-case/partner/ai-bot-integration/

Just swap in your <your-domain>.

Item Value
Callback URL /api/integration-service/webhook/unified-messaging/<tenant>/callback
Base URL
Tenant likemagic-test
WhatsApp number +1 (226) 640-5907 (test only, production uses the hotel's own number)

Receiving Guest Messages

LIKE MAGIC posts (POST) every event for your AI to the webhook URL you provided.

Security: every request carries the lm-webhook-secret header. Reject requests whose header does not match the secret you received.

Property Type Contract Description
event Enum required lm.message, lm.image, lm.file, lm.notification or lm.action
type Enum required Channel of the message (whatsapp, sms, booking_dot_com) or the action (HUMAN_TAKE_OVER, AI_TAKE_OVER)
tenantName String required Name of the LIKE MAGIC customer
conversationId UUID required Identifier of the conversation. Send it back on every callback
messageId UUID optional Set for messages. Identifier of the specific message
pmsReservationId String optional Linked reservation id from the PMS, if known
pmsPropertyId String optional Linked property id from the PMS. Not sent when no property can be determined
content String or Object optional Set for messages. A string for lm.message, an Image, File or Notification object for the other events
createdAt DateTime String (ISO-8601) required When the message was created
guestActor Guest Actor optional Guest details. Sent for lm.message, lm.image, lm.file and lm.notification, not for lm.action

Guest Actor

Property Type Contract Description
guestIdentityId Long optional Durable identifier of the guest across conversations and channels within one tenant. Empty while the contact is not yet identified, see Guest identity and conversation history
userProfileId Long optional Identifier of the guest profile. Use it to load conversation history and profile data. Set whenever guestIdentityId is set and a profile exists
firstName String optional First name of the guest
lastName String optional Last name of the guest
phone String optional Phone number of the guest
email String optional Email of the guest

Image

Property Type Contract Description
mediaUrl String required URL of the image, download it as described in Downloading guest media
caption String optional Caption written by the guest

File

Property Type Contract Description
mediaUrl String required URL of the file, download it as described in Downloading guest media
contentType String required Type of the file, for example video/mp4, audio/ogg or application/pdf
caption String optional Caption written by the guest

Notification

lm.notification carries the trigger based template messages LIKE MAGIC sent to the guest, so your AI knows what the guest already received.

Property Type Contract Description
text String required Text of the template message
templateName Enum required COMPANION_ADDED, PRE_CHECKIN_REMINDER, RESERVATION_CREATED, CHECKIN, CHECKED_IN, CHECKIN_INTRODUCTION, CHECKIN_REMINDER, CHECKOUT_ALERT, CHECKOUT_FOLLOW_UP, CHECKOUT_INTRODUCTION, ID_CHECK_DECLINED, INVOICE or RESERVATION_CANCELED
language Enum required Language of the template, for example DE or EN

Example: Guest Message

{
  "event": "lm.message",
  "type": "whatsapp",
  "tenantName": "LIKE MAGIC",
  "conversationId": "CONVERSATION_ID_LIKEMAGIC",
  "messageId": "MESSAGE_ID_LIKEMAGIC",
  "pmsReservationId": "PMS_RESERVATION_ID",
  "pmsPropertyId": "PMS_PROPERTY_ID",
  "content": "Where can I find the ironing board?",
  "createdAt": "2025-01-14T15:55:59.547Z",
  "guestActor": {
    "guestIdentityId": 12345,
    "userProfileId": 67890,
    "firstName": "John",
    "lastName": "Smith",
    "email": "john.smith@example.com",
    "phone": "+15550100000"
  }
}

Example: Guest Image

{
  "event": "lm.image",
  "type": "whatsapp",
  "tenantName": "LIKE MAGIC",
  "conversationId": "CONVERSATION_ID_LIKEMAGIC",
  "messageId": "MESSAGE_ID_LIKEMAGIC",
  "pmsReservationId": "PMS_RESERVATION_ID",
  "pmsPropertyId": "PMS_PROPERTY_ID",
  "content": {
    "mediaUrl": "https://media.likemagic.tech/VgYYE0oT",
    "caption": "Is this the right coffee machine?"
  },
  "createdAt": "2025-01-14T15:55:59.547Z",
  "guestActor": {
    "guestIdentityId": 12345,
    "userProfileId": 67890,
    "firstName": "John",
    "lastName": "Smith",
    "email": "john.smith@example.com",
    "phone": "+15550100000"
  }
}

Example: Guest File

{
  "event": "lm.file",
  "type": "whatsapp",
  "tenantName": "LIKE MAGIC",
  "conversationId": "CONVERSATION_ID_LIKEMAGIC",
  "messageId": "MESSAGE_ID_LIKEMAGIC",
  "pmsReservationId": "PMS_RESERVATION_ID",
  "pmsPropertyId": "PMS_PROPERTY_ID",
  "content": {
    "mediaUrl": "https://media.likemagic.tech/VgYYE0oT",
    "contentType": "application/pdf",
    "caption": "My train ticket"
  },
  "createdAt": "2025-01-14T15:55:59.547Z",
  "guestActor": {
    "guestIdentityId": 12345,
    "userProfileId": 67890,
    "firstName": "John",
    "lastName": "Smith",
    "email": "john.smith@example.com",
    "phone": "+15550100000"
  }
}

Example: Notification

{
  "event": "lm.notification",
  "type": "whatsapp",
  "tenantName": "LIKE MAGIC",
  "conversationId": "CONVERSATION_ID_LIKEMAGIC",
  "messageId": "MESSAGE_ID_LIKEMAGIC",
  "pmsReservationId": "PMS_RESERVATION_ID",
  "pmsPropertyId": "PMS_PROPERTY_ID",
  "content": {
    "text": "Hey John, your room is almost ready. Complete your online check-in now.",
    "templateName": "CHECKIN_REMINDER",
    "language": "EN"
  },
  "createdAt": "2025-08-19T03:36:11.344Z",
  "guestActor": {
    "guestIdentityId": 12345,
    "userProfileId": 67890,
    "firstName": "John",
    "lastName": "Smith",
    "email": "john.smith@example.com",
    "phone": "+15550100000"
  }
}

Example: Handover Signals

The hotel team took over the conversation (HUMAN_TAKE_OVER) or handed it back to your AI (AI_TAKE_OVER):

{
  "event": "lm.action",
  "type": "HUMAN_TAKE_OVER",
  "tenantName": "LIKE MAGIC",
  "pmsPropertyId": "PMS_PROPERTY_ID",
  "conversationId": "CONVERSATION_ID_LIKEMAGIC"
}

Stop answering a conversation after HUMAN_TAKE_OVER and resume after AI_TAKE_OVER.

Downloading Guest Media

The mediaUrl of a guest image or file is not public. Download it with your service account token and the guest_message_attachment.read scope:

GET /api/unified-messaging/guest-conversations/attachments?mediaUrl={mediaUrl}

URL encode the mediaUrl value.

Guest Identity and Conversation History

Four identifiers appear in these events and they serve different purposes.

Identifier Use it for Stability
guestIdentityId Grouping a guest's conversations over time Durable, but can be superseded
userProfileId Loading conversation history and profile data through our APIs Stable in normal operation. Can change when two profiles are merged
conversationId Correlating events within one conversation Not durable, can change
messageId Matching a specific message across changes Stable, preserved in all cases

When guestIdentityId Is Empty

We set guestIdentityId once we have matched the sender's phone number or email to a known guest. It is empty when:

  • the guest writes from a phone number or email we have never linked to a reservation
  • the contact belongs to an OTA placeholder address rather than to the guest
  • our person record matching could not resolve the contact unambiguously

While it is empty we cannot tell you which other conversations belong to the same person, and neither history endpoint helps. Use guestActor.phone if you need a best effort grouping on your side.

The value fills in on its own once a reservation carrying that contact reaches us. It is not guaranteed to ever fill in. A contact that never appears on a reservation stays unidentified.

Loading a Guest's Conversation History

With the userProfileId from the event:

Endpoint Returns
GET /guest-conversations/by-user-profile-id/{userProfileId} Paginated conversations of that guest, newest first
GET /guest-conversations/{conversationId}/messages Paginated messages of one conversation

If you only hold a guestIdentityId, resolve the profile first with GET /user-profiles/by-guest-identity-id/{guestIdentityId}. The id in the response is the userProfileId. A guest identity almost always has a profile, but the call can return 404, so handle that case.

Do not swap the two ids

Do not pass a guestIdentityId where a userProfileId is expected. They are separate id spaces. The call usually returns 404 and can in rare cases return a different guest's conversations.

When a Conversation Is Re-keyed

When a contact that was not identified later becomes identified, or an operator resolves an identity conflict, we move the affected messages onto the identified guest and the conversationId changes.

Plan for the following:

  • A conversationId you hold can change. The next event for that guest carries the new one.
  • A conversation can be re-keyed more than once.
  • We delete a conversation once a move leaves it empty, so a GET on that conversationId returns 404. Treat that as superseded rather than invalid and resolve the guest again.
  • guestIdentityId can also be superseded. When an operator merges several identities we create a new one, so two values you have seen can both be replaced by a third.
  • A conversation can hold messages for more than one contact address of the same guest, for example a phone number and an email. A move covers the messages of the contact that was linked, so a conversation can be split.

Because of the last point, do not assume that every message you received under the old conversationId belongs to the newly resolved guest. Match on messageId, which we preserve. Messages you saw under the old conversation reappear under the new one with the same message ids.

We do not currently push an event when a conversation is re-keyed. You can derive it from the events you already receive. If the guestIdentityId for a conversationId you know changes, or a conversation you know appears under a new id, re-read that guest's history through the endpoints above.

Answering the Guest

Post (POST) your answer to the callback URL from the Test Environment table. Send the lm-webhook-secret header you received with every callback.

Property Type Contract Description
event Enum required ai.response
conversationId UUID required The conversationId of the guest message you answer
messageId String required Your own unique identifier of this answer, for example 42827c8e-0354-4b13-9319-5093b83886fe
type String optional Kept for compatibility, send text
content String optional Text of the answer. Required when there is no attachment
attachment Attachment optional One image or document. Required when there is no content

Send at least one of content and attachment. To send several files, post one callback per file, each with its own messageId.

Attachment

Property Type Contract Description
mediaUrl String required Public https URL of the file. LIKE MAGIC passes it on to the messaging channel, which downloads it when the message is sent
contentType String required image/jpeg or image/png for images. application/pdf, Word (.doc, .docx), Excel (.xls, .xlsx), PowerPoint (.ppt, .pptx) or text/plain for documents
fileName String optional Name the guest sees on a document, for example Microwave manual.pdf. Taken from the last part of the URL path when missing. Not shown for images

Hosting your files:

  • Keep the mediaUrl reachable for at least 24 hours. LIKE MAGIC retries failed deliveries and the hotel team views the file in LIKE MAGIC from the same URL.
  • Prefer permanent URLs for knowledge base media. A signed URL that expires before delivery means the guest receives nothing.
  • Use a new URL when you change a file. WhatsApp caches a URL for 10 minutes.
  • Keep images under 5 MB and documents under 20 MB.

How the Answer Reaches the Guest

Channel Text only Attachment only Text and attachment
WhatsApp Text message Image or document without caption Text up to 1024 characters becomes the caption of the image or document. Longer text is sent first as its own message, followed by the image or document
Booking.com Email reply Not delivered, send text with it Email reply with the file attached
SMS Text message Not delivered Not delivered, send text only

Responses

Status Meaning
200 Answer accepted. Delivery to the guest happens asynchronously
400 Answer rejected. The body names the problem: neither content nor attachment, a mediaUrl that is not an absolute https URL or a contentType that is not allowed

Channel rules from the table above are applied after the 200. An attachment that the channel cannot deliver is dropped without a callback to you, so check the channel (type of the guest message) before you send one.

Example: Text Answer

curl -X 'POST' \
  '{{monitoringUrl}}/api/integration-service/webhook/unified-messaging/<tenant>/callback' \
  -H 'Content-Type: application/json' \
  -H 'lm-webhook-secret: <your secret>' \
  -d '{
    "event": "ai.response",
    "conversationId": "367fecba-bc23-418b-aef2-7943180860d4",
    "messageId": "42827c8e-0354-4b13-9319-5093b83886fe",
    "type": "text",
    "content": "The ironing board is in the wardrobe, on the left side."
  }'

Example: Image With Caption

curl -X 'POST' \
  '{{monitoringUrl}}/api/integration-service/webhook/unified-messaging/<tenant>/callback' \
  -H 'Content-Type: application/json' \
  -H 'lm-webhook-secret: <your secret>' \
  -d '{
    "event": "ai.response",
    "conversationId": "367fecba-bc23-418b-aef2-7943180860d4",
    "messageId": "9b1d3f2a-6c4e-4f7a-8d21-0e5b7c3a9f10",
    "type": "text",
    "content": "The ironing board is in the wardrobe, on the left side.",
    "attachment": {
      "mediaUrl": "https://kb.example.com/rooms/ironing-board.jpg",
      "contentType": "image/jpeg"
    }
  }'

Example: Document Without Text

curl -X 'POST' \
  '{{monitoringUrl}}/api/integration-service/webhook/unified-messaging/<tenant>/callback' \
  -H 'Content-Type: application/json' \
  -H 'lm-webhook-secret: <your secret>' \
  -d '{
    "event": "ai.response",
    "conversationId": "367fecba-bc23-418b-aef2-7943180860d4",
    "messageId": "c5e8a1d4-2b7f-4e93-a6c0-71d4f2b8e356",
    "type": "text",
    "attachment": {
      "mediaUrl": "https://kb.example.com/manuals/microwave.pdf",
      "contentType": "application/pdf",
      "fileName": "Microwave manual.pdf"
    }
  }'

Handing Over to a Human

Tell LIKE MAGIC that a person needs to take over. The conversation moves to the hotel team in LIKE MAGIC with its full history.

curl -X 'POST' \
  '{{monitoringUrl}}/api/integration-service/webhook/unified-messaging/<tenant>/callback' \
  -H 'Content-Type: application/json' \
  -H 'lm-webhook-secret: <your secret>' \
  -d '{
    "event": "ai.action",
    "conversationId": "367fecba-bc23-418b-aef2-7943180860d4",
    "type": "HUMAN_INTERVENTION_NEEDED"
  }'

Managing Conversations

Through the Unified Messaging API your AI can resolve a conversation and change its associated pmsPropertyId. Both endpoints return the current guest conversation.

Creating Tasks

Integrate with the Task API to turn guest requests into tasks for the hotel team and track their progress. See Manage Tasks.

Key APIs

Integration Certification

Before moving to production, your integration is certified by LIKE MAGIC.

Checklist:

  1. Develop and test the integration in the test environment
  2. Implement all events and endpoints you use, including handover
  3. Handle errors and edge cases, such as re-keyed conversations and 400 responses
  4. Test every message type in both directions, including images and documents

Schedule the certification call:

  1. Email api-support@likemagic.tech with the subject "Integration Certification Request"
  2. Include your test tenant name, a short summary of your integration and the use cases you support
  3. Share your availability for a call
  4. We review your integration and schedule the meeting

During the call we verify the integration and give feedback before approving it for production.


New to the platform? Start with Authentication and Manage Service Accounts.