Send messages
Learn how to send messages on WhatsApp using Unipile API.
There is two scenarios where you want to send messages:
- You don't have yet a conversation with the recipient(s), so you create a new chat and send the first message using Start a Chat.
- You already have a conversation with the recipient(s), so you send a message in an existing chat using Send a Message.
Spam detectionIf you initiate too many new conversations without receiving responses or if there are a high number of signals of spam/block, it may temporarily restrict your account.
Incorporate realistic delays between messages to mimic human behavior. Avoid sending messages with intervals shorter than 10-20 seconds to align with natural conversation patterns.
Start a new conversation
Find User IDs
For WhatsApp, user IDs follow a convenient format based on their phone number:
- Include the full international number (with country code).
- Remove any spaces, + signs, or formatting characters.
- Append
@s.whatsapp.netto the end.
For example:
+33 44 55 66 77 88 → [email protected]
Start an individual chat
To initiate a conversation with another user, use the Start a Chat method and provide the recipient’s User ID.
WhatsApp allows only one individual chat per user. Attempting to start a chat with a user who already has an existing conversation will simply send a message in that existing chat.
const { data, error } = await messagingApi.startChat({
path: {
account_id: "acc_123456789",
},
body: {
user_ids: ["[email protected]"],
text: "This is the first message in the chat",
},
});chat = messaging_api.start_chat(
"acc_123456789",
{
"user_ids": ["[email protected]"],
"text": "This is the first message in the chat",
},
)
Note about chat idsYou may notice that the
chat_idreturned in the response is the same as the recipient’s user ID.
This is expected behavior: for individual chats, WhatsApp uses the recipient’s ID as the chat identifier.
Start a group chat
To create a new group chat, use the Start a Chat endpoint and provide a list of members in user_ids.
The Unipile API performs two actions in one request:
- It creates the group by inviting all members.
- It sends the first message to the group.
If you want to create the group without sending a message, simply set the text field to an empty string.
You can then send a message later using the Send a Message method.
You may optionally specify a group name. If not provided, the group name will be automatically generated from the names of the initial members.
const { data, error } = await messagingApi.startChat({
path: {
account_id: "acc_123456789",
},
body: {
user_ids: ["[email protected]", "[email protected]"],
text: "This is the first message in the chat",
name: "Group Chat Name",
},
});chat = messaging_api.start_chat(
"acc_123456789",
{
"user_ids": [
"[email protected]",
"[email protected]",
],
"text": "This is the first message in the chat",
"name": "Group Chat Name",
},
)Send a message in a conversation
To send a message in an existing chat, use the Send a Message method and provide the ID of the Chat to send the message in. See Retrieve chats & messages to find chat IDs.
const { data, error } = await messagingApi.sendMessage({
path: {
account_id: "acc_123456789",
chat_id: "chat_id",
},
body: {
text: "Hello, world!",
},
});message = messaging_api.send_message(
"chat_id",
"acc_123456789",
{"text": "Hello, world!"},
)curl --request POST \
--url https://api.unipile.com/v2/account_id/chats/chat_id/messages/send \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '
{
"text": "Hello, World!"
}
'Format text messages
WhatsApp formatting feature is fully supported.
Send attachments
WhatsApp only allows a single attachment per message.
- If you send multiple attachments in one API call, Unipile will automatically send them as separate messages, one per attachment.
- Any
textcontent provided in the request will be sent as an additional message after all the attachments. - If you want each attachment to have its own caption, you must call Send a Message once per attachment, including its caption in the
textfield.
Provider limitationsWhatsApp enforces specific size and format restrictions for attachments. Refer to the WhatsApp Help Center for the latest limits.
The following examples use Send a Message but you can send attachments with Start a Chat as well.
Send Images & Videos
To send an image or video with an inline preview, call the Send a Message method and include files in the attachments array.
Any file with a MIME type starting with image/ or video/ will be sent as media with an inline preview in the chat.
const imageFile = await readFile('image.png');
const videoFile = await readFile('video.mp4');
const { data, error } = await messagingApi.sendMessage({
path: {
account_id: "acc_123456789",
chat_id: "chat_id",
},
body: {
text: '',
attachments: [
{
content: imageFile.toString('base64'),
content_type: 'image/png',
filename: 'image.png',
},
{
content: videoFile.toString('base64'),
content_type: 'video/mp4',
filename: 'video.mp4',
},
],
},
});import base64
with open("image.png", "rb") as f:
image_file = base64.b64encode(f.read()).decode("utf-8")
with open("video.mp4", "rb") as f:
video_file = base64.b64encode(f.read()).decode("utf-8")
message = messaging_api.send_message(
"chat_id",
"acc_123456789",
{
"text": "",
"attachments": [
{
"content": image_file,
"content_type": "image/png",
"filename": "image.png",
},
{
"content": video_file,
"content_type": "video/mp4",
"filename": "video.mp4",
},
],
},
)curl --request POST \
--url https://api.unipile.com/v2/account_id/chats/chat_id/messages/send \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '
{
"attachments": [
{
"content": "base64",
"content_type": "image/png",
"filename": "image.png",
},
{
"content": "base64",
"content_type": "video/mp4",
"filename": "video.mp4",
}
]
}
'Send Documents
To send a document, use the Send a Message method and provide the file as an attachment.
In the official WhatsApp apps, you can choose to send images or videos as documents (which appear without a preview).
Unipile does not support this mode — all images and videos are always sent as media with inline previews as mentioned in the previous section.
const file = await readFile('document.pdf');
const { data, error } = await messagingApi.sendMessage({
path: {
account_id: "acc_123456789",
chat_id: "chat_id",
},
body: {
text: '',
attachments: [
{
content: file.toString('base64'),
content_type: 'application/pdf',
filename: 'document.pdf',
},
],
},
});import base64
with open("document.pdf", "rb") as f:
file = base64.b64encode(f.read()).decode("utf-8")
message = messaging_api.send_message(
"chat_id",
"acc_123456789",
{
"text": "",
"attachments": [
{
"content": file,
"content_type": "application/pdf",
"filename": "document.pdf",
}
],
},
)curl --request POST \
--url https://api.unipile.com/v2/account_id/chats/chat_id/messages/send \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '
{
"attachments": [
{
"content": "base64",
"content_type": "application/pdf",
"filename": "document.pdf",
}
]
}
'Send a voice message
To send a voice message, call the Send a Message method and attach the audio file with the voice_note property set to true so the audio will appear in the chat as an inline, playable voice message.
const file = await readFile('voice.mp3');
const { data, error } = await messagingApi.sendMessage({
path: {
account_id: "acc_123456789",
chat_id: "chat_id",
},
body: {
text: '',
attachments: [
{
content: file.toString('base64'),
content_type: 'audio/mpeg',
filename: 'voice.mp3',
voice_note: true,
},
],
},
});import base64
with open("voice.mp3", "rb") as f:
file = base64.b64encode(f.read()).decode("utf-8")
message = messaging_api.send_message(
"chat_id",
"acc_123456789",
{
"text": "",
"attachments": [
{
"content": file,
"content_type": "audio/mpeg",
"filename": "voice.mp3",
"voice_note": True,
}
],
},
)curl --request POST \
--url https://api.unipile.com/v2/account_id/chats/chat_id/messages/send \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '
{
"attachments": [
{
"content": "base64",
"content_type": "audio/mpeg",
"filename": "voice.mp3",
"voice_note": true
}
]
}
'Reply to a specific message
To send a message as a reply to a specific message (to see the replied message embedded), use the Send a Message method and provide the ID of the message to reply to as quote_id.
const { data, error } = await messagingApi.sendMessage({
path: {
account_id: "acc_123456789",
chat_id: "chat_id",
},
body: {
text: "This is a reply to a message",
quote_id: "message_id",
},
});message = messaging_api.send_message(
"chat_id",
"acc_123456789",
{
"text": "This is a reply to a message",
"quote_id": "message_id",
},
)curl --request POST \
--url https://api.unipile.com/v2/account_id/chats/chat_id/messages/send \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '
{
"quote_id": "message_id",
"text": "This is a reply to a message"
}
'Forward a message to another Chat
To forward a message into another chat, use the Forward a Message method and provider the ID of the chat to forward the message to.
In WhatsApp, forwarded messages are not embedded into another one, but they are sent as a new message flagged as forwarded, so filling the text field has no effect.
const { data, error } = await messagingApi.forwardMessage({
path: {
account_id: "acc_123456789",
chat_id: "chat_id",
message_id: "message_id",
},
body: {
chat_id: "destination_chat_id",
},
});messaging_api.forward_message(
"chat_id",
"message_id",
"acc_123456789",
{"chat_id": "destination_chat_id"},
)curl --request POST \
--url https://api.unipile.com/v2/account_id/chats/chat_id/messages/message_id/forward \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '
{
"chat_id": "destination_chat_id",
}
'Be notified about read messages
To be notified when a sent message is read by someone in the conversations, Configure a webhook that listen for message.receipt.read events.
Updated about 1 month ago