Messages are a sub-resource of conversations.

Path: /v1/{appId}/conversations/{conversationId}/messages
Methods:GET, POST

Sending messages

There are currently two types of messages you can send to a conversation. You can either send messages to a conversation on behalf of one user or on behalf of your app. Users in the conversation must have had their data synchronized first.

The request payload of this endpoint must always be an array, even if you send only one message. This way it's possible for you to send a batch of consecutive messages in a single request. It's also possible to combine user messages and system messages in one request.

Sending on behalf of a user

You can programmatically send messages on behalf of a user in a conversation. The behavior is identical to that when sending messages via the UI; notifications are triggered based on the participating user's role. UserMessage also supports sending attachments and locations. See Sending Files.


    "text": string,
    "sender": string,
    "type": "UserMessage"

sender has to be a participant in the conversation. type must be "UserMessage" when sender is provided or the request fails.

System Messages

System Messages are messages which are not sent by a participant, but programmatically by your application. A SystemMessage is displayed differently in the UI, and doesn't trigger notifications for any user in the conversation. You are expected to handle these notifications in your application if needed. These messages currently doesn't support attachments or locations.

System Messages support formatting.

Some example use cases in a marketplace for System Messages are 'order received' and 'payment failed', but these can be anything from payment confirmations to "User left the group" notifications.


    "text": string,
    "type": "SystemMessage"

text field supports the same syntax as Subjects. sender must not be provided when sending system messages.

Listing messages from a conversation

You can list messages written in conversations by users in TalkJS. In order to do that you need to call the following endpoint:

GET /v1/{appId}/conversations/{conversationId}/messages
Limits and pagination

Similarly to other list requests, pagination and limits are applicable to listing messages.


Getting messages

Alternatively you can check the status of a certain message from a conversation (e.g., after some time to read a readBy status), by calling:

GET /v1/{appId}/conversations/{conversationId}/messages/{messageId}

Sending files

Sending files (images, documents, etc) is a two-step process. First, you upload the file to our servers. Then, you send a message in the same way as a text message, but with a reference to the uploaded file.

1. Upload a file

You upload a file using the files resource:

Path: /v1/{appId}/files

This is the only resource on the TalkJS REST API that does not accept a JSON payload. Instead, send multipart/form-data formatted data with a single value called file that contains the file.

This is the usual way files are uploaded over HTTP. Check the docs of your favorite HTTP client for information on how to upload files with it. For example: JavaScript, Python (Requests), PHP, Ruby (RestClient).

This resource returns a JSON object with a single value, attachmentToken:

    "attachmentToken": "L0oQOg5DVENGFVQZABpOQVNRCxs...EFFbHxhiXVEYUBw"

2. Send a message with an attachment

Now, use the usual messages resource to send a message, but replace the text field by an attachmentToken field:


    "attachmentToken": "L0oQOg5DVENGFVQZABpOQVNRCxs...EFFbHxhiXVEYUBw",
    "sender": "1",
    "type": "UserMessage"

Troubleshooting file uploads

I'm getting "400 Bad Request"

  • Ensure that you're using a "multipart" file upload, and not just sending JSON or x-form-urlencoded formatted data. Find your HTTP library's "file upload" reference on how to enable this.
  • Check if your code is explicitly setting a Content-type: multipart/form-data somewhere. If so, remove it. Most HTTP libraries will autogenerate this header when uploading files, and they will usually set the header to something like Content-Type: multipart/form-data; boundary=a3eb698cd620e766f278e52886c572edcb0e4a97. Without the boundary, TalkJS can't parse the data.
  • For TalkJS to be able to detect that you're uploading a file, the file needs to have a filename directive set. Many HTTP libraries do this automatically. If not, there will be a way for you to set it explicitly. Doing so causes the library to generate a header such as Content-Disposition: form-data; name="file"; filename="image.jpg" inside the HTTP body. You shouldn't need to set this header manually; find a facility in your HTTP library to give an uploaded file a filename.

I'm getting "Invalid JSON"

The TalkJS REST API has a known bug that, when it cannot understand the request, it returns this message. That's usually correct since the entire API is JSON-based, but it does not hold for file uploads. Do not try to send valid JSON; instead, follow the three steps suggested above.

Deprecated: Sending messages to a conversation without a unique identifier

Path: /v1/{appId}/conversations/participants={userIds}/messages
Methods:GET, POST

Note: Do not use this endpoint in new projects. Instead, choose an appropriate conversation ID for your situation.

If your JavaScript code uses the getOrStartConversation method to start converstions then you need to use this endpoint. getOrStartConversation generates an internal conversation ID and this endpoint allows you to find (or create) a conversation without specifying this ID.

Use the same payload as above. See Conversations for more info on the URL structure.