Webhooks
When webhooks are enabled from the Settings page of the TalkJS dashboard, your server will receive HTTP POST
requests from TalkJS server notifying you about events that happen in your application between your users. Webhooks can be useful as part of a chatbot interface, to inspect messages as they happen or to be notified of certain events to trigger custom domain specific actions.
For testing the webhooks locally, you can check out our tutorial on how to integrate ngrok with TalkJS.
TalkJS sends webhook events as HTTP POST
requests with a JSON payload. By default, TalkJS sends a HTTP POST
request and waits for a response from your webhook endpoint for 5 seconds. If TalkJS receives a non-200 OK
response we will retry sending the event once more shortly after the first attempt failed.
If you expect a high amount of usage, then we strongly recommend that you immediately respond with a HTTP 200 OK
and handle the webhook event asynchronously. This ensures that events are acknowledged and aren't incorrectly retried. If you handle events synchronously, it may cause your endpoint to become unresponsive when a surge of events are generated by your TalkJS account.
We advise you to check the authenticity of each event sent to your webhook endpoint, as explained in our security recommendations guide.
TalkJS supports following webhook events:
Occurs when a user is created in TalkJS backend.
Occurs when a user is updated in TalkJS backend.
Occurs when a message is sent in a conversation.
Occurs when another user in the same conversation receives the message in the chat UI. This event gets sent at most once for every member of a conversation other than the sender.
Note that message.read
is only sent for conversations with at most 300 participants, in which case the readBy
field contains up to 300 elements. For conversations with 301 or more participants, no message.read
webhook is sent.
Occurs when the content or metadata of the message is updated. Note that message.updated
is not called when the message has been read (message.read
).
Occurs when the message has been deleted.
Occurs when a conversation is deleted via the REST API
Occurs when TalkJS decided that a notification is to be sent to a user. In particular, this is the case when both of the following conditions are met:
- One or more messages have been sent by one or more users and the user(s) stopped typing or went offline, indicating that no further messages are to be expected
- Another user was not currently online and looking at the same conversation, indicating that they might have missed the messages sent and thus should be notified.
This webhook event is triggered even if notify is set to false
for individual participants. This makes it possible to create additional custom logic for if each participant should be notified. Using the webhook payload data you can check the participants notify setting within the webhook payload itself and determine if the notification should be sent or dropped, for example:
JavaScript1const conversation = event.data.conversation;2const recipient = event.data.recipient;3if(conversation.participants[recipient.id].notify) { ... }
Note that the notification.triggered
event will occur even if a user has no email or phone number set. This allows you to substitute TalkJS's notification features by your own, if you wish.
Occurs when TalkJS has actually sent the aforementioned notification. May be triggered more than once for each notification if TalkJS notifies a user both via email and SMS. Does not get triggered for mobile push notifications.
Occurs when a email was successfully delivered.
Occurs when an email was not successfully delivered. It is triggered for bounces and spam complaints that resulted from outgoing email.
Occurs when a user opens an email notification in an email client. Note that it may not always be triggered, because user’s email client might be blocking tracking pixels.
Occurs when a user clicks a link inside an email notification.
Prefer examples?
You can see examples on how to use TalkJS Webhooks in our examples repository on GitHub.
All events have the same top-level structure, as shown below. Only the structure of the data
field differs for every type
:
1type Event = {2 id: string;3 createdAt: number; // UNIX timestamp in milliseconds4 data: any;5 type: string;6};
The supported webhook events are structured below.
The structure for the user.created
event is as follows:
1type UserCreatedEvent = {2 id: string;3 createdAt: UnixMilliseconds;4 data: {5 user: User;6 };7};
The structure for the user.updated
event is as follows:
1type UserUpdatedEvent = {2 id: string;3 createdAt: UnixMilliseconds;4 data: {5 user: User;6 };7 type: 'user.updated';8};
The structure for the conversation.deleted
event is as follows:
1type ConversationDeletedEvent = {2 id: string;3 createdAt: UnixMilliseconds;4 data: {5 conversation: Conversation;6 };7 type: 'conversation.deleted';8};
The structure for the message.sent
event is as follows:
1type MessageSentEvent = {2 id: string;3 createdAt: UnixMilliseconds;4 data: {5 sender: User;6 conversation: Conversation;7 message: Message;8 };9 type: 'message.sent';10};
The structure for the message.read
event is as follows:
1type MessageReadEvent = {2 id: string;3 createdAt: UnixMilliseconds;4 data: {5 recipient: User;6 conversation: Conversation;7 message: Message;8 };9 type: 'message.read';10};
The structure for the message.updated
event is as follows:
1type MessageUpdatedEvent = {2 id: string;3 createdAt: UnixMilliseconds;4 data: {5 sender: User;6 conversation: Conversation;7 message: Message;8 };9 type: 'message.updated';10};
The structure for the message.deleted
event is as follows:
1type MessageDeleted = {2 id: string;3 createdAt: UnixMilliseconds;4 data: {5 sender: User | null;6 conversation: Conversation;7 message: Message;8 };9 type: 'message.deleted';10};
The structure for the notification.triggered
event is as follows:
1type NotificationTriggered = {2 id: string;3 createdAt: UnixMilliseconds;4 data: {5 notificationId: string;6 recipient: User;7 sender: User;8 conversation: Conversation;9 messages: Message[];10 };11 type: 'notification.triggered';12};
Note that the notification.triggered
event will occur even if a user has no email or phone number set. This allows you to substitute TalkJS's notification features by your own, if you wish.
The structure for the notification.sent
event is as follows:
1type NotificationSent = {2 id: string;3 createdAt: UnixMilliseconds;4 data: {5 notificationId: string;6 recipient: User;7 sender: User;8 conversation: Conversation;9 messages: Message[];10 channel: 'email' | 'sms';11 };12 type: 'notification.sent';13};
The structure for the notification.delivered
event is as follows:
1type NotificationDelivered = {2 id: string;3 createdAt: UnixMilliseconds;4 data: {5 notificationId: NotificationId;6 conversation: Conversation;7 messages: Message[];8 recipient: User;9 sender: User;10 channel: 'email';11 };12 type: 'notification.delivered';13};
The structure for the notification.bounced
event is as follows:
1type NotificationBounced = {2 id: string;3 createdAt: UnixMilliseconds;4 data: {5 notificationId: NotificationId;6 conversation: Conversation;7 messages: Message[];8 recipient: User;9 sender: User;10 channel: 'email';11 };12 type: 'notification.bounced';13};
The structure for the notification.opened
event is as follows:
1type NotificationOpened = {2 id: string;3 createdAt: UnixMilliseconds;4 data: {5 notificationId: NotificationId;6 conversation: Conversation;7 messages: Message[];8 recipient: User;9 sender: User;10 channel: 'email';11 isFirstOpen: boolean12 };13 type: 'notification.opened';14};
The structure for the notification.link.clicked
event is as follows:
1type NotificationLinkClicked = {2 id: string;3 createdAt: UnixMilliseconds;4 data: {5 notificationId: NotificationId;6 conversation: Conversation;7 messages: Message[];8 recipient: User;9 sender: User;10 channel: 'email';11 originalUrl: string;12 };13 type: 'notification.link.clicked';14};
The interfaces of the types presented above are the following:
1type UserId = string;2type ConversationId = string;3type MessageId = string;4type UnixMilliseconds = number;5type ByteSize = number;67type Message = {8 id: MessageId;9 conversationId: ConversationId;10 type: 'UserMessage' | 'SystemMessage';11 senderId: UserId;12 origin: 'web' | 'rest' | 'email' | 'import';13 createdAt: UnixMilliseconds;14 readBy: UserId[];15 text?: string;16 attachment?: File;17 location?: Coordinates;18 content: ContentBlock[];19};2021type Conversation =22{23 id: ConversationId;24 subject: string | null;25 photoUrl: string | null;26 welcomeMessages: string[] | null;27 custom: { [name: string]: string };28 lastMessage: Message | null;29 participants: {30 [id: UserId]: { access: 'ReadWrite' | 'Read'; notify: boolean };31 };32 createdAt: UnixMilliseconds;33};3435type User = {36 id: UserId;37 name: string;38 welcomeMessage: string;39 photoUrl: string;40 role: string;41 email: string[] | null;42 phone: string[] | null;43 custom: { [name: string]: string };44 availabilityText: string;45 locale: string;46 createdAt: UnixMilliseconds;47 pushTokens: { [token_id: string]: true | null } | null;48};4950type File = {51 url: string;52 size: ByteSize;53};5455type Coordinates = [56 number, // latitude57 number // longitude58];
If your server does not receive webhook requests when expected, here are some steps to help debug the issue:
Make sure you have configured webhooks on the "Settings" page of your TalkJS dashboard. Your test app ID and live app ID must be configured separately.
Check the "Live Log" page in your TalkJS dashboard. This shows all the webhook requests that are triggered in your TalkJS app. All events appear in the live log, even if you are not configured to receive them on the settings page. If you don't see the event here, then TalkJS never tried to send a webhook in the first place.
Use webhook.site to create a temporary webhook URL for debugging. Configure this as your webhook URL on the settings page, then trigger a webhook. If you don't see the webhook here, then it is not configured correctly. Check the settings page and the live log. If you see the webhook here, but your server doesn't receive it, keep working through the steps below.
Run your server locally, and try sending a webhook request with Postman or cURL. If that request fails, your webhook endpoint is misconfigured.
Try sending a webhook request to your production server. If that fails, there is an issue with your firewall, routing, or load balancer meaning the webhook never arrives at the production server.
Try sending 1000 requests in a row. If any of them fail, it means you have some kind of rate limiting or anti-bot protection that is blocking the webhook requests from TalkJS. You must disable any bot-prevention on the webhook endpoint, because the TalkJS server sending the request is a bot and can't complete a CAPTCHA.
If everything worked when you sent the requests manually, but your server still does not receive the webhooks from TalkJS, please get in touch via the live chat. Our developers are happy to help investigate the issue for you.