ThingsChat

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.

Base URL — https://api.thingschat.online

Authentication

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}/latest

Endpoints

All endpoints are relative to the base URL.

POST/{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

tokenrequired

string

Your API token

thingrequired

string

Name of the thing (device/sensor/etc.)

Request body

(any key)required

any

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}'
GET/{token}/chat/{thing}/latest

Latest Message

Retrieve the most recent message published to a thing. Returns a 404 if no messages have been sent yet.

Path parameters

tokenrequired

string

Your API token

thingrequired

string

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
GET/{token}/chat/{thing}/history

Message History

Retrieve recent messages for a thing, ordered newest-first. Use the limit query parameter to control how many records are returned.

Path parameters

tokenrequired

string

Your API token

thingrequired

string

Name of the thing

Query parameters

limitoptional

integer

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"
GET/{token}/chat/{thing}/listen

Live 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

tokenrequired

string

Your API token

thingrequired

string

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
GET/{token}/things

List Things

List all thing names that have received at least one message under the given token.

Path parameters

tokenrequired

string

Your API token

Response

Returns an array of strings — the names of all things associated with the token.

curl https://api.thingschat.online/{token}/things

SSE 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

EventWhenData shape
statusOn connect (free tier){"type":"connected","retry":60000}
statusOn connect (upcoming paid tier){"type":"connected"}
messageWhen someone POSTs to the thing{"thing":"…","token":"…","chat":{…},"createdAt":"…","id":123}
sessionIdle 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

  1. Install the eventsource package: npm install eventsource — or use Node 18+ with the --experimental-eventsource flag
  2. Export your token: export TOKEN="your-token" — optionally set THING and BASE_URL (defaults to my-device and https://api.thingschat.online)
  3. 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.

PlanWrite limit (POST)Read limit (GET)
Free100 / hour60 / hour
Payload size limit10 KB

The maximum request body size for POST /{token}/chat/{thing} is 10 KB. Requests exceeding this limit will be rejected with HTTP 413.

SSE connection weight×5

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.