Send a message to the guest of a booking
/api/v1/bookings/{booking_id}/messagesmessages.writeSends the text right away, the way the ZenHost inbox does, and answers once it is sent. platform writes on the messaging of the Sales Channel of the booking; email and sms use the guest contact details ZenHost holds. The message is attributed to your App: the host sees "Sent by" and the name of your App in the inbox.
To attach photos, send the same fields as multipart/form-data with up to 5 photos parts (JPEG, PNG, WebP or AVIF, 10 MB each), on platform only; email and SMS answer validation_failed. In practice a whole call stays under about 4.5 MB (see below). The text and each photo reach the guest as separate messages, the way the ZenHost inbox sends them: the answer is the text message, and GET /bookings/{booking_id}/messages lists the photo messages right after it, with their files. Once the text has reached the guest, the request answers 201 with it even if a photo was refused or its fate is unknown: check that list for the photos before sending them again. Whatever these limits, the hosting platform refuses a request body above 4.5 MB with a 413 that is not the JSON error of the API: send fewer or smaller photos per call.
**SMS are billed to the host**, €0.10 per segment, on their ZenHost subscription. When the subscription cannot be billed, the request answers sms_billing_unavailable: nothing is sent and nothing is billed.
Refusals known before sending answer 422 and send nothing: channel_unavailable (the chosen channel cannot reach the guest, try another one: on platform, the Sales Channel of the booking has no messaging, no conversation exists there yet, or the host must restore their connection to it; on email, the account has no sending address), missing_guest_contact (no email or phone for the chosen channel). When the send fails, delivery_failed tells in details.delivery_outcome whether the message certainly did not leave (not_sent: safe to send again) or its fate is unknown (unknown: check GET /bookings/{booking_id}/messages before sending again).
For Zenny, a message from your App is a reply of the host: a reply Zenny was preparing for this conversation is dropped, and a conversation Zenny handed over to the host is released. Your message never becomes Knowledge. A booking outside the Connection Scope answers not_found, exactly like a missing one. Counts against the send rate limit.
Parameters
Path parameters
booking_idstring (uuid)requiredBooking id.
Headers
Idempotency-KeystringReplaying the same key on the same App Connection within 24 hours answers what the first request did (the same message, or the same refusal) and sends nothing new. Reusing it with a different body answers
idempotency_key_reused; while the first request is still sending,idempotency_key_in_use.at most 255 characters
Request body
application/jsonSendMessageRequest
A text to the guest of the booking.
channelstringrequiredplatformis the messaging of the Sales Channel of the booking (Airbnb, Booking.com…);emailandsmsreach the guest contact details ZenHost holds.One of:
platformemailsmstextstringrequiredThe message. Shortcodes require their corresponding read permission, including nested custom values: bookings.read (plus prices.read for amounts), guests.read, properties.read for title/currency, property_guide.read for guide/custom values, or lock_codes.read. Missing permission refuses the send with forbidden_permission. Portal credentials and invoice/payment links cannot be expanded by Apps.
at most 10000 characters
subjectstringEmail only. Shortcodes follow the same read-permission checks as the text. Without it, the email takes the name of the Property.
at most 255 characters
Responses
201The message, sent.
application/jsonMessage
idstring (uuid)requireddirectionstringrequiredinboundfrom the guest,outboundto the guest.One of:
inboundoutboundauthorMessageAuthorrequiredWho wrote the message. Never carries a guest email or phone, nor the name of the team member.
Show 2 child attributesHide child attributes
typestringrequiredguest(inbound),host(the host or a team member),zenny(written by Zenny, the ZenHost assistant),automation(a Scheduled Message) orapp(an App, seeapp_name). Version 1 may add values.One of:
guesthostzennyautomationappapp_namestringName of the App that sent the message, when
typeisapp.
channelstringrequiredplatformis the messaging of the Sales Channel of the booking (Airbnb, Booking.com…). Version 1 may add values.One of:
platformemailsmstextstringrequiredsubjectstring | nullrequiredEmail subject.
attachmentsMessageAttachment[]requiredShow 5 child attributesHide child attributes
indexintegerrequiredPosition of the file in the message, as in the download URL. Files that cannot be downloaded are left out, so indexes may skip.
min 0
typestringrequiredOnly images in version 1; other types may be added.
One of:
imagefile_namestring | nullrequiredcontent_typestring | nullrequiredMIME type when known; the download answers with the actual one.
urlstring (uri)requiredDownload URL of the file. Call it with the access token of the App Connection, like any other endpoint.
delivery_statusstringrequiredreceivedfor an inbound message. For an outbound one:pendingwhile it is not confirmed sent (in flight, or its fate is not known yet),sent, orrejectedwhen it did not reach the guest: the Sales Channel refused it, or its send failed or stayed unconfirmed for a minute, as the ZenHost inbox shows it. Version 1 may add values.One of:
receivedpendingsentrejectedsent_atstring (date-time)requiredcreated_atstring (date-time)requiredWhen ZenHost recorded the message; the list is sorted on it.
401Error code: unauthorized, connection_revoked.
Error codes
unauthorizedThe access token is missing, unknown, expired or revoked, or was issued before the account connected the App again. Refresh it; if refreshing fails, ask the owner to connect again.connection_revokedThe owner revoked the App Connection (or your App revoked its own refresh token). Stop calling for this account and drop its tokens.
402Error code: subscription_blocked.
Error codes
subscription_blockedThe ZenHost subscription of the account is blocked (unpaid, cancelled…). The connection is kept: tell your customer, calls work again once the subscription is restored.
403Error code: app_suspended, forbidden_permission.
Error codes
app_suspendedZenHost suspended your App, or no longer allows it on this account. Stop calling and contact ZenHost.forbidden_permissionYour App was not granted the Permission this endpoint requires.
404Error code: not_found.
Error codes
not_foundThe resource does not exist or is outside the Connection Scope (both look the same), or the path is not an endpoint of/api/v1.
409Error code: idempotency_key_in_use.
Error codes
idempotency_key_in_useA request with thisIdempotency-Keyis still being processed. Retry in a few seconds to get its answer.
422Error code: validation_failed, idempotency_key_reused, channel_unavailable, missing_guest_contact, sms_billing_unavailable.
Error codes
validation_failedThe query, headers or body are invalid;details.issuespoints at each problem (path,message, andmaximumwhen a value or list is too big).idempotency_key_reusedThisIdempotency-Keywas already used on this App Connection with a different body.channel_unavailableThe chosen channel cannot reach the guest of this booking. Onplatform: the Sales Channel has no messaging for this booking, no conversation exists there yet, or the host must restore their connection to that Sales Channel. Onemail: the account has no sending address. Nothing was sent; try another channel.missing_guest_contactThe guest of this booking has no email address (foremail) or phone number (forsms). Nothing was sent.sms_billing_unavailableThe ZenHost subscription of the account cannot be billed for SMS. Nothing was sent and nothing was billed; use another channel.
429Error code: rate_limited.
Header Retry-After — Seconds to wait before the next call is allowed. Limits per App Connection: 60 reads (GET), 10 writes (other POST) and 30 messages sent to guests per minute.
Error codes
rate_limitedToo many calls on this App Connection. Wait for the number of seconds inRetry-After.
500Error code: internal_error.
Error codes
internal_errorZenHost failed to answer. Retry later with a back-off.
502Error code: delivery_failed.
Error codes
delivery_failedThe message could not be delivered.details.delivery_outcomeisnot_sentwhen it certainly did not leave (safe to send again) orunknownwhen its fate is not known (read the messages of the booking before sending again).