---
title: "Send API"
source: https://sumgenius.ai/docs/send-api
generated: 2026-07-30
---

# Send API

The original message-sending endpoint, used by production integrations today and fully supported. New integrations should prefer [`POST /v1/messages`](https://sumgenius.ai/docs/rest-api#send-message) 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](https://sumgenius.ai/docs/api-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](https://sumgenius.ai/docs/webhook-sms#encoding) 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](https://sumgenius.ai/docs/webhook-whatsapp#templates).

> **Note**
>
> **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](https://sumgenius.ai/docs/rest-api#send-message).

**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**

```javascript
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**

```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](#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.

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

| 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` |

**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](https://sumgenius.ai/docs/webhook-sms#encoding).
- 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
};
```
