API Reference
ThingsChat is a simple HTTP API that lets IoT devices publish and subscribe to messages. Devices communicate through named “things” scoped to a token. No infrastructure needed.
https://api.thingschat.onlineAuthentication
ThingsChat uses token-based authentication. Your token is a unique identifier that scopes all your things. Include it directly in the URL path. There is no Authorization header required for free-tier usage.
Don't have a token yet? Generate a free token on the home page.
# Token goes in the URL path — not in a header
GET https://api.thingschat.online/{YOUR_TOKEN}/chat/{thing}/latestEndpoints
All endpoints are relative to the base URL.
/{token}/chat/{thing}Send Message
Publish a JSON message to a named thing under your token. The body can be any valid JSON object; keys and values are entirely up to you. The maximum payload size is 10 KB.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
| token | string | yes | Your API token |
| thing | string | yes | Name of the thing (device/sensor/etc.) |
tokenrequiredstring
Your API token
thingrequiredstring
Name of the thing (device/sensor/etc.)
Request body
| Name | Type | Required | Description |
|---|---|---|---|
| (any key) | any | yes | Any JSON key/value pairs, e.g. {"temperature": 22.5} |
(any key)requiredany
Any JSON key/value pairs, e.g. {"temperature": 22.5}
Response
Returns {"status":"ok","id":123} on success. The id is the unique message identifier.
curl -X POST https://api.thingschat.online/{token}/chat/sensor1 \
-H "Content-Type: application/json" \
-d '{"temperature": 22.5, "humidity": 60}'/{token}/chat/{thing}/latestLatest Message
Retrieve the most recent message published to a thing. Returns a 404 if no messages have been sent yet.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
| token | string | yes | Your API token |
| thing | string | yes | Name of the thing |
tokenrequiredstring
Your API token
thingrequiredstring
Name of the thing
Response
Returns the latest message object: { thing, token, chat, createdAt, id }. The chat field contains the original JSON payload.
curl https://api.thingschat.online/{token}/chat/sensor1/latest/{token}/chat/{thing}/historyMessage History
Retrieve recent messages for a thing, ordered newest-first. Use the limit query parameter to control how many records are returned.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
| token | string | yes | Your API token |
| thing | string | yes | Name of the thing |
tokenrequiredstring
Your API token
thingrequiredstring
Name of the thing
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
| limit | integer | no | Max number of messages to return |
limitoptionalinteger
Max number of messages to return
Response
Returns an array of message objects, each containing { id, thing, chat, createdAt }.
curl "https://api.thingschat.online/{token}/chat/sensor1/history?limit=10"/{token}/chat/{thing}/listenLive Stream (SSE)
Subscribe to a real-time stream of messages using Server-Sent Events. The connection stays open and the server pushes new messages as they arrive. Use the browser's built-in EventSource API or any SSE client. Note: each open SSE connection counts as 5 reads against your rate limit.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
| token | string | yes | Your API token |
| thing | string | yes | Name of the thing to listen on |
tokenrequiredstring
Your API token
thingrequiredstring
Name of the thing to listen on
Response
Returns a text/event-stream. Each event contains a JSON-encoded message object: { thing, chat, createdAt, id }.
# curl follows the SSE stream until interrupted
curl -N https://api.thingschat.online/{token}/chat/sensor1/listen/{token}/thingsList Things
List all thing names that have received at least one message under the given token.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
| token | string | yes | Your API token |
tokenrequiredstring
Your API token
Response
Returns an array of strings — the names of all things associated with the token.
curl https://api.thingschat.online/{token}/thingsSSE Client Guide
The /listen endpoint is the primary way to receive real-time data from your things. It uses Server-Sent Events (SSE) with three distinct event types. Below is a reference table and a complete Node.js client example.
Event types
| Event | When | Data shape |
|---|---|---|
| status | On connect (free tier) | {"type":"connected","retry":60000} |
| status | On connect (upcoming paid tier) | {"type":"connected"} |
| message | When someone POSTs to the thing | {"thing":"…","token":"…","chat":{…},"createdAt":"…","id":123} |
| session | Idle timeout (free tier, 3 min) | {"type":"expired","reason":"idle"} |
Key behavior
Auto-reconnect — EventSource handles reconnection automatically. The server sends retry: 60000 for free tier, so after any disconnect the client waits 60s then reconnects.
Idle timeout (free) — Connections are closed after 3 minutes of inactivity. You'll receive a session event with {"type":"expired","reason":"idle"} right before, then EventSource reconnects.
Keepalives (upcoming paid tier) — A future paid tier will include server-side keepalives every 20s, allowing connections to stay open indefinitely with no idle timeout.
SSE comments — The browser EventSource API automatically ignores SSE comments (: keepalive, : ping). No handling needed.
Complete Node.js client example
- Install the
eventsourcepackage:npm install eventsource— or use Node 18+ with the--experimental-eventsourceflag - Export your token:
export TOKEN="your-token"— optionally setTHINGandBASE_URL(defaults tomy-deviceandhttps://api.thingschat.online) - Save the script below and run:
node thingschat-client.js
// thingschat-client.js
const EventSource = globalThis.EventSource ?? require('eventsource')
const BASE_URL = process.env.BASE_URL || 'https://api.thingschat.online'
const TOKEN = process.env.TOKEN
const THING = process.env.THING || 'my-device'
if (!TOKEN) {
console.error('Missing TOKEN env var')
process.exit(1)
}
const url = `${BASE_URL}/${TOKEN}/chat/${THING}/listen`
console.log(`Connecting to ${url}`)
const es = new EventSource(url)
// --- Connection lifecycle ---
es.addEventListener('status', (e) => {
const data = JSON.parse(e.data)
console.log('[connected]', data)
if (data.retry) {
console.log(` Free plan — idle connections close after 3 min`)
console.log(` Auto-reconnect delay: ${data.retry / 1000}s`)
}
})
// --- Incoming messages ---
es.addEventListener('message', (e) => {
const msg = JSON.parse(e.data)
console.log(`[message] id=${msg.id} thing=${msg.thing}`)
console.log(' payload:', msg.chat)
console.log(' at:', msg.createdAt)
})
// --- Session management (free plan only) ---
es.addEventListener('session', (e) => {
const data = JSON.parse(e.data)
console.log('[session]', data)
if (data.type === 'expired' && data.reason === 'idle') {
console.log(' Expired due to inactivity — will reconnect automatically')
}
})
// --- Error handling ---
es.onerror = () => {
if (es.readyState === EventSource.CONNECTING) {
console.log('[reconnecting...]')
} else if (es.readyState === EventSource.CLOSED) {
console.log('[closed] connection was terminated')
}
}
// --- Graceful shutdown ---
process.on('SIGINT', () => {
console.log('\nClosing connection...')
es.close()
process.exit(0)
})Rate Limits
Rate limits are enforced per token. Every response includes an X-RateLimit-Remaining header showing how many requests remain in the current window. When the limit is exceeded, the API returns HTTP 429 with a Retry-After header.
| Plan | Write limit (POST) | Read limit (GET) |
|---|---|---|
| Free | 100 / hour | 60 / hour |
The maximum request body size for POST /{token}/chat/{thing} is 10 KB. Requests exceeding this limit will be rejected with HTTP 413.
Opening a GET /{token}/chat/{thing}/listen connection counts as 5 reads against your hourly limit, because it holds a persistent open connection rather than a single request. On the free tier (60 reads/hour) this allows up to 12 simultaneous SSE connections.
Keep in mind that dropping and reconnecting costs another 5 reads each time. Things that receive infrequent messages may cause clients to disconnect due to inactivity, making reconnection-heavy patterns expensive on the free tier.
A paid tier is coming soon with connections that stay alive during periods of inactivity, eliminating reconnection overhead entirely.
Response headers
X-RateLimit-RemainingNumber of requests remaining in the current 1-hour window.Retry-AfterSeconds until the rate limit resets. Only present on 429 responses.