import { PeriskopeApi } from '@periskope/periskope-client';
const client = new PeriskopeApi({
authToken: 'YOUR_API_KEY',
phone: '919876543210', // the phone to act with (x-phone)
});
async function main() {
const response = await client.messages.sendMessageSync({
chat_id: '911111111111@c.us',
});
console.log(response);
}
main();curl -X POST 'https://api.periskope.app/v1/message/send-sync' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'x-phone: 919876543210' \
-H 'Content-Type: application/json' \
-d '{
"chat_id": "911111111111@c.us"
}'{
"status": "sent",
"unique_id": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
"message": {
"message_id": "true_911111111111@c.us_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
"unique_id": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
"org_id": "00000000-0000-0000-0000-000000000000",
"org_phone": "911111111111@c.us",
"chat_id": "120363000000000000@g.us",
"body": "Hello World",
"message_type": "chat",
"timestamp": "2026-01-15T09:30:00+00:00",
"from_me": true,
"ack": "3",
"performed_by": "api",
"sender_phone": "911111111111@c.us",
"quoted_message_id": null,
"broadcast_id": null,
"is_deleted": null,
"media": {
"path": "https://example.com/files/image.png",
"mimetype": "image/png",
"filename": "image.png",
"size": 24576,
"dimensions": {
"width": null,
"height": null,
"ar": null
},
"thumbnail": null
},
"mentioned_ids": [],
"prev_body": null,
"sent_message_id": "00000000-0000-0000-0000-000000000000",
"delivery_info": {
"delivered": {
"911111111111@c.us": 1737967705196
},
"read": {
"911111111111@c.us": 1737967704763
},
"pending": [],
"delivered_count": 1,
"read_count": 1
},
"poll_info": {},
"poll_results": {},
"flag_status": null,
"updated_at": "2026-01-15T09:35:38.221+00:00",
"reactions": [
{
"reaction_id": "true_911111111111@c.us_AAAAAAAAAAAAAAAAAAAAAA",
"message_id": "true_911111111111@c.us_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
"unique_id": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
"chat_id": "911111111111@c.us",
"org_id": "00000000-0000-0000-0000-000000000000",
"org_phone": "911111111111@c.us",
"sender_id": "911111111111@c.us",
"reaction": "😄",
"read": true,
"timestamp": "2026-01-15T09:31:57.008+00:00"
}
]
}
}{
"code": "ERROR",
"message": "The phone is off or its server is unreachable — or the send failed within the wait window (code MESSAGE_SEND_FAILED): WhatsApp rejected the message (ack -1), or the phone gave up before it reached WhatsApp, for example because the number is not on WhatsApp. details carry unique_id, org_phone, chat_id, ack -1 and the failure reason when one was reported, plus message_id when a message record exists. Retry from another phone via the x-phone header.",
"status": 400
}{
"code": "UNAUTHORIZED_ERROR",
"message": "Invalid bearer auth token",
"status": 401
}{
"code": "NOT_FOUND_ERROR",
"message": "x-phone omitted and the group chat was not found on any phone of the org",
"status": 404
}{
"code": "VALIDATION_ERROR",
"message": "Request validation failed",
"status": 422,
"fields": {
"body.chat_id": {
"message": "chat_id is required"
}
}
}{
"code": "RATE_LIMIT_ERROR",
"message": "You can only make 100 requests per second",
"status": 429
}{
"code": "UNKNOWN_ERROR",
"message": "Internal server error",
"status": 500
}Send Sync Message
Sends a message like POST /message/send (including automatic phone selection for group chats when x-phone is omitted), then waits up to sync_timeout seconds (default 20) for WhatsApp to accept or reject the message. When accepted in time the response carries the sent message record (status sent). When the send fails in time — WhatsApp rejected it (ack -1), or the phone gave up before it reached WhatsApp, for example because the number is not on WhatsApp — the request fails with a 400 MESSAGE_SEND_FAILED error carrying the reason, so the caller can retry — typically from another phone via the x-phone header. Otherwise it falls back to the asynchronous queued response.
import { PeriskopeApi } from '@periskope/periskope-client';
const client = new PeriskopeApi({
authToken: 'YOUR_API_KEY',
phone: '919876543210', // the phone to act with (x-phone)
});
async function main() {
const response = await client.messages.sendMessageSync({
chat_id: '911111111111@c.us',
});
console.log(response);
}
main();curl -X POST 'https://api.periskope.app/v1/message/send-sync' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'x-phone: 919876543210' \
-H 'Content-Type: application/json' \
-d '{
"chat_id": "911111111111@c.us"
}'{
"status": "sent",
"unique_id": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
"message": {
"message_id": "true_911111111111@c.us_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
"unique_id": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
"org_id": "00000000-0000-0000-0000-000000000000",
"org_phone": "911111111111@c.us",
"chat_id": "120363000000000000@g.us",
"body": "Hello World",
"message_type": "chat",
"timestamp": "2026-01-15T09:30:00+00:00",
"from_me": true,
"ack": "3",
"performed_by": "api",
"sender_phone": "911111111111@c.us",
"quoted_message_id": null,
"broadcast_id": null,
"is_deleted": null,
"media": {
"path": "https://example.com/files/image.png",
"mimetype": "image/png",
"filename": "image.png",
"size": 24576,
"dimensions": {
"width": null,
"height": null,
"ar": null
},
"thumbnail": null
},
"mentioned_ids": [],
"prev_body": null,
"sent_message_id": "00000000-0000-0000-0000-000000000000",
"delivery_info": {
"delivered": {
"911111111111@c.us": 1737967705196
},
"read": {
"911111111111@c.us": 1737967704763
},
"pending": [],
"delivered_count": 1,
"read_count": 1
},
"poll_info": {},
"poll_results": {},
"flag_status": null,
"updated_at": "2026-01-15T09:35:38.221+00:00",
"reactions": [
{
"reaction_id": "true_911111111111@c.us_AAAAAAAAAAAAAAAAAAAAAA",
"message_id": "true_911111111111@c.us_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
"unique_id": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
"chat_id": "911111111111@c.us",
"org_id": "00000000-0000-0000-0000-000000000000",
"org_phone": "911111111111@c.us",
"sender_id": "911111111111@c.us",
"reaction": "😄",
"read": true,
"timestamp": "2026-01-15T09:31:57.008+00:00"
}
]
}
}{
"code": "ERROR",
"message": "The phone is off or its server is unreachable — or the send failed within the wait window (code MESSAGE_SEND_FAILED): WhatsApp rejected the message (ack -1), or the phone gave up before it reached WhatsApp, for example because the number is not on WhatsApp. details carry unique_id, org_phone, chat_id, ack -1 and the failure reason when one was reported, plus message_id when a message record exists. Retry from another phone via the x-phone header.",
"status": 400
}{
"code": "UNAUTHORIZED_ERROR",
"message": "Invalid bearer auth token",
"status": 401
}{
"code": "NOT_FOUND_ERROR",
"message": "x-phone omitted and the group chat was not found on any phone of the org",
"status": 404
}{
"code": "VALIDATION_ERROR",
"message": "Request validation failed",
"status": 422,
"fields": {
"body.chat_id": {
"message": "chat_id is required"
}
}
}{
"code": "RATE_LIMIT_ERROR",
"message": "You can only make 100 requests per second",
"status": 429
}{
"code": "UNKNOWN_ERROR",
"message": "Internal server error",
"status": 500
}Authorizations
Your Periskope API token, sent as Authorization: Bearer <token>. Generate one from the Periskope dashboard under Settings → API & Webhooks. API access requires an active Pro or Enterprise plan.
Headers
Phone to send from: country code + number without symbols or spaces (e.g. 911111111111), or a phone_id (phone-xxxxxxxxxxxx). Required for 1-1 chats. For group chats it can be omitted — a connected phone that is in the group is selected automatically, within the token's phone scopes.
"919876543210"
Body
Chat to send the message to. For group chats, the chat_id ending with @g.us; for 1-1 chats, country code + number of the contact, optionally suffixed with @c.us (e.g. 911111111111 or 911111111111@c.us).
1"911111111111@c.us"
The text body of the message, or the caption when media is provided. Supports the basic WhatsApp markdown formatting (bold, italic, strikethrough, monospace).
"Hello World"
Media to send — a document, image, video, audio file or voice note. Provide either a public url or base64 filedata. The message text, when given, becomes the caption.
Show child attributes
Show child attributes
Poll to send instead of a plain message. The resulting message has message_type poll_creation.
Show child attributes
Show child attributes
message_id of an existing message in the chat to reply to. The sent message quotes it.
"true_911111111111@c.us_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
Additional sending options
Show child attributes
Show child attributes
How long to wait for the send confirmation, in seconds (1-60). When the message is not confirmed within this window the response falls back to the asynchronous shape. Defaults to 20.
1 <= x <= 6020
Response
The sent message when WhatsApp accepted it within sync_timeout, otherwise the queued response
- Option 1
- Option 2
The sent message when WhatsApp accepted it within sync_timeout, otherwise the asynchronous queued response
WhatsApp accepted the message within the wait window (message.ack is 1 or higher)
sent Provisional id assigned when the message was queued
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
A WhatsApp message record. Responses may include additional raw fields of the underlying record (id, author, links, location, vcards, is_forwarded, has_media, message_ticket_id, ...).
Show child attributes
Show child attributes
Was this page helpful?