Push messages to your chat room from external services, bots, and integrations.
Relay SSN chat into NinjaChatter with the room ingress API key, or display a room in an SSN dock. See setup, verification, and limitations below.
POST /rooms/{room_id}/ingress
Send a message to a chat room via HTTP POST request.
Two authentication methods are supported:
Include your room's API key in the Authorization header:
Authorization: Bearer YOUR_API_KEY
Find your API key in the Dashboard under "Bot & Webhook Integration" for each room.
Sign the exact request bytes using HMAC-SHA256 with your webhook secret. Encode the digest as Base64, with no sha256= prefix:
X-Chat-Signature: BASE64_HMAC_SHA256
For text-only bots, create a send-only bot key in the dashboard’s Integrations section. Use it in X-API-Key or Authorization: Bearer. It cannot delete messages or mint privileged tokens. See the automation guide for its restricted payload, key management, signing examples, response handling, and retry limitations. Existing SSN ingress keys keep their current permissions.
| Field | Type | Description |
|---|---|---|
type*required |
string | Message type. Use "chat" for chat messages. |
payload*required |
object | Message payload containing the message data. |
Use the message_id returned by ingress to remove a displayed message. Send the same room authentication as for chat:
{ "type": "delete", "payload": { "target_id": "MESSAGE_ID" } }
The target can also be supplied as a top-level target_id. Chat and WebSocket overlays handle these events and the moderation event delete_message with payload.message_id. Repeating a deletion or targeting a message no longer displayed has no effect.
| Field | Type | Description |
|---|---|---|
text*required |
string | The message content to display in chat. |
displayNameoptional |
string | Display name for the message sender. Defaults to "webhook". |
userIdoptional |
string | Unique identifier for the sender. |
avataroptional |
string | URL to the sender's avatar image. |
sourceoptional |
string | Platform name (e.g., "youtube", "twitch", "discord"). |
sourceIconoptional |
string | URL to an icon representing the source platform. |
| Field | Type | Description |
|---|---|---|
badgesoptional |
array | Array of badge objects. Each badge can have: src (image URL), type ("img" or "svg"), html (SVG markup). |
isModeratoroptional |
boolean | Whether the sender is a moderator. |
nameColoroptional |
string | CSS color for the display name. |
| Field | Type | Description |
|---|---|---|
donationoptional |
string | Donation amount as displayed (e.g., "$5.00", "500 bits"). |
donationValueoptional |
number | Numeric donation value for sorting/filtering. |
backgroundColoroptional |
string | Background color for Super Chat style messages. |
textColoroptional |
string | Text color for Super Chat style messages. |
| Field | Type | Description |
|---|---|---|
membershipoptional |
string | Membership status or tier (e.g., "MEMBER", "Tier 1 Sub"). |
subtitleoptional |
string | Additional membership info (e.g., "12 months", "Gifted by User"). |
| Field | Type | Description |
|---|---|---|
eventoptional |
string | Event type: "follow", "raid", "subscription", "giftpurchase", "sponsorship", etc. |
titleoptional |
string | Event title or label. |
| Field | Type | Description |
|---|---|---|
contentImageoptional |
string | URL to content image (stickers, emotes, etc.). |
replyTooptional |
string | Name of user being replied to. |
replyTextoptional |
string | Text of message being replied to. |
sourceNameoptional |
string | Channel or stream name. |
sourceImageoptional |
string | Channel thumbnail or logo URL. |
In addition to the payload object, you can include a top-level meta field for custom data:
{
"type": "chat",
"payload": { ... },
"meta": {
"customField": "value",
"anyOtherData": 123
}
}
The meta field passes through to connected clients unchanged, useful for custom integrations.
curl -X POST "https://api.ninjachatter.com/rooms/YOUR_ROOM_ID/ingress" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "chat",
"payload": {
"text": "Hello from my bot!"
}
}'
curl -X POST "https://api.ninjachatter.com/rooms/YOUR_ROOM_ID/ingress" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "chat",
"payload": {
"text": "Check out this stream!",
"displayName": "StreamBot",
"userId": "bot-123",
"source": "twitch",
"sourceIcon": "https://example.com/twitch-icon.png",
"avatar": "https://example.com/bot-avatar.png"
}
}'
curl -X POST "https://api.ninjachatter.com/rooms/YOUR_ROOM_ID/ingress" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "chat",
"payload": {
"text": "Great stream! Keep it up!",
"displayName": "GenerousViewer",
"userId": "viewer-456",
"source": "youtube",
"donation": "$10.00",
"donationValue": 10.00,
"backgroundColor": "#1565c0",
"textColor": "#ffffff"
}
}'
curl -X POST "https://api.ninjachatter.com/rooms/YOUR_ROOM_ID/ingress" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "event",
"payload": {
"text": "",
"displayName": "BigStreamer",
"event": "raid",
"title": "RAID",
"subtitle": "123 viewers"
}
}'
| Status | Body | Description |
|---|---|---|
202 |
queued |
Message accepted and queued for delivery. |
202 |
filtered |
Message was filtered (blocked by bad word filter). |
401 |
Unauthorized |
Invalid or missing API key. |
400 |
Bad Request |
Invalid JSON payload. |
404 |
Not Found |
Room does not exist. |
Social Stream Ninja has built-in support for Ninja Chatter. Push messages from YouTube, Twitch, TikTok, and 30+ platforms directly to your chat room with just a few clicks.
Once connected, share your chat link with viewers:
https://ninjachatter.com/YOUR_ROOM_ID
Viewers do not need the SSN extension. Joining and sending chat follow the room’s guest/provider settings. A public read-only overlay requires the room to be enabled and Allow read-only stream access to be on; guest access is a separate setting.
To show this room in an SSN dock, use the SSN-format read-only stream and dock URL. This connects the dock directly to NinjaChatter. It does not import a source into the SSN extension, merge an existing SSN session, or send replies back to Twitch/YouTube. Use NinjaChatter’s normal chat page when viewers should participate.
/rooms/{room}/ingress, not the built-in /ssn relay. Replace the saved SSN key after ingress-key rotation.https://api.ninjachatter.com/ssn. Its current relay does not report HTTP failures in the popup. Check status and response body, but redact authorization headers before sharing logs.message_id of filtered without external_id means filtering blocked publication. Check the destination room and display permissions. A successful HTTP response is not a viewer-delivery receipt.socialstreamchat, but that is not a general loop guarantee for custom adapters. Preserve provenance and prevent your own publications from being relayed back.Keep the ingress key in your private SSN configuration or integration backend, never in an overlay URL or public page. SSN exports may contain it. For a custom text-only bot, prefer the restricted send-only bot key.
POST https://api.ninjachatter.com/ssn takes Authorization: Bearer ROOM_INGRESS_API_KEY, Content-Type: application/json, and the envelope below. The key identifies the destination room. This endpoint does not accept a send-only bot key, JWT, or HMAC signature in place of the ingress key. The request body limit is 65,536 bytes. Check every HTTP response; do not automatically retry an ambiguous publication because repeated requests can duplicate messages.
{
"type": "chat",
"payload": {
"text": "Hello from SSN",
"displayName": "Example viewer",
"userId": "example-viewer-1",
"source": "youtube"
}
}
The built-in adapter converts SSN messages to this envelope; posting a raw SSN row is not the same contract. Its usual relay path forwards chat text, not every SSN event. HTML chat content is cleaned to text. Rich fields are supported selectively and are not guaranteed to survive every downstream display; the SSN read-only adapter is a smaller format than the ingress payload.
For developers building custom integrations or needing more control, you can send messages directly via HTTP POST:
https://api.ninjachatter.com/rooms/YOUR_ROOM_ID/ingressAuthorization: Bearer YOUR_API_KEYContent-Type: application/json{
"type": "chat",
"payload": {
"text": "{message}",
"displayName": "{author}",
"userId": "{authorId}",
"source": "{platform}",
"avatar": "{authorPhoto}"
}
}
The braces above are illustrative placeholders, not an SSN template language. Map actual SSN fields in your adapter:
| SSN Field | Maps To | Description |
|---|---|---|
chatmessage | payload.text | The chat message content |
chatname | payload.displayName | Username of the sender |
userid | payload.userId | Unique user identifier |
type | payload.source | Platform name (youtube, twitch, etc.) |
chatimg | payload.avatar | User's profile picture URL |
Messages sent via webhook ingress are subject to the same filtering and moderation as regular chat messages.
When enabled in room settings, the bad word filter automatically blocks messages containing inappropriate content:
202 filtered statusTo enable: Dashboard → Room Settings → "Enable chat filter"
Room moderators can take action on webhook users just like regular users:
| Limit | Value | Scope |
|---|---|---|
| Messages per user | 20 / 10 seconds | Per user ID |
| Messages per IP | 60 / 10 seconds | Per source IP |
| Message size | 64 KB max | Per message |
If you have questions or need assistance with your integration: