Sendmako Docs
v1.0 EN FR ← Dashboard

Sendmako Documentation

Sendmako lets you send and receive WhatsApp messages programmatically. Connect your WhatsApp number via QR code, then use any HTTP client to send messages, manage sessions, receive real-time events via webhooks, and decrypt incoming media files.

5

Session endpoints

8

Message types

4

Webhook events

REST

JSON API

Base URL

All API requests use the following base URL:

BASE_URL/api

All requests and responses use application/json unless stated otherwise (decrypt-media returns binary).

Authentication

All requests must include your API key in the Authorization header.

Header

Authorization: Bearer wsa_your_api_key_here

Generate and manage your API keys in the Dashboard → API Keys page.

Errors & Responses

Sendmako uses standard HTTP status codes. All errors include a message field.

Code Meaning
200OK — request succeeded
201Created — resource created
400Bad Request — missing or invalid fields
401Unauthorized — invalid or missing API key
403Forbidden — plan limit reached
404Not Found — resource does not exist
422Unprocessable — valid request but operation failed
503Service Unavailable — WhatsApp service unreachable

Error response

{
  "success": false,
  "message": "No WhatsApp session found. Connect a number first."
}

Sessions

GET /api/whatsapp/sessions/

List All Sessions

Returns all WhatsApp sessions for the authenticated user with their current live status.

curl -X GET "https://sendmako.com/api/whatsapp/sessions/" \
  -H "Authorization: Bearer wsa_your_api_key"
import requests

r = requests.get(
    "https://sendmako.com/api/whatsapp/sessions/",
    headers={"Authorization": "Bearer wsa_your_api_key"}
)
print(r.json())
const r = await fetch("https://sendmako.com/api/whatsapp/sessions/", {
  headers: { "Authorization": "Bearer wsa_your_api_key" }
});
console.log(await r.json());
 ["Authorization: Bearer wsa_your_api_key"],
    CURLOPT_RETURNTRANSFER => true,
]);
print_r(json_decode(curl_exec($ch), true));

Response

[
  {
    "id": 1,
    "session_id": "user_1",
    "session_name": "Personal",
    "status": "connected",
    "phone_number": "22241857975",
    "qr": null
  }
]
POST /api/whatsapp/sessions/

Create Session

Creates a new WhatsApp session slot. After creation, poll the session status endpoint until status = qr_ready, then display the QR code for scanning. Limited by your subscription plan.

session_namestringOptional. Label for this session (e.g. "Business")
curl -X POST "https://sendmako.com/api/whatsapp/sessions/" \
  -H "Authorization: Bearer wsa_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"session_name": "Business"}'
r = requests.post(
    "https://sendmako.com/api/whatsapp/sessions/",
    headers={"Authorization": "Bearer wsa_your_api_key"},
    json={"session_name": "Business"}
)
print(r.json())
const r = await fetch("https://sendmako.com/api/whatsapp/sessions/", {
  method: "POST",
  headers: {"Authorization":"Bearer wsa_your_api_key","Content-Type":"application/json"},
  body: JSON.stringify({session_name: "Business"})
});
console.log(await r.json());
$ch = curl_init("https://sendmako.com/api/whatsapp/sessions/");
curl_setopt_array($ch, [
    CURLOPT_POST        => true,
    CURLOPT_POSTFIELDS  => json_encode(["session_name" => "Business"]),
    CURLOPT_HTTPHEADER  => ["Authorization: Bearer wsa_your_api_key","Content-Type: application/json"],
    CURLOPT_RETURNTRANSFER => true,
]);
print_r(json_decode(curl_exec($ch), true));

Response 201

{
  "success": true,
  "id": 2,
  "session_id": "user_1_2",
  "session_name": "Business",
  "status": "connecting"
}
GET /api/whatsapp/sessions/{session_id}/

Session Status & QR Code

Returns the live status of a session. When status = qr_ready, the response includes a base64 QR code image to display for scanning.

session_idpathRequired. The session ID (e.g. user_1)
curl -X GET "https://sendmako.com/api/whatsapp/sessions/user_1/" \
  -H "Authorization: Bearer wsa_your_api_key"
r = requests.get(
    "https://sendmako.com/api/whatsapp/sessions/user_1/",
    headers={"Authorization": "Bearer wsa_your_api_key"}
)
print(r.json())
const r = await fetch("https://sendmako.com/api/whatsapp/sessions/user_1/", {
  headers: { "Authorization": "Bearer wsa_your_api_key" }
});
console.log(await r.json());
$ch = curl_init("https://sendmako.com/api/whatsapp/sessions/user_1/");
curl_setopt_array($ch,[CURLOPT_HTTPHEADER=>["Authorization: Bearer wsa_your_api_key"],CURLOPT_RETURNTRANSFER=>true]);
print_r(json_decode(curl_exec($ch),true));

When connected

{"status": "connected", "qr": null}

When QR ready

{"status": "qr_ready", "qr": "data:image/png;base64,iVBO..."}
PATCH /api/whatsapp/sessions/{session_id}/

Rename Session

Updates the display name of a session.

session_namestringRequired. New name for the session
curl -X PATCH "https://sendmako.com/api/whatsapp/sessions/user_1/" \
  -H "Authorization: Bearer wsa_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"session_name": "My Business Line"}'
r = requests.patch(
    "https://sendmako.com/api/whatsapp/sessions/user_1/",
    headers={"Authorization": "Bearer wsa_your_api_key"},
    json={"session_name": "My Business Line"}
)
await fetch("https://sendmako.com/api/whatsapp/sessions/user_1/", {
  method: "PATCH",
  headers: {"Authorization":"Bearer wsa_your_api_key","Content-Type":"application/json"},
  body: JSON.stringify({session_name: "My Business Line"})
});
$ch = curl_init("https://sendmako.com/api/whatsapp/sessions/user_1/");
curl_setopt_array($ch,[CURLOPT_CUSTOMREQUEST=>"PATCH",
  CURLOPT_POSTFIELDS=>json_encode(["session_name"=>"My Business Line"]),
  CURLOPT_HTTPHEADER=>["Authorization: Bearer wsa_your_api_key","Content-Type: application/json"],
  CURLOPT_RETURNTRANSFER=>true]);
print_r(json_decode(curl_exec($ch),true));

Response

{"success": true, "session_name": "My Business Line"}
DELETE /api/whatsapp/sessions/{session_id}/

Delete Session

Disconnects and permanently removes a WhatsApp session. The number will need to reconnect via QR code to be used again.

curl -X DELETE "https://sendmako.com/api/whatsapp/sessions/user_1/" \
  -H "Authorization: Bearer wsa_your_api_key"
requests.delete("https://sendmako.com/api/whatsapp/sessions/user_1/",
    headers={"Authorization": "Bearer wsa_your_api_key"})
await fetch("https://sendmako.com/api/whatsapp/sessions/user_1/", {
  method: "DELETE",
  headers: {"Authorization": "Bearer wsa_your_api_key"}
});
$ch = curl_init("https://sendmako.com/api/whatsapp/sessions/user_1/");
curl_setopt_array($ch,[CURLOPT_CUSTOMREQUEST=>"DELETE",
  CURLOPT_HTTPHEADER=>["Authorization: Bearer wsa_your_api_key"],
  CURLOPT_RETURNTRANSFER=>true]);
print_r(json_decode(curl_exec($ch),true));

Response

{"success": true}

Messages

POST /api/send-message

Send Text Message

Sends a plain text message to a WhatsApp number.

tostringRequired. Recipient number with country code, no + sign (e.g. 22241857975)
typestringRequired. Must be text
textstringRequired. The message content
session_idstringOptional. Session to use. Defaults to your first connected session
curl -X POST "https://sendmako.com/api/send-message" \
  -H "Authorization: Bearer wsa_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "to": "22241857975",
    "type": "text",
    "text": "Hello from Sendmako!"
  }'
import requests

r = requests.post(
    "https://sendmako.com/api/send-message",
    headers={"Authorization": "Bearer wsa_your_api_key"},
    json={"to": "22241857975", "type": "text", "text": "Hello from Sendmako!"}
)
print(r.json())
const r = await fetch("https://sendmako.com/api/send-message", {
  method: "POST",
  headers: {
    "Authorization": "Bearer wsa_your_api_key",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    to: "22241857975",
    type: "text",
    text: "Hello from Sendmako!"
  })
});
console.log(await r.json());
 true,
    CURLOPT_POSTFIELDS  => json_encode([
        "to"   => "22241857975",
        "type" => "text",
        "text" => "Hello from Sendmako!"
    ]),
    CURLOPT_HTTPHEADER  => [
        "Authorization: Bearer wsa_your_api_key",
        "Content-Type: application/json"
    ],
    CURLOPT_RETURNTRANSFER => true,
]);
print_r(json_decode(curl_exec($ch), true));

Response

{"success": true}
POST /api/send-message

Send Image Message

Sends an image from a public URL. Max file size: 16 MB.

tostringRequired. Recipient phone number
typestringRequired. Must be image
imageUrlstringRequired. Public URL of the image (JPEG, PNG, WEBP)
captionstringOptional. Text caption below the image
curl -X POST "https://sendmako.com/api/send-message" \
  -H "Authorization: Bearer wsa_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "to": "22241857975",
    "type": "image",
    "imageUrl": "https://example.com/photo.jpg",
    "caption": "Check this out!"
  }'
r = requests.post(
    "https://sendmako.com/api/send-message",
    headers={"Authorization": "Bearer wsa_your_api_key"},
    json={
        "to": "22241857975", "type": "image",
        "imageUrl": "https://example.com/photo.jpg",
        "caption": "Check this out!"
    }
)
await fetch("https://sendmako.com/api/send-message", {
  method: "POST",
  headers: {"Authorization":"Bearer wsa_your_api_key","Content-Type":"application/json"},
  body: JSON.stringify({
    to: "22241857975", type: "image",
    imageUrl: "https://example.com/photo.jpg",
    caption: "Check this out!"
  })
});
$data = ["to"=>"22241857975","type"=>"image",
         "imageUrl"=>"https://example.com/photo.jpg","caption"=>"Check this out!"];
// ... curl setup same as text example ...
POST/api/send-message

Send Video Message

Sends a video from a public URL. Max file size: 50 MB.

typestringRequired. Must be video
videoUrlstringRequired. Public URL of the video (MP4)
captionstringOptional. Caption text
curl -X POST "https://sendmako.com/api/send-message" \
  -H "Authorization: Bearer wsa_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"to":"22241857975","type":"video","videoUrl":"https://example.com/clip.mp4","caption":"Watch this!"}'
r = requests.post("https://sendmako.com/api/send-message",
    headers={"Authorization":"Bearer wsa_your_api_key"},
    json={"to":"22241857975","type":"video","videoUrl":"https://example.com/clip.mp4"})
await fetch("https://sendmako.com/api/send-message",{method:"POST",
  headers:{"Authorization":"Bearer wsa_your_api_key","Content-Type":"application/json"},
  body:JSON.stringify({to:"22241857975",type:"video",videoUrl:"https://example.com/clip.mp4"})});
$data=["to"=>"22241857975","type"=>"video","videoUrl"=>"https://example.com/clip.mp4"];
POST/api/send-message

Send Audio Message

Sends an audio file. Set voiceNote: true to render as a WhatsApp voice note with waveform. Max: 15 MB.

typestringRequired. Must be audio
audioUrlstringRequired. Public URL of the audio file (MP3, OGG)
voiceNotebooleanOptional. Default false. Set true to display as voice note
curl -X POST "https://sendmako.com/api/send-message" \
  -H "Authorization: Bearer wsa_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"to":"22241857975","type":"audio","audioUrl":"https://example.com/audio.mp3","voiceNote":false}'
r = requests.post("https://sendmako.com/api/send-message",
    headers={"Authorization":"Bearer wsa_your_api_key"},
    json={"to":"22241857975","type":"audio","audioUrl":"https://example.com/audio.mp3","voiceNote":False})
await fetch("https://sendmako.com/api/send-message",{method:"POST",
  headers:{"Authorization":"Bearer wsa_your_api_key","Content-Type":"application/json"},
  body:JSON.stringify({to:"22241857975",type:"audio",audioUrl:"https://example.com/audio.mp3",voiceNote:false})});
$data=["to"=>"22241857975","type"=>"audio","audioUrl"=>"https://example.com/audio.mp3","voiceNote"=>false];
POST/api/send-message

Send Document

Sends a document file (PDF, DOCX, XLSX, etc.). Max file size: 70 MB.

typestringRequired. Must be document
documentUrlstringRequired. Public URL of the document
filenamestringRequired. Filename shown to the recipient (e.g. invoice.pdf)
mimetypestringRequired. MIME type (e.g. application/pdf, application/vnd.openxmlformats-officedocument...)
curl -X POST "https://sendmako.com/api/send-message" \
  -H "Authorization: Bearer wsa_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "to": "22241857975",
    "type": "document",
    "documentUrl": "https://example.com/invoice.pdf",
    "filename": "invoice.pdf",
    "mimetype": "application/pdf"
  }'
r = requests.post("https://sendmako.com/api/send-message",
    headers={"Authorization":"Bearer wsa_your_api_key"},
    json={"to":"22241857975","type":"document",
          "documentUrl":"https://example.com/invoice.pdf",
          "filename":"invoice.pdf","mimetype":"application/pdf"})
await fetch("https://sendmako.com/api/send-message",{method:"POST",
  headers:{"Authorization":"Bearer wsa_your_api_key","Content-Type":"application/json"},
  body:JSON.stringify({to:"22241857975",type:"document",
    documentUrl:"https://example.com/invoice.pdf",
    filename:"invoice.pdf",mimetype:"application/pdf"})});
$data=["to"=>"22241857975","type"=>"document",
       "documentUrl"=>"https://example.com/invoice.pdf",
       "filename"=>"invoice.pdf","mimetype"=>"application/pdf"];
POST/api/send-message

Send Location

Sends a GPS location pin that opens in maps.

typestringRequired. Must be location
latitudefloatRequired. Latitude coordinate
longitudefloatRequired. Longitude coordinate
curl -X POST "https://sendmako.com/api/send-message" \
  -H "Authorization: Bearer wsa_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"to":"22241857975","type":"location","latitude":14.6928,"longitude":-17.4467}'
r = requests.post("https://sendmako.com/api/send-message",
    headers={"Authorization":"Bearer wsa_your_api_key"},
    json={"to":"22241857975","type":"location","latitude":14.6928,"longitude":-17.4467})
await fetch("https://sendmako.com/api/send-message",{method:"POST",
  headers:{"Authorization":"Bearer wsa_your_api_key","Content-Type":"application/json"},
  body:JSON.stringify({to:"22241857975",type:"location",latitude:14.6928,longitude:-17.4467})});
$data=["to"=>"22241857975","type"=>"location","latitude"=>14.6928,"longitude"=>-17.4467];
POST/api/send-bulk

Bulk Send

Send the same message to up to 100 recipients in a single request. A 500ms delay is applied between sends to respect WhatsApp rate limits.

recipientsarrayRequired. Array of phone numbers (max 100)
typestringRequired. Message type (text, image, video, audio, document, location)
text / imageUrl / ...stringRequired fields for the chosen type (same as single send)
curl -X POST "https://sendmako.com/api/send-bulk" \
  -H "Authorization: Bearer wsa_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "recipients": ["22241857975", "221781234567", "237691234567"],
    "type": "text",
    "text": "Hello everyone!"
  }'
r = requests.post(
    "https://sendmako.com/api/send-bulk",
    headers={"Authorization": "Bearer wsa_your_api_key"},
    json={
        "recipients": ["22241857975", "221781234567", "237691234567"],
        "type": "text",
        "text": "Hello everyone!"
    }
)
print(r.json())
const r = await fetch("https://sendmako.com/api/send-bulk", {
  method: "POST",
  headers: {"Authorization":"Bearer wsa_your_api_key","Content-Type":"application/json"},
  body: JSON.stringify({
    recipients: ["22241857975","221781234567","237691234567"],
    type: "text",
    text: "Hello everyone!"
  })
});
console.log(await r.json());
$data = [
    "recipients" => ["22241857975","221781234567","237691234567"],
    "type" => "text",
    "text" => "Hello everyone!"
];
$ch = curl_init("https://sendmako.com/api/send-bulk");
curl_setopt_array($ch,[CURLOPT_POST=>true,CURLOPT_POSTFIELDS=>json_encode($data),
    CURLOPT_HTTPHEADER=>["Authorization: Bearer wsa_your_api_key","Content-Type: application/json"],
    CURLOPT_RETURNTRANSFER=>true]);
print_r(json_decode(curl_exec($ch),true));

Response

{
  "success": true,
  "summary": {"total": 3, "sent": 3, "failed": 0},
  "results": [
    {"to": "22241857975",  "success": true},
    {"to": "221781234567", "success": true},
    {"to": "237691234567", "success": true}
  ]
}
POST/api/decrypt-media

Decrypt Media File

Downloads and decrypts an encrypted WhatsApp media file using the mediaKey received in a webhook payload. Returns the raw decrypted binary with the correct Content-Type header — save it directly as .jpg, .mp4, .mp3, etc.

urlstringRequired. Encrypted media URL from the webhook data.media.url
mediaKeystringRequired. Base64 media key from data.media.mediaKey
mimetypestringRequired. MIME type from data.media.mimetype
directPathstringRecommended. From data.media.directPath
fileEncSha256stringOptional. From data.media.fileEncSha256
curl -X POST "https://sendmako.com/api/decrypt-media" \
  -H "Authorization: Bearer wsa_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "url":           "https://mmg.whatsapp.net/v/t62.7118-24/...",
    "mediaKey":      "tE5cFixjaflyXbwRha8IdwovYHzrjAQ4mz16uhNcR6o=",
    "mimetype":      "image/jpeg",
    "directPath":    "/v/t62.7118-24/...",
    "fileEncSha256": "Dhg75NZE9fSYDm1P6ovnCs7bNXHzWgSbSRPq4Uj7CIc="
  }' \
  --output data
r = requests.post(
    "https://sendmako.com/api/decrypt-media",
    headers={"Authorization": "Bearer wsa_your_api_key"},
    json={
        "url":           "https://mmg.whatsapp.net/v/...",
        "mediaKey":      "tE5cFixjaflyXbwRha8IdwovYHzrjAQ4mz16uhNcR6o=",
        "mimetype":      "image/jpeg",
        "directPath":    "/v/t62.7118-24/...",
        "fileEncSha256": "Dhg75NZE9fSYDm1P6ovnCs7bNX..."
    }
)
with open("image.jpg", "wb") as f:
    f.write(r.content)
const r = await fetch("https://sendmako.com/api/decrypt-media", {
  method: "POST",
  headers: {"Authorization":"Bearer wsa_your_api_key","Content-Type":"application/json"},
  body: JSON.stringify({
    url:           "https://mmg.whatsapp.net/v/...",
    mediaKey:      "tE5cFixjaflyXbwRha8IdwovYHzrjAQ4mz16uhNcR6o=",
    mimetype:      "image/jpeg",
    directPath:    "/v/t62.7118-24/...",
    fileEncSha256: "Dhg75NZE9fSYDm1P6ovnCs7bNX..."
  })
});
const blob = await r.blob();
// blob is the decrypted image — save or display it
$ch = curl_init("https://sendmako.com/api/decrypt-media");
$data = [
    "url"           => "https://mmg.whatsapp.net/v/...",
    "mediaKey"      => "tE5cFixjaflyXbwRha8IdwovYHzrjAQ4mz16uhNcR6o=",
    "mimetype"      => "image/jpeg",
    "directPath"    => "/v/t62.7118-24/...",
    "fileEncSha256" => "Dhg75NZE9fSYDm1P6ovnCs7bNX..."
];
curl_setopt_array($ch,[CURLOPT_POST=>true,CURLOPT_POSTFIELDS=>json_encode($data),
    CURLOPT_HTTPHEADER=>["Authorization: Bearer wsa_your_api_key","Content-Type: application/json"],
    CURLOPT_RETURNTRANSFER=>true]);
file_put_contents("image.jpg", curl_exec($ch));

Response

Binary file with Content-Type: image/jpeg (or appropriate MIME type). Use --output data with cURL or write r.content to a file in Python.

Contacts

GET/api/whatsapp/contacts/

Get All Contacts

Returns all contacts synced from your connected WhatsApp number. Contacts are loaded automatically when the session connects.

session_idqueryOptional. Session to fetch contacts from. Defaults to your first session
curl -X GET "https://sendmako.com/api/whatsapp/contacts/" \
  -H "Authorization: Bearer wsa_your_api_key"
r = requests.get("https://sendmako.com/api/whatsapp/contacts/",
    headers={"Authorization": "Bearer wsa_your_api_key"})
print(r.json())
const r = await fetch("https://sendmako.com/api/whatsapp/contacts/", {
  headers: {"Authorization": "Bearer wsa_your_api_key"}
});
console.log(await r.json());
$ch = curl_init("https://sendmako.com/api/whatsapp/contacts/");
curl_setopt_array($ch,[CURLOPT_HTTPHEADER=>["Authorization: Bearer wsa_your_api_key"],CURLOPT_RETURNTRANSFER=>true]);
print_r(json_decode(curl_exec($ch),true));

Response

{
  "success": true,
  "contacts": [
    {"id": "22241857975@s.whatsapp.net", "phone": "22241857975", "name": "Alassane Diallo"},
    {"id": "221781234567@s.whatsapp.net", "phone": "221781234567", "name": "Fatou Ndiaye"}
  ]
}

Groups

GET/api/groups

List All Groups

Returns all WhatsApp groups the connected account is a member of.

curl -X GET "https://sendmako.com/api/groups" \
  -H "Authorization: Bearer wsa_your_api_key"
r = requests.get("https://sendmako.com/api/groups",
  headers={"Authorization": "Bearer wsa_your_api_key"})
print(r.json())
const r = await fetch("https://sendmako.com/api/groups", {
  headers: {"Authorization": "Bearer wsa_your_api_key"}
});
console.log(await r.json());

Response

{
  "success": true,
  "groups": [
    {
      "id": "120363XXXXXXXXXX@g.us",
      "subject": "Team Sendmako",
      "subjectOwner": "22241857975@s.whatsapp.net",
      "creation": 1711209600,
      "desc": "Official team group",
      "owner": "22241857975@s.whatsapp.net",
      "participants": [...]
    }
  ]
}
POST/api/groups

Create a New Group

Creates a new WhatsApp group with a name and initial list of participants.

namestringRequired. Group name
participantsarrayRequired. Phone numbers to add (e.g. ["22241857975"])
curl -X POST "https://sendmako.com/api/groups" \
  -H "Authorization: Bearer wsa_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"name":"Team Sendmako","participants":["22241857975","221781234567"]}'
r = requests.post("https://sendmako.com/api/groups",
  headers={"Authorization": "Bearer wsa_your_api_key"},
  json={"name": "Team Sendmako", "participants": ["22241857975", "221781234567"]})
print(r.json())
const r = await fetch("https://sendmako.com/api/groups", {
  method: "POST",
  headers: {"Authorization":"Bearer wsa_your_api_key","Content-Type":"application/json"},
  body: JSON.stringify({name:"Team Sendmako",participants:["22241857975","221781234567"]})
});
console.log(await r.json());

Response

{"success": true, "group": {"id": "120363XXXXXXXXXX@g.us", "subject": "Team Sendmako", ...}}
POST/api/send-message

Send Group Message / Message with Mentions

Send a message to a group by passing the group JID (120363XXXXXXXXXX@g.us) as the to field. For mentions, add a mentions array of phone numbers.

curl -X POST "https://sendmako.com/api/send-message" \
  -H "Authorization: Bearer wsa_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "to":   "120363XXXXXXXXXX@g.us",
    "type": "text",
    "text": "Hello group!"
  }'
curl -X POST "https://sendmako.com/api/send-message" \
  -H "Authorization: Bearer wsa_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "to":       "120363XXXXXXXXXX@g.us",
    "type":     "text",
    "text":     "@22241857975 check this out!",
    "mentions": ["22241857975"]
  }'
r = requests.post("https://sendmako.com/api/send-message",
  headers={"Authorization": "Bearer wsa_your_api_key"},
  json={
    "to":       "120363XXXXXXXXXX@g.us",
    "type":     "text",
    "text":     "@22241857975 check this out!",
    "mentions": ["22241857975"]
  })
print(r.json())
GET/api/groups/{groupJid}/metadata

Get Group Metadata

Returns subject, description, creation date, owner, and participant list for a group.

curl "https://sendmako.com/api/groups/120363XXXXXXXXXX%40g.us/metadata" \
  -H "Authorization: Bearer wsa_your_api_key"
r = requests.get("https://sendmako.com/api/groups/120363XXXXXXXXXX@g.us/metadata",
  headers={"Authorization": "Bearer wsa_your_api_key"})
print(r.json())

Response

{
  "success": true,
  "metadata": {
    "id": "120363XXXXXXXXXX@g.us",
    "subject": "Team Sendmako",
    "creation": 1711209600,
    "owner": "22241857975@s.whatsapp.net",
    "desc": "Official team group",
    "participants": [
      {"id": "22241857975@s.whatsapp.net", "admin": "superadmin"},
      {"id": "221781234567@s.whatsapp.net", "admin": null}
    ]
  }
}
GET/api/groups/{groupJid}/participants

Get Group Participants

Returns the list of participants for a specific group. If the list is empty, the initial sync may still be in progress.

curl "https://sendmako.com/api/groups/120363XXXXXXXXXX%40g.us/participants" \
  -H "Authorization: Bearer wsa_your_api_key"
r = requests.get("https://sendmako.com/api/groups/120363XXXXXXXXXX@g.us/participants",
  headers={"Authorization": "Bearer wsa_your_api_key"})
print(r.json())

Response

{
  "success": true,
  "participants": [
    {"id": "22241857975@s.whatsapp.net", "admin": "superadmin"},
    {"id": "221781234567@s.whatsapp.net", "admin": null}
  ]
}
POST/api/groups/{groupJid}/participants/add

Add Group Participants

Adds one or more participants to a group. Requires admin privileges.

participantsarrayRequired. Phone numbers to add (e.g. ["22241857975"])
curl -X POST "https://sendmako.com/api/groups/120363XXXXXXXXXX%40g.us/participants/add" \
  -H "Authorization: Bearer wsa_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"participants":["22241857975","221781234567"]}'
r = requests.post(
  "https://sendmako.com/api/groups/120363XXXXXXXXXX@g.us/participants/add",
  headers={"Authorization": "Bearer wsa_your_api_key"},
  json={"participants": ["22241857975", "221781234567"]})
print(r.json())
POST/api/groups/{groupJid}/participants/remove

Remove Group Participants

Removes one or more participants from a group. Requires admin privileges.

participantsarrayRequired. Phone numbers to remove
curl -X POST "https://sendmako.com/api/groups/120363XXXXXXXXXX%40g.us/participants/remove" \
  -H "Authorization: Bearer wsa_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"participants":["221781234567"]}'
r = requests.post(
  "https://sendmako.com/api/groups/120363XXXXXXXXXX@g.us/participants/remove",
  headers={"Authorization": "Bearer wsa_your_api_key"},
  json={"participants": ["221781234567"]})
print(r.json())
PUT/api/groups/{groupJid}/participants/update

Promote / Demote Participants

Promotes participants to admin or demotes them. Requires admin privileges.

participantsarrayRequired. Phone numbers to promote or demote
actionstringRequired. "promote" or "demote"
curl -X PUT "https://sendmako.com/api/groups/120363XXXXXXXXXX%40g.us/participants/update" \
  -H "Authorization: Bearer wsa_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"participants":["221781234567"],"action":"promote"}'
r = requests.put(
  "https://sendmako.com/api/groups/120363XXXXXXXXXX@g.us/participants/update",
  headers={"Authorization": "Bearer wsa_your_api_key"},
  json={"participants": ["221781234567"], "action": "promote"})
print(r.json())
PUT/api/groups/{groupJid}/settings

Update Group Settings

Updates group subject, description, announce mode (only admins can send), or restrict mode (only admins can edit group info). Requires admin privileges.

subjectstringOptional. New group name
descriptionstringOptional. New group description
announcebooleanOptional. true = only admins can send messages
restrictbooleanOptional. true = only admins can edit group info
curl -X PUT "https://sendmako.com/api/groups/120363XXXXXXXXXX%40g.us/settings" \
  -H "Authorization: Bearer wsa_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"subject":"New Name","description":"Updated desc","announce":true}'
r = requests.put(
  "https://sendmako.com/api/groups/120363XXXXXXXXXX@g.us/settings",
  headers={"Authorization": "Bearer wsa_your_api_key"},
  json={"subject": "New Name", "description": "Updated desc", "announce": True})
print(r.json())
GET/api/groups/invite/{inviteCode}

Get Group Invite Info

Retrieves metadata for a group from its invite code without joining it.

curl "https://sendmako.com/api/groups/invite/AbCdEfGhIjKlMn" \
  -H "Authorization: Bearer wsa_your_api_key"
r = requests.get("https://sendmako.com/api/groups/invite/AbCdEfGhIjKlMn",
  headers={"Authorization": "Bearer wsa_your_api_key"})
print(r.json())
POST/api/groups/invite/accept

Accept Group Invite

Join a group using an invite code.

inviteCodestringRequired. The invite code (not the full URL, just the code part)
curl -X POST "https://sendmako.com/api/groups/invite/accept" \
  -H "Authorization: Bearer wsa_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"inviteCode":"AbCdEfGhIjKlMn"}'
r = requests.post("https://sendmako.com/api/groups/invite/accept",
  headers={"Authorization": "Bearer wsa_your_api_key"},
  json={"inviteCode": "AbCdEfGhIjKlMn"})
print(r.json())
GET/api/groups/{groupJid}/picture

Get Group Profile Picture

Returns the URL of the group's profile picture. Returns null if no picture is set.

curl "https://sendmako.com/api/groups/120363XXXXXXXXXX%40g.us/picture" \
  -H "Authorization: Bearer wsa_your_api_key"
r = requests.get("https://sendmako.com/api/groups/120363XXXXXXXXXX@g.us/picture",
  headers={"Authorization": "Bearer wsa_your_api_key"})
print(r.json())

Response

{"success": true, "picture_url": "https://pps.whatsapp.net/v/..."}
POST/api/groups/{groupJid}/leave

Leave Group

Leave a specific WhatsApp group.

curl -X POST "https://sendmako.com/api/groups/120363XXXXXXXXXX%40g.us/leave" \
  -H "Authorization: Bearer wsa_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{}'
r = requests.post("https://sendmako.com/api/groups/120363XXXXXXXXXX@g.us/leave",
  headers={"Authorization": "Bearer wsa_your_api_key"})
print(r.json())

Response

{"success": true}

Webhooks

Webhook Setup & Signature Verification

Configure your webhook URL in Dashboard → Webhooks. Sendmako sends a signed HTTP POST to your URL for every event.

Verifying Signatures

Every request includes X-Sendmako-Signature: sha256=<hmac>. Verify it to ensure the request is genuine and not forged.

import hmac, hashlib

def verify_signature(payload_body: bytes, signature_header: str, secret: str) -> bool:
    expected = "sha256=" + hmac.new(
        secret.encode(), payload_body, hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, signature_header)

# Django/Flask usage:
# sig = request.headers.get("X-Sendmako-Signature", "")
# if not verify_signature(request.body, sig, "your_webhook_secret"):
#     return HttpResponse(status=403)
const crypto = require('crypto');

function verifySignature(payload, signature, secret) {
  const expected = 'sha256=' + crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
}

// Express usage:
// app.post('/webhook', (req, res) => {
//   const sig = req.headers['x-sendmako-signature'];
//   if (!verifySignature(JSON.stringify(req.body), sig, 'your_secret')) {
//     return res.sendStatus(403);
//   }
// });
function verifySignature(string $payload, string $signature, string $secret): bool {
    $expected = 'sha256=' . hash_hmac('sha256', $payload, $secret);
    return hash_equals($expected, $signature);
}

// Usage:
// $payload = file_get_contents('php://input');
// $sig     = $_SERVER['HTTP_X_SENDMAKO_SIGNATURE'] ?? '';
// if (!verifySignature($payload, $sig, 'your_webhook_secret')) {
//     http_response_code(403); exit;
// }

Webhook Events Reference

All events use the same envelope. The data object varies per event.

Common envelope

{
  "event":      "message.received",
  "timestamp":  "2026-03-23T17:00:00Z",
  "session_id": "user_1",
  "data":       { ... }
}
message.received

Fired when a new incoming message arrives on your number.

{
  "event": "message.received",
  "timestamp": "2026-03-23T17:00:00Z",
  "session_id": "user_1",
  "data": {
    "message_id":  "3EB043CFB548568C7532C1",
    "from":        "22241857975",
    "sender_name": "Alassane Diallo",
    "type":        "conversation",
    "body":        "Hello!",
    "timestamp":   1711209600,

    // For media messages (imageMessage, videoMessage, audioMessage, documentMessage):
    "media": {
      "url":           "https://mmg.whatsapp.net/v/...",
      "mimetype":      "image/jpeg",
      "mediaKey":      "tE5cFixjaflyXbwRha8IdwovYHzrjAQ4mz16uhNcR6o=",
      "fileEncSha256": "Dhg75NZE9fSYDm1P6ovnCs7bNXHzWgSbSRPq4Uj7CIc=",
      "directPath":    "/v/t62.7118-24/...",
      "fileSize":      "122866",
      "width":         905,
      "height":        1280,
      "duration":      30
    }
  }
}
message.status

Fired when a sent message is delivered or read by the recipient.

{
  "event": "message.status",
  "timestamp": "2026-03-23T17:01:00Z",
  "session_id": "user_1",
  "data": {
    "message_id": "3EB043CFB548568C7532C1",
    "to":         "22241857975",
    "status":     "delivered"   // "delivered" or "read"
  }
}
session.connected

Fired when a WhatsApp number successfully connects after QR scan.

{
  "event": "session.connected",
  "timestamp": "2026-03-23T17:00:00Z",
  "session_id": "user_1",
  "data": {
    "phone_number": "22241857975"
  }
}
session.disconnected

Fired when a session drops — either by logout or connection loss.

{
  "event": "session.disconnected",
  "timestamp": "2026-03-23T17:05:00Z",
  "session_id": "user_1",
  "data": {
    "reason": "logged_out"   // "logged_out" or "connection_lost"
  }
}