Webhooks
Thursday, January 14, 2021 4:56 AMTable of Contents
Introduction
When webhooks are enabled in 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.
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.
Webhook events
TalkJS supports following webhook events:
- user.created: Occurs when a user is created in TalkJS backend.
- user.updated: Occurs when a user is updated in TalkJS backend.
- message.sent: Occurs when a message is sent in a conversation.
- message.read: Occurs when another user in the same conversation receives the message in the chat UI. This event will get sent at most once for every member of a conversation other than the sender.
-
message.updated: 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
). - message.deleted: Occurs when the message has been deleted.
- conversation.deleted: Occurs when a conversation is deleted via the REST API
-
notification.triggered: 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.
- notification.sent: 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.
- notification.delivered - Occurs when a email was successfully delivered.
- notification.bounced - Occurs when an email was not successfully delivered. It is triggered for bounces and spam complaints that resulted from outgoing email.
- notification.opened - 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.
- notification.link.clicked - Occurs when a user clicks a link inside an email notification.
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.
You can see examples on how to use TalkJS Webhooks in our examples repository on GitHub.
Event structure
All events have the same top-level structure, as shown below. Only the structure of the data
field differs for every type
:
type Event = {
id: string;
createdAt: number; // UNIX timestamp in milliseconds
data: any;
type: string;
};
The supported webhook events are structured below.
User created
The structure for the user.created
event is as follows:
type UserCreatedEvent = {
id: string;
createdAt: UnixMilliseconds;
data: {
user: User;
}
}
User updated
The structure for the user.updated
event is as follows:
type UserUpdatedEvent = {
id: string;
createdAt: UnixMilliseconds;
data: {
user: User;
}
type: "user.updated";
}
Conversation deleted
The structure for the conversation.deleted
event is as follows:
type ConversationDeletedEvent = {
id: string;
createdAt: UnixMilliseconds;
data: {
conversation: Conversation;
}
type: "conversation.deleted";
};
Message sent
The structure for the message.sent
event is as follows:
type MessageSentEvent = {
id: string;
createdAt: UnixMilliseconds;
data: {
sender: User;
conversation: Conversation;
message: Message;
}
type: "message.sent";
};
Message read
The structure for the message.read
event is as follows:
type MessageReadEvent = {
id: string;
createdAt: UnixMilliseconds;
data: {
recipient: User;
conversation: Conversation;
message: Message;
};
type: "message.read";
};
Message updated
The structure for the message.updated
event is as follows:
type MessageUpdatedEvent = {
id: string;
createdAt: UnixMilliseconds;
data: {
sender: User;
conversation: Conversation;
message: Message;
};
type: "message.updated";
};
Message deleted
The structure for the message.deleted
event is as follows:
type MessageDeleted = {
id: string;
createdAt: UnixMilliseconds;
data: {
sender: User | null;
conversation: Conversation;
message: Message;
};
type: "message.deleted";
};
Notification triggered
The structure for the notification.triggered
event is as follows:
type NotificationTriggered = {
id: string;
createdAt: UnixMilliseconds;
data: {
notificationId: string;
recipient: User;
sender: User;
conversation: Conversation;
messages: Message[];
};
type: "notification.triggered";
};
Notification sent
The structure for the notification.sent
event is as follows:
type NotificationSent = {
id: string;
createdAt: UnixMilliseconds;
data: {
notificationId: string;
recipient: User;
sender: User;
conversation: Conversation;
messages: Message[];
channel: "email" | "sms";
};
type: "notification.sent";
};
Notification delivered
The structure for the notification.delivered
event is as follows:
type NotificationDelivered = {
id: string;
createdAt: UnixMilliseconds;
data: {
notificationId: NotificationId;
conversation: Conversation;
messages: Message[];
recipient: User;
sender: User;
channel: "email";
};
type: "notification.delivered";
}
Notification bounced
The structure for the notification.bounced
event is as follows:
type NotificationBounced = {
id: string;
createdAt: UnixMilliseconds;
data: {
notificationId: NotificationId;
conversation: Conversation;
messages: Message[];
recipient: User;
sender: User;
channel: "email";
};
type: "notification.bounced";
}
Notification opened
The structure for the notification.opened
event is as follows:
type NotificationOpened = {
id: string;
createdAt: UnixMilliseconds;
data: {
notificationId: NotificationId;
conversation: Conversation;
messages: Message[];
recipient: User;
sender: User;
channel: "email"
};
type: "notification.opened";
}
Notification link clicked
The structure for the notification.link.clicked
event is as follows:
type NotificationLinkClicked = {
id: string;
createdAt: UnixMilliseconds;
data: {
notificationId: NotificationId;
conversation: Conversation;
messages: Message[];
recipient: User;
sender: User;
channel: "email";
originalUrl: string;
};
type: "notification.link.clicked";
}
Interfaces
The interfaces of the types presented above are the following:
type UserId = string;
type ConversationId = string;
type MessageId = string;
type UnixMilliseconds = number;
type ByteSize = number;
type Message = {
id: MessageId;
conversationId: ConversationId;
type: "UserMessage" | "SystemMessage";
readBy: UserId[];
senderId: UserId;
text?: string;
attachment?: File;
origin: "web" | "rest" | "email" | "import";
location?: Coordinates;
createdAt: UnixMilliseconds;
};
type Conversation = {
id: ConversationId;
subject?: string;
topicId?: string;
photoUrl?: string;
welcomeMessages?: string[];
custom?: {[name: string]: string };
participants: {
[id: UserId]: {access: "ReadWrite" | "Read", notify: boolean}
};
createdAt: UnixMilliseconds;
}
type User = {
id: UserId;
name: string;
welcomeMessage?: string;
photoUrl?: string;
headerPhotoUrl?: string;
role?: string;
email?: string[] | null;
phone?: string[] | null;
custom?: {[name: string]: string };
availabilityText?: string;
locale?: string;
createdAt: UnixMilliseconds;
};
type File = {
url: string;
size: ByteSize;
}
type Coordinates = [
number, // latitude
number // longitude
]