Sending notifications from your server to a chat room
How to send data from your server to a chat room channel with the server API (v2), and how your page script or a plugin can pick out and show only the data your server sent.
Last updated October 19, 2026
On this page
When something happens on your server (a payment completes, a new post goes up, a stream starts), you can send it to a chat room channel with the server API, and your page script can receive it and show it in the chat room. The full request format and error codes are in Server REST API.
To just show it without writing code, turn on the Event alert box plugin and send with plugin set to alertBox. It shows new post, donation, and subscription alerts as colored boxes in the chat list. The Donation goal bar, Live status, Scoreboard, Countdown, and Ranking plugins work the same way.
Flow
- Your page script (or a plugin) opens a channel (for example,
notice-bot) in the chat room and waits. - Your server sends
{"plugin":"notice-bot","data":[...]}toPOST https://api.uchat.io/v2/rooms/{id}/events. - People currently connected to the chat room receive the data on that channel. The sender is the server user, with
auth4. - Your page script checks
authand shows the data on the screen.
By default, it goes only to people connected right now. If no one is there, there is simply no one to receive it; it is not an error. If people who join later should also see it, save it with "save": true (see For people who join later below).
API key
In the admin page, go to the API menu and click Create API key. Give it a name and turn on Events in its permissions. The key (uchat_…) is shown only once when issued, so copy it right away. On the same screen, also copy the API chat room id (room_…) that goes in the URL.
Keep the API key only on your server. If you call the server API from browser JavaScript, the key is exposed and anyone can send data as the server user. If the key leaks, revoke it or roll it right away in the API menu.
1. Prepare the receiving side
<script>U=window.U=window.U||{},U.events=U.events||[],U.chat=function(n){return{on:function(e,t){U.events.push([n,e,t])},off:function(e){for(var t=U.events.length;t>0;)U.events[--t][0]==n&&U.events[t][1]==e&&U.events.splice(t,1)}}};</script>
<script async src="https://client.uchat.io/uchat.js"></script>
<u-chat room="my-room" style="display:inline-block; width:100%; max-width:500px; height:500px;"></u-chat>
<script>
function escapeHtml(text) {
return String(text).replace(/[&<>"']/g, function (c) {
return { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[c];
});
}
U.chat('my-room').on('after.create', function (room) {
room.plugin.add('notice-bot').onReceived(function (room, msg) {
if (!msg.user || msg.user.auth !== 4) return; // only server API data or saved values
if (msg.type !== 0) return; // only data the server API sent to everyone
if (typeof msg.data[0] !== 'string') return;
room.print('[Notice] ' + escapeHtml(msg.data[0]));
});
});
</script>
- People in the chat room can also send data with the same channel name. To trust only what your server sent, check
msg.user.auth === 4.auth4 means data sent through the server API, or a value saved by a moderator or above. Saved values arrive withtype1 on entry, so to accept only server API data sent to everyone (type0), also checkmsg.type === 0. Server API data sent to a specific nickname is alsotype1, so you cannot tell it apart from saved values. The server user has no nickname, so do not check by nickname. room.printinterprets its input as HTML, so escape any text you receive before inserting it.
2. Send from your server
curl:
curl -X POST https://api.uchat.io/v2/rooms/room_xxxxxxxxxxxxxxxx/events \
-H "Authorization: Bearer uchat_..." \
-H "Content-Type: application/json" \
-d '{"plugin":"notice-bot","data":["Payment for order #1024 is complete",12000]}'
datais an array of values. Use strings, numbers, and booleans; the receiving side gets them all as strings.- On success you get HTTP 202 and
{"data":{"sent":true}}. On failure you get an HTTP status and{"error":{"code":…,"message":…}}. - Before sending for real, you can run the same body with Try it in the API menu.
Node.js (18 or later):
const ROOM = 'room_xxxxxxxxxxxxxxxx';
async function sendToRoom(plugin, data, options = {}) {
const res = await fetch(`https://api.uchat.io/v2/rooms/${ROOM}/events`, {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.UCHAT_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ plugin, data, ...options })
});
const result = await res.json();
if (!res.ok) console.warn('uchat api error', res.status, result.error);
return result;
}
await sendToRoom('notice-bot', ['Payment for order #1024 is complete', 12000]);
PHP:
<?php
function uchat_send($plugin, array $data, array $options = []) {
$ch = curl_init('https://api.uchat.io/v2/rooms/room_xxxxxxxxxxxxxxxx/events');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('UCHAT_API_KEY'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode(['plugin' => $plugin, 'data' => $data] + $options),
CURLOPT_RETURNTRANSFER => true,
]);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);
return $result;
}
uchat_send('notice-bot', ['Payment for order #1024 is complete', 12000]);
Send to one person
Put a nickname in "to" in the body to send only to that person. On the receiving side, msg.type is 1. Non-English nicknames such as Korean ones work as is.
curl -X POST https://api.uchat.io/v2/rooms/room_xxxxxxxxxxxxxxxx/events \
-H "Authorization: Bearer uchat_..." \
-H "Content-Type: application/json" \
-d '{"plugin":"notice-bot","to":"Minji","data":["Minji, your coupon has been issued"]}'
If that nickname is not in the chat room right now, you get HTTP 404 target_not_found.
For people who join later
Add "save": true to save it as the channel's last value. It is sent to people here now, and people who join later receive it on entry (msg.type 1). It is saved even if you send it when no one is in the chat room.
curl -X POST https://api.uchat.io/v2/rooms/room_xxxxxxxxxxxxxxxx/events \
-H "Authorization: Bearer uchat_..." \
-H "Content-Type: application/json" \
-d '{"plugin":"notice-bot","save":true,"data":["Maintenance tonight at midnight"]}'
- To delete it, save
"data":[]. The receiving side gets an empty value. - The limits are the same as channel save (a free chat room can save one channel, up to 1KB). → Channel API and limits
- Saved values remain even when the chat room empties or the server restarts.
- The receiving example above drops
msg.type !== 0, so remove that line if you also want saved values.
Common errors
| Error | Meaning | What to do |
|---|---|---|
401 missing_key, invalid_key |
No key, or not a key for this chat room | Check the Authorization: Bearer header and the API chat room id. Use the API key, not the member integration token |
403 insufficient_scope |
The key lacks the Events permission | Fix that key's permissions in the API menu |
400 invalid_data |
data is not an array, or contains control characters such as line breaks |
Send it in the form [...], without line breaks |
404 target_not_found |
The to nickname is not in the chat room |
Check the nickname |
429 rate_limited, chat_rate_limited |
Call or channel send limit exceeded | Send less often. → Server REST API |
The start of the request body and the request IP are kept for 30 days in the call log of the API menu. Do not send personal or payment information; send only the text to display. A complete example is in Payment completion notice. The older v1 method (/rooms/{room}/plugin/...) is covered in Server REST API.
Still not sure how it works? Ask your question on the contact board.