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)
In practice your plan's monthly SMS allowance is the limit you reach first (500/month on Professional, 2,500 on Business, plus any volume packs), well before any carrier ceiling. Above that sits the A2P 10DLC layer: we register a low-volume campaign, which T‑Mobile caps at roughly 2,000 message segments per day. That cap counts T‑Mobile traffic only (including Sprint and MetroPCS), applies per registered brand across every provider sending for that business, and resets at midnight Pacific. Your exact daily limit and per-second throughput are set by your brand's Trust Score from The Campaign Registry, not by us, and are visible in Twilio's Trust Hub once your brand is approved. US and Canadian carriers require your business to be registered before this number can send at all, which you complete once from Settings → SMS in your portal. We handle the submission and tell you when the carriers approve it.
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
};