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)

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

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