Send API
The original message-sending endpoint, used by production integrations today and fully supported. New integrations should prefer POST /v1/messages on the REST API: it drives the same sending engine with the same request body, and returns the standard v1 envelope.
Webhook & API Add-on · $29/month · Requires Creator+ planThe endpoint
One authenticated POST handles all five platforms and every action. Choose the recipient via conversation_id, platform_user_id, or to_phone. Authentication is the same API key as everything else.
Send API vs POST /v1/messages
-
request bodyidentical
Same fields, same actions, same routing, same idempotency. Moving between the two is a URL change.
-
responsediffers
This endpoint returns a flat body with a success boolean and a local-time sent_at. POST /v1/messages returns the v1 envelope ({"data": ...} / {"error": ...}) with UTC ISO-8601 timestamps and stable machine-readable error codes.
-
existing integrations
Nothing to change. This endpoint is stable; both endpoints share one engine, so behavior and capabilities never drift apart.
Actions
-
send_message
All five platforms. Free-form text, or approved WhatsApp templates.
-
react · unreact
Facebook and Instagram DMs only.
-
typing_on
Facebook, Instagram, and Telegram.
POST https://sumgenius.ai/api/meta/webhook-send.php
POST https://sumgenius.ai/api/v1/messages
// same body, v1 envelope; see the REST API page
Actions
POST action: send_message
Send a text message to a customer. This is the default action when action is omitted.
Body
-
idempotency_keystringrequired
Your unique key for this request (max 128 chars). Submitting the same key twice returns the original result without resending.
-
conversation_idinteger
The conversation.id from a received webhook event. Use this, or the routing below.
-
platform_user_idstring
The customer's PSID for Facebook or Instagram, or the chat_id for Telegram. Requires platform when used without conversation_id.
-
to_phonestring
Recipient phone in E.164 format, for SMS or WhatsApp. Auto-normalized. For WhatsApp also set platform: "whatsapp"; for SMS the platform auto-sets.
-
platformenumoptional
facebook · instagram · sms · whatsapp · telegram. Required when routing by platform_user_id, and for WhatsApp with to_phone.
-
message_textstringrequired
Max 1,000 chars on Instagram, 2,000 on Facebook, 1,600 on SMS (GSM-7) or 1,530 (UCS-2), 4,096 on WhatsApp and Telegram. See Encoding & Segments for SMS segmentation. For WhatsApp templates use template_name instead.
-
template_name · template_language · template_componentsoptional
WhatsApp only. Send an approved template any time, no 24h window required. template_language defaults to en_US; components pass through to Meta verbatim. See WhatsApp Templates.
Cold outbound. SMS, WhatsApp, and Telegram can send to a recipient with no existing conversation; the thread is auto-created. Facebook and Instagram require the customer to have messaged first. A failed cold send still creates the conversation and contact; see the note on the REST page.
curl -X POST https://sumgenius.ai/api/meta/webhook-send.php \
-H "X-SumGenius-Api-Key: sgwh_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"idempotency_key": "confirm-appt-10482-001",
"conversation_id": 10482,
"message_text": "Your appointment is confirmed for Tuesday at 2pm. See you then!"
}'
const response = await fetch('https://sumgenius.ai/api/meta/webhook-send.php', {
method: 'POST',
headers: {
'X-SumGenius-Api-Key': process.env.CHATGENIUS_API_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify({
idempotency_key: 'confirm-appt-10482-001',
conversation_id: 10482,
message_text: 'Your appointment is confirmed for Tuesday at 2pm.'
})
});
const result = await response.json();
$payload = json_encode([
'idempotency_key' => 'confirm-appt-10482-001',
'conversation_id' => 10482,
'message_text' => 'Your appointment is confirmed for Tuesday at 2pm.'
]);
$ch = curl_init('https://sumgenius.ai/api/meta/webhook-send.php');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $payload,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'X-SumGenius-Api-Key: ' . getenv('CHATGENIUS_API_KEY'),
'Content-Type: application/json'
]
]);
$result = json_decode(curl_exec($ch), true);
POST action: react
Add an emoji reaction to a specific message. Facebook and Instagram DMs only; other platforms reject it with HTTP 422. Use the message.id from a received webhook event as target_message_id.
Body
-
actionrequired
Must be "react".
-
idempotency_keyrequired
-
conversation_id or platform_user_id (+ platform)required
platform is facebook or instagram.
-
target_message_idrequired
The platform message id to react to.
-
reactionoptional
love ❤️ · smile 😆 · wow 😮 · sad 😢 · angry 😡 · yes 👍 · no 👎. Defaults to love when omitted.
curl -X POST https://sumgenius.ai/api/meta/webhook-send.php \
-H "X-SumGenius-Api-Key: sgwh_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"action": "react",
"idempotency_key": "react-10482-msg-001",
"conversation_id": 10482,
"target_message_id": "mid.1234567890abcdef",
"reaction": "love"
}'
POST action: unreact
Remove a previously added reaction. Same routing and fields as react, with action: "unreact" and no reaction field.
curl -X POST https://sumgenius.ai/api/meta/webhook-send.php \
-H "X-SumGenius-Api-Key: sgwh_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"action": "unreact",
"idempotency_key": "unreact-10482-msg-001",
"conversation_id": 10482,
"target_message_id": "mid.1234567890abcdef"
}'
POST action: typing_on
Show a typing indicator (the "..." bubble) to the customer. Lasts about 20 seconds or until you send a message. Supported on Facebook, Instagram, and Telegram (where it maps to sendChatAction).
Body
-
actionrequired
Must be "typing_on".
-
idempotency_keyrequired
-
conversation_id or platform_user_id (+ platform)required
No message_text needed.
Typing indicators are ephemeral. They are not retried on failure: a failed send goes straight to dead_letter. On Meta DM the messaging-window check is skipped, since Meta allows sender_action outside the window.
curl -X POST https://sumgenius.ai/api/meta/webhook-send.php \
-H "X-SumGenius-Api-Key: sgwh_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"action": "typing_on",
"idempotency_key": "typing-10482-001",
"conversation_id": 10482
}'
Behavior
Idempotency
Every request requires an idempotency_key (1 to 128 characters). Submitting the same key again returns the original result without resending, which makes retries safe under network failures. A reliable pattern: {your-reference}-{conversation_id}-{sequence}.
{
"success": true,
"status": "duplicate",
"request_id": "msgreq_c8d83cf861ec1f48",
"message": "Request already processed with this idempotency key."
}
Response format
Responses are JSON. This endpoint's shape predates the v1 envelope: a flat body with a success boolean.
-
successboolean
-
statusenum
sent: delivered to the platform · queued_retry: immediate send failed, queued for automatic retry · duplicate: this idempotency key was already processed · dead_letter: permanently failed.
-
request_id
ChatGenius request id. Provide it when contacting support.
-
conversation_id · platform · action
The resolved conversation, platform (any of the five), and executed action.
-
target_message_id · reaction
Present on react / unreact.
-
sent_at
Local-time string on this endpoint. POST /v1/messages returns the same moment as UTC ISO-8601.
{
"success": true,
"status": "sent",
"request_id": "msgreq_c8d83cf861ec1f48",
"conversation_id": 10482,
"platform": "instagram",
"action": "send_message",
"sent_at": "2026-02-20 08:15:32",
"message": "Message sent successfully."
}
Errors
Errors return "success": false with an error string describing what went wrong. (POST /v1/messages returns the same failures with stable machine-readable codes; branch on those if you need programmatic handling.)
| HTTP | When |
|---|---|
| 200 | Request accepted. Always check status: a 200 may also carry queued_retry or duplicate. |
| 400 | Invalid or missing request fields, or a non-JSON body |
| 401 | Missing or invalid API key |
| 403 | Valid key, but the add-on is not active |
| 405 | Wrong HTTP method; only POST is accepted |
| 422 | Validation passed but the request cannot be fulfilled: message too long, unsupported action for the platform, expired messaging window |
| 500 | Unexpected server error; contact support with your request_id |
{
"success": false,
"status": "error",
"error": "message_text is required for action=send_message."
}
Limits
These apply to sending through either endpoint; the platforms enforce them, not us.
Message length
- instagram1,000 chars
- facebook2,000 chars
-
sms1,600 GSM-7 · 1,530 UCS-2
Auto-split into segments (160 chars GSM-7, 70 UCS-2). See Encoding & Segments.
- whatsapp4,096 chars
-
telegram4,096 chars
Sent as plain text, never parsed as HTML or Markdown.
Platform rate limits
-
Instagram DM
100 messages/second, 750 private replies/hour.
-
Facebook Messenger
300 messages/second, 750 private replies/hour.
-
SMS (Twilio)
Subject to Twilio's A2P 10DLC throughput tier for your Messaging Service. New US brands typically start at the low-volume tier (about 4,500 segments/day, 1 to 3 segments/second); higher volumes require additional Twilio brand vetting. Registration is handled at provisioning, no extra setup from you.
If a platform returns a rate-limit error, the request is queued and retried automatically (status: queued_retry).
// per-platform caps
const LIMITS = {
instagram: 1000,
facebook: 2000,
sms: 1600,
whatsapp: 4096,
telegram: 4096
};