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:
    1. 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
    2. 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";
}

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
]