Send a message
const url = 'https://chat.work.optidata.cloud/api/chats/36/messages';const options = { method: 'POST', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"content":"The report is ready for review.","idempotencyHash":"8baf581a-63b4-49b9-bf0c-740d13db6ffa"}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://chat.work.optidata.cloud/api/chats/36/messages \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "content": "The report is ready for review.", "idempotencyHash": "8baf581a-63b4-49b9-bf0c-740d13db6ffa" }'Posts a message into the conversation. A message can carry any combination of text, file attachments, user mentions, a reply to an earlier message, and a poll.
Attachments make the request multipart/form-data: send each file as
files[0][blob], files[0][name], files[0][source] and so on. source
is required per file and says where the file came from —
SOURCE_USER_FILE_SYSTEM for an upload, SOURCE_OPTIWORK_DRIVE for a
file already stored in Drive.
Sending is idempotent when you supply idempotencyHash: a retry with
the same value returns the message created by the first attempt instead of
posting a duplicate. Generate one UUID per message you intend to send and
reuse it across retries — this is the safest way to send from an unreliable
network.
Authorizations
Section titled “Authorizations”Parameters
Section titled “ Parameters ”Path Parameters
Section titled “Path Parameters”Numeric id of the conversation.
Request Bodyrequired
Section titled “Request Bodyrequired”The payload of a new message. Every field is optional on its own, but a
message with neither content nor files carries nothing.
object
The message text.
Client-generated value that makes the send idempotent. A retry with the same value returns the message the first attempt created instead of posting a duplicate.
Client-chosen identifier for the message. Generated by the server when omitted.
Id of the message this one replies to.
Free-text label naming where the message came from. Defaults to
chat.
Whether the text mentions anyone.
UUIDs of the mentioned users. Required when hasUserMentions is
true.
Attachments. Requires a multipart/form-data request when the bytes
travel with the message.
object
The file bytes.
MIME type of the file.
true for a voice message.
Playback length in seconds.
Where the file comes from — an upload, or a file already stored in Drive. Required on every file.
object
A poll to attach to the message.
object
Examples
Plain text
{ "content": "The report is ready for review.", "idempotencyHash": "8baf581a-63b4-49b9-bf0c-740d13db6ffa"}A reply with a mention
{ "content": "@Jane Doe agreed, let us ship it", "replyMessage": 176, "hasUserMentions": true, "mentionedUserUuids": [ "3f1c9a52-4d7e-4b31-9c02-77a1b6e5d840" ]}A poll
{ "content": "When should we meet?", "poll": { "question": "When should we meet?", "is_multiple_answers": false, "options": [ "Monday", "Tuesday", "Wednesday" ] }}The payload of a new message. Every field is optional on its own, but a
message with neither content nor files carries nothing.
object
The message text.
Client-generated value that makes the send idempotent. A retry with the same value returns the message the first attempt created instead of posting a duplicate.
Client-chosen identifier for the message. Generated by the server when omitted.
Id of the message this one replies to.
Free-text label naming where the message came from. Defaults to
chat.
Whether the text mentions anyone.
UUIDs of the mentioned users. Required when hasUserMentions is
true.
Attachments. Requires a multipart/form-data request when the bytes
travel with the message.
object
The file bytes.
MIME type of the file.
true for a voice message.
Playback length in seconds.
Where the file comes from — an upload, or a file already stored in Drive. Required on every file.
object
A poll to attach to the message.
object
Responses
Section titled “ Responses ”The created message. On a retry carrying a known idempotencyHash,
the message created by the first attempt is returned unchanged.
The message carries the send-time serialization
(CreatedMessage): the whole conversation is embedded under chat,
user is the full user record, and the read-side enrichment fields are
absent.
object
The message shape returned by the send endpoints
(POST /chats/{chat}/messages and POST /users/{userUuid}/chats/messages).
It is a different serialization from the Message returned by the read
endpoints: it embeds the whole conversation under chat, serializes user
as the full user record, and omits the read-side enrichment fields
(reactions, meta, is_seen, is_forwarded, is_important,
is_favorite, message_link_id, poll).
object
Author of the message.
The message this one replies to, or null.
Stable identifier of the message.
The client-supplied value that made the send idempotent.
The message text.
The author, serialized as the full user record.
object
Numeric id, used on the conversation and participant routes.
Stable identifier of the user across the Optiwork suite.
Identifier of the company the user belongs to.
null for a person. 0 marks the Optiwork AI assistant, 1 a bot and
2 a contact reached over an external messaging integration.
The colour used for this user’s name in the interface.
Set when the user has been removed from the company.
Details of the linked external-messaging contact, present when the user
is reached over an external messaging integration (type 2); null
for an ordinary person. Its keys depend on the integration, so treat it
as an open object.
A file attached to a message.
object
Alternative identifier accepted by the attachment content endpoints.
Size in bytes.
true for a voice message.
Playback length in seconds, for audio and video.
Thumbnail, when one was generated.
Storage metadata. Its keys depend on where the file is stored, so treat it as an open object.
The conversation the message belongs to, embedded — the conversation’s
own columns plus its participants under users. This embed is unique
to the send responses.
object
Identifier of the company the conversation belongs to.
External identifier, set when the conversation mirrors one in another Optiwork module.
The group or channel name. null on a private conversation, whose
name is the other person.
true for a one-to-one conversation.
What kind of conversation this is: 1 group, 2 private, 3 the
user’s own saved-messages space, 4 a conversation created by another
Optiwork module, 5 channel, 6 a conversation bridged to an
external messaging integration. A freshly created conversation may
report null here until it is classified.
Set on channels; null elsewhere.
How many messages the caller has not seen.
false once the caller has left or been removed.
The caller’s unsent text for this conversation.
The call currently running in the conversation, or null.
One user’s membership of one conversation. It appears as pivot on the
conversation payload and carries everything that is personal to that user:
their role, their read marker and their pin, mute, archive and draft state.
object
One message. type separates what a person wrote (USER) from what the
service recorded about the conversation (SYSTEM) — a rename, a join, a
departure. Render SYSTEM messages as notices, not as chat bubbles; their
data holds the details of what happened.
object
Author of the message.
The message this one replies to, or null.
Stable identifier of the message. This is what
POST /chats/messages/forward takes.
The client-supplied value that made the send idempotent.
The message text.
Structured payload. On a SYSTEM message it describes the event; on a
USER message it carries the mentioned user ids, when there are any.
Where the message came in from — chat for Talk itself, or the name of
the external messaging integration that relayed it.
true when the message was copied here from another conversation.
1 when the caller has favourited this message, 0 otherwise.
How many participants have seen the message.
Position of the message within the conversation.
The trimmed user record embedded in message payloads and search results.
object
Details of the linked external-messaging contact, present when the
embedded user is one (type 2); null otherwise. Open object.
A file attached to a message.
object
Alternative identifier accepted by the attachment content endpoints.
Size in bytes.
true for a voice message.
Playback length in seconds, for audio and video.
Thumbnail, when one was generated.
Storage metadata. Its keys depend on where the file is stored, so treat it as an open object.
Preview of the first link found in the text, when there is one.
Reactions on the message: the ids of the users who left each emoji, keyed by the emoji. Empty when nobody has reacted.
object
A poll carried by a message. total_votes and the per-option
votes_count / voter_ids are computed for every message payload, so a
client can render the result without a second call.
object
Whether a voter may pick more than one option.
object
Display order, starting at 0.
When the user pinned the conversation, or null.
When the mute expires. null on an indefinite mute, and on an
unmuted conversation. Unlike the other timestamps, the value inside
pivot is a plain YYYY-MM-DD HH:MM:SS UTC string, not ISO-8601.
Whether an unread message mentions this user.
Set when the user has left or been removed.
Settings that apply to a conversation as a whole.
object
Participant ceiling, or null when unlimited.
When true, nobody may post.
When true, only administrators may post.
How many unread messages trigger an automatic summary, or null when
the feature is off for this conversation.
The participants, each with their own pivot and status.
object
Numeric id, used on the conversation and participant routes.
Stable identifier of the user across the Optiwork suite.
Identifier of the company the user belongs to.
null for a person. 0 marks the Optiwork AI assistant, 1 a bot and
2 a contact reached over an external messaging integration.
The colour used for this user’s name in the interface.
Set when the user has been removed from the company.
Details of the linked external-messaging contact, present when the user
is reached over an external messaging integration (type 2); null
for an ordinary person. Its keys depend on the integration, so treat it
as an open object.
One user’s membership of one conversation. It appears as pivot on the
conversation payload and carries everything that is personal to that user:
their role, their read marker and their pin, mute, archive and draft state.
object
One message. type separates what a person wrote (USER) from what the
service recorded about the conversation (SYSTEM) — a rename, a join, a
departure. Render SYSTEM messages as notices, not as chat bubbles; their
data holds the details of what happened.
object
Author of the message.
The message this one replies to, or null.
Stable identifier of the message. This is what
POST /chats/messages/forward takes.
The client-supplied value that made the send idempotent.
The message text.
Structured payload. On a SYSTEM message it describes the event; on a
USER message it carries the mentioned user ids, when there are any.
Where the message came in from — chat for Talk itself, or the name of
the external messaging integration that relayed it.
true when the message was copied here from another conversation.
1 when the caller has favourited this message, 0 otherwise.
How many participants have seen the message.
Position of the message within the conversation.
The trimmed user record embedded in message payloads and search results.
object
Details of the linked external-messaging contact, present when the
embedded user is one (type 2); null otherwise. Open object.
A file attached to a message.
object
Alternative identifier accepted by the attachment content endpoints.
Size in bytes.
true for a voice message.
Playback length in seconds, for audio and video.
Thumbnail, when one was generated.
Storage metadata. Its keys depend on where the file is stored, so treat it as an open object.
Preview of the first link found in the text, when there is one.
Reactions on the message: the ids of the users who left each emoji, keyed by the emoji. Empty when nobody has reacted.
object
A poll carried by a message. total_votes and the per-option
votes_count / voter_ids are computed for every message payload, so a
client can render the result without a second call.
object
Whether a voter may pick more than one option.
object
Display order, starting at 0.
When the user pinned the conversation, or null.
When the mute expires. null on an indefinite mute, and on an
unmuted conversation. Unlike the other timestamps, the value inside
pivot is a plain YYYY-MM-DD HH:MM:SS UTC string, not ISO-8601.
Whether an unread message mentions this user.
Set when the user has left or been removed.
Presence information for a user.
object
When the user was last active.
One message. type separates what a person wrote (USER) from what the
service recorded about the conversation (SYSTEM) — a rename, a join, a
departure. Render SYSTEM messages as notices, not as chat bubbles; their
data holds the details of what happened.
object
Author of the message.
The message this one replies to, or null.
Stable identifier of the message. This is what
POST /chats/messages/forward takes.
The client-supplied value that made the send idempotent.
The message text.
Structured payload. On a SYSTEM message it describes the event; on a
USER message it carries the mentioned user ids, when there are any.
Where the message came in from — chat for Talk itself, or the name of
the external messaging integration that relayed it.
true when the message was copied here from another conversation.
1 when the caller has favourited this message, 0 otherwise.
How many participants have seen the message.
Position of the message within the conversation.
The trimmed user record embedded in message payloads and search results.
object
Details of the linked external-messaging contact, present when the
embedded user is one (type 2); null otherwise. Open object.
A file attached to a message.
object
Alternative identifier accepted by the attachment content endpoints.
Size in bytes.
true for a voice message.
Playback length in seconds, for audio and video.
Thumbnail, when one was generated.
Storage metadata. Its keys depend on where the file is stored, so treat it as an open object.
Preview of the first link found in the text, when there is one.
Reactions on the message: the ids of the users who left each emoji, keyed by the emoji. Empty when nobody has reacted.
object
A poll carried by a message. total_votes and the per-option
votes_count / voter_ids are computed for every message payload, so a
client can render the result without a second call.
object
Whether a voter may pick more than one option.
object
Display order, starting at 0.
One message. type separates what a person wrote (USER) from what the
service recorded about the conversation (SYSTEM) — a rename, a join, a
departure. Render SYSTEM messages as notices, not as chat bubbles; their
data holds the details of what happened.
object
Author of the message.
The message this one replies to, or null.
Stable identifier of the message. This is what
POST /chats/messages/forward takes.
The client-supplied value that made the send idempotent.
The message text.
Structured payload. On a SYSTEM message it describes the event; on a
USER message it carries the mentioned user ids, when there are any.
Where the message came in from — chat for Talk itself, or the name of
the external messaging integration that relayed it.
true when the message was copied here from another conversation.
1 when the caller has favourited this message, 0 otherwise.
How many participants have seen the message.
Position of the message within the conversation.
The trimmed user record embedded in message payloads and search results.
object
Details of the linked external-messaging contact, present when the
embedded user is one (type 2); null otherwise. Open object.
A file attached to a message.
object
Alternative identifier accepted by the attachment content endpoints.
Size in bytes.
true for a voice message.
Playback length in seconds, for audio and video.
Thumbnail, when one was generated.
Storage metadata. Its keys depend on where the file is stored, so treat it as an open object.
Preview of the first link found in the text, when there is one.
Reactions on the message: the ids of the users who left each emoji, keyed by the emoji. Empty when nobody has reacted.
object
A poll carried by a message. total_votes and the per-option
votes_count / voter_ids are computed for every message payload, so a
client can render the result without a second call.
object
Whether a voter may pick more than one option.
object
Display order, starting at 0.
Example
{ "message": { "type": "USER", "origin": "chat", "user": { "messenger_color": "#2180f3" }, "chat": { "type": 1, "visibility": "public", "pivot": { "role": "OWNER", "last_message_seen": { "type": "USER", "origin": "chat" } }, "users": [ { "messenger_color": "#2180f3", "pivot": { "role": "OWNER", "last_message_seen": { "type": "USER", "origin": "chat" } } } ], "last_message": { "type": "USER", "origin": "chat" }, "last_message_seen": { "type": "USER", "origin": "chat" } } }}Missing, malformed or expired authentication key.
Authentication failures — and a few permission denials — use an error
key rather than message.
object
Examples
No bearer token sent
{ "error": "JWT passport exception: Missing bearer token in request"}The caller is not a participant of the conversation, or lacks the role the operation requires.
Generic error envelope used by policy, binding and framework failures.
object
Human-readable description of the failure.
Examples
{ "message": "This action is unauthorized."}The resource does not exist, or does not belong to the given conversation.
Generic error envelope used by policy, binding and framework failures.
object
Human-readable description of the failure.
Examples
{ "message": "No query results for model [App\\Models\\Chat\\Chat] 99999999"}The request body or query string failed validation.
object
The first validation message.
Validation messages keyed by field name.
object
Examples
{ "message": "The content field is required.", "errors": { "content": [ "The content field is required." ] }}Rate limit exceeded. Retry after the window resets.
Generic error envelope used by policy, binding and framework failures.
object
Human-readable description of the failure.
Examples
{ "message": "Too Many Attempts."}