Conversation API
Webhooks/Callbacks
Through webhooks, you can receive notifications when an event is fired. In most cases, it is a good idea to start processing inbound messages and then process the statuses of outbound messages.
Registering and processing webhooks
For each organization, you can specify separate webhook URLs and headers for events.
Our server will send POST requests to your server, in which the body will be a JSON representation of the notification. Your server should return a 200 status code. Any other status code will be considered a failure by our backend. Our server will retry later (up to 30 times) with an increasing delay. First 10 retries every 30 seconds, the next 10 retries every 3 mins, and the last 10 retries every 15 mins. After 30 retries, we will stop sending notifications.
If your service/app doesn’t return a response within 15 seconds, our server will disconnect and reschedule a webhook for retry. It’s highly recommended that your apps/services defer processing until return a response with a status code 200.
Webhook Events
Sample Webhook Events
These are some representative samples of webhooks you might receive from LoopMessage. Keep in mind that webhooks can include additional fields to what’s shown here.
Response {.tabset .tabset-fade}
tab Inbound
{
"event": "message_inbound",
"contact": "+13231112233",
"text": "text",
"message_type": "text",
"message_id": "59c55Ce8-41d6-43Cc-9116-8cfb2e696D7b",
"webhook_id": "ab5Ae733-cCFc-4025-9987-7279b26bE71b",
"api_version": "1.0"
}
tab Scheduled
{
"event": "message_scheduled",
"contact": "+13231112233",
"text": "text",
"message_id": "59c55Ce8-41d6-43Cc-9116-8cfb2e696D7b",
"webhook_id": "ab5Ae733-cCFc-4025-9987-7279b26bE71b",
"api_version": "1.0"
}
tab Failed
{
"event": "message_failed",
"contact": "+13231112233",
"text": "text",
"error_code": 100,
"message_id": "59c55Ce8-41d6-43Cc-9116-8cfb2e696D7b",
"webhook_id": "ab5Ae733-cCFc-4025-9987-7279b26bE71b",
"api_version": "1.0"
}
tab Delivered
{
"event": "message_delivered",
"contact": "+13231112233",
"text": "text",
"message_id": "59c55Ce8-41d6-43Cc-9116-8cfb2e696D7b",
"webhook_id": "ab5Ae733-cCFc-4025-9987-7279b26bE71b",
"api_version": "1.0"
}
tab Reaction
{
"event": "message_reaction",
"contact": "+13231112233",
"text": "text",
"reaction": "like",
"message_id": "59c55Ce8-41d6-43Cc-9116-8cfb2e696D7b",
"webhook_id": "ab5Ae733-cCFc-4025-9987-7279b26bE71b",
"api_version": "1.0"
}
Possible JSON fields in webhooks
| Field | Type | Description |
|---|---|---|
| message_id | String | Unique identifier of your request/message. |
| webhook_id | String | Unique identifier of the event. |
| event | String | Check the Event Types section for possible values. |
| contact | String | The contact to which the event relates. Contact can be a phone number or email address. A phone number will be in the E164 format: +13231112233, without spaces and brackets. Email will be in lowercase format. |
| text | String | Text in the message. |
| subject | String | Optional Field. Message subject. |
| attachments | Array | Optional Field with an array of strings. This field will only be for the event: message_inbound. Each element of the array is the URL to download the file. |
| message_type | String | This field will only be for events: message_inbound or message_reaction. Possible values: text, reaction, audio, attachments, sticker, location. |
| channel | String | How the message was sent/received. Possible values: imessage, sms, rcs. |
| reaction | String | Indicates if a contact reacted to your message This field will only be for the event: message_reaction Possible values: love, like, dislike, laugh, emphasize, question, unknown. |
| sender | String | Dedicated sender name ID. |
| thread_id | String | Optional field. If the contact tapped reply-to it will create a conversation thread in the iMessage. This identifier will help you understand to which thread the message is related. |
| error_code | Integer | Error code that occurred while processing the request This field will only be for the event: message_failed. |
| language | Object | The dominant language that is used in the text. Check the language section for details. |
| group | Object | Data related to the iMessage group. Check the group section for details. |
| speech | Object | Optional field. Transcription of an inbound audio message. Will be contained in the JSON only if the speech section for details. |
| parameters | Object | Optional field. This field will only be for the event: message_inbound. Additional parameters were included by using the opt-in API or sign-up forms. Parameters may vary depending on what you set up to include there. |
Event Types
All values will be in lowercase and in snake_case format
| Event type | Description |
|---|---|
| message_failed | Failed to send or deliver a message. Further events related to your request will no longer be fired. |
| message_delivered | The message has been delivered. |
| message_inbound | Contact sent you an inbound message. |
| message_reaction | Contact put a reaction to your text. For example Like, Love and etc. |
| inbound_call | Your contact attempted to call via FaceTime. |
| unknown | An unknown event has occurred |
Language
| Key | Value |
|---|---|
| code | ISO 639-1 code. Examples: en, fr, de, ja, zh. |
| name | Examples: English, French, German, Japanese, Chinese. |
| script | Optional field. Supported only two values for the Chinese language:-Hans: Simplified Chinese script-Hant: Traditional Chinese script |
The dominant language in the text. These values are approximate and may be incorrect if the message is less than 100 characters long or contains text in several languages.
Group
| Key | Value |
|---|---|
| id | Unique ID of iMessage group. You can use this value as the contact/recipient value in the send messages requests. |
| name | Optional field. Custom name for this group (if named). |
| participants | An array of strings (participants) in this group. Values in the array can be a phone number (in E164 format) or email (in lowercase format). |
Speech
| Key | Value |
|---|---|
| text | Text transcription from audio message |
| language | Language object. The dominant language that is used in the text. Check the language section for details. |
| metadata | Optional field. The metadata of speech in the audio message. Check the speech metadata section for details. |
These values are approximate and may be incorrect if the voice is too long, unclear, or in several languages.
Speech metadata
Any field in this object can be optional. All values are float type.
| Key | Value |
|---|---|
| speaking_rate | Measures the number of words spoken per minute. |
| average_pause_duration | Measures average pause between words (in seconds). |
| speech_start_timestamp | Timestamp of start of speech in audio. |
| speech_duration | Duration of speech in audio. |
| jitter | Jitter measures vocal stability and is measured as an absolute difference between consecutive periods, divided by the average period. It is expressed as a percentage. |
| shimmer | Shimmer measures vocal stability and is measured in decibels. |
| pitch | Pitch measures the highness and lowness of tone and is measured in logarithm of normalized pitch estimates. |
| voicing | Voicing measures the probability of whether a frame is voiced or not and is measured as a probability. |
Parameters
Parameters may vary depending on what you set up to include there.
If you are using the opt-in API, it will include all parameters you passed when generating an opt-in URL.
If you are using sign-up forms, they may include all the fields that you set up in your form.
An example of fields if you’re using sign-up forms:
{
...
"parameters": {
"pool": "your-pool-id",
"timezone": "America/New_York",
"form_elements": {
"first_name": "John",
"last_name": "Smith",
"email": "[email protected]",
"country": "US",
"company": "String",
"company_website": "https://secrect-company.ai",
"zip": "10001",
"custom1": "Custom field"
}
}
}
Headers
All webhooks will contain the following headers
| Key | Value |
|---|---|
| Content-Type | application/json |
| User-Agent | LoopMessage |
| Connection | close |
Best practices
Authorization
You can configure the authorization header used for webhook requests via the dashboard. Your server should verify the validity of the authorization header for every event. This will help you make sure that a webhook was sent from our service.
IP Whitelisting
The webhook IP range is variable, so we don’t recommend hardcoding our server’s IP. To authenticate requests, you can add an authorization token to the webhook that you can then verify on your server.
Response Duration
Try to return a response immediately so as not to accidentally reach the timeout duration.
If this happens, you can use webhook_id as a unique identifier to avoid processing the same event twice. But even in this case, you need to return a response with code 200 to stop firing a webhook.
Please note that if you are using ngrok or similar services, the timeout time will be much shorter to prevent abuse by keeping many dummy connections.
Security and encryption
It is highly recommended to use HTTPS URLs for webhooks. If you use HTTP URLs (without SSL), requests to your server will not be encrypted and the contents of your requests/messages may be intercepted. In some cases, webhooks for HTTP URLs (without SSL) may not be delivered.
Future-Proofing
You should be able to handle webhooks that include all important fields to what’s shown here, including new event types. We may add new fields or event types in the future without changing the API version. We won’t remove fields or events without proper API versioning and deprecation.