ChatGenius Developer Send API Markdown

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+ plan

The 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.

Endpoint
POST https://sumgenius.ai/api/meta/webhook-send.php
Recommended for new integrations
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.

Request
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!"
  }'
Node.js
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();
PHP
$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.

Request
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.

Request
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.

Request
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}.

Replay of a processed key
{
  "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
{
  "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.)

HTTPWhen
200Request accepted. Always check status: a 200 may also carry queued_retry or duplicate.
400Invalid or missing request fields, or a non-JSON body
401Missing or invalid API key
403Valid key, but the add-on is not active
405Wrong HTTP method; only POST is accepted
422Validation passed but the request cannot be fulfilled: message too long, unsupported action for the platform, expired messaging window
500Unexpected server error; contact support with your request_id
Error
{
  "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).

Length check before sending
// per-platform caps
const LIMITS = {
  instagram: 1000,
  facebook:  2000,
  sms:       1600,
  whatsapp:  4096,
  telegram:  4096
};