REST API
Event Broker REST
Publish events, read and purge history, and configure retention per Main Topic.
All routes are below https://api.thuum.dev/api/{domain}/event. Data routes check the key's Event Broker
claim data flags on the topic's Main Topic; config routes check its topic flags.
| Method | Path | Flag | Purpose |
|---|---|---|---|
POST | /event/data/{topic} | data P | Publish an event |
GET | /event/data/{topic} | data R | Read history |
DELETE | /event/data/{topic} | data W | Purge history |
GET | /event/topics | topic R | List retention configs |
GET | /event/topics/{topic} | topic R | A Main Topic's effective window |
PUT | /event/topics/{topic} | topic W | Set a Main Topic's window |
DELETE | /event/topics/{topic} | topic W | Remove it (back to the default) |
Event Broker claims themselves are managed under /event/claims: see
Management.
Publish an event#
POST /event/data/{topic} publishes on exactly {topic}: stored, then delivered to WebSocket
subscribers of the topic and of its super topics.
| Body field | Required | Rules |
|---|---|---|
type | yes | 1–64 characters of a-z A-Z 0-9 _ . : - |
data | yes | Any JSON value except null, at most 64 KiB as JSON |
curl -s -X POST https://api.thuum.dev/api/acme/event/data/orders:1042 \
-H "authorization: Bearer $TOKEN" \
-H 'content-type: application/json' \
-d '{"type":"order.shipped","data":{"carrier":"DHL","tracking":"JD014600003SE"}}'const response = await fetch(`${API}/api/acme/event/data/orders:1042`, {
method: 'POST',
headers: { authorization: `Bearer ${token}`, 'content-type': 'application/json' },
body: JSON.stringify({
type: 'order.shipped',
data: { carrier: 'DHL', tracking: 'JD014600003SE' }
})
});
const { data: event } = await response.json();const event = await acme.eventBroker.data.publish('orders:1042', {
type: 'order.shipped',
data: { carrier: 'DHL', tracking: 'JD014600003SE' }
});Response 201:
{
"data": {
"id": "79717053-e3ab-40db-9999-7c54ca310125",
"topic": "orders:1042",
"type": "order.shipped",
"data": { "carrier": "DHL", "tracking": "JD014600003SE" },
"ts": 1792590697447
}
}Errors: 403 without P on the Main Topic; 422 for an invalid topic, type or data.
Read history#
GET /event/data/{topic} returns the retained events of the topic and its sub-topics, newest
first: exactly what a subscriber of {topic} would have received.
| Query | Meaning |
|---|---|
type | Only events of this type. |
since | Epoch ms, inclusive. |
until | Epoch ms, exclusive. |
limit | Default 100, at most 1000 (larger is capped). |
curl -s "https://api.thuum.dev/api/acme/event/data/orders?type=order.shipped&limit=20" \
-H "authorization: Bearer $TOKEN"{ "data": [ { "id": "…", "topic": "orders:1042", "type": "order.shipped", "data": { … }, "ts": 1792590697447 }, … ] }To page further back, pass the oldest ts you received as until. Events that share that exact
millisecond would be skipped; when that matters, pass ts + 1 and drop the ids you already have.
const page1 = await acme.eventBroker.data.list('orders', { limit: 1000 });
const oldest = page1.at(-1);
const page2 = oldest
? await acme.eventBroker.data.list('orders', { limit: 1000, until: oldest.ts })
: [];Purge history#
DELETE /event/data/{topic} deletes retained events of the topic's subtree. Optional filters:
type, since, until. Subscribers are not notified.
curl -s -X DELETE "https://api.thuum.dev/api/acme/event/data/chat:room-7" -H "authorization: Bearer $TOKEN"{ "data": { "deleted": 1342 } }Retention configs#
A config sets the history window of a Main Topic and all its sub-topics. {topic} must be a
Main Topic (no :), else 422.
curl -s -X PUT https://api.thuum.dev/api/acme/event/topics/chat \
-H "authorization: Bearer $TOKEN" -H 'content-type: application/json' \
-d '{"max_events":50000,"ttl_seconds":604800}'{
"data": {
"topic": "chat",
"max_events": 50000,
"ttl_seconds": 604800,
"default": false,
"inserted_at": "…",
"updated_at": "…"
}
}PUTreplaces the whole config: an omitted bound isnull, which means unbounded. Bounds must be greater than 0.GET /event/topics/{topic}returns the effective window, with"default": true(and the system default of 1000 events and 3600 seconds) when nothing is stored.GET /event/topicslists stored configs, ordered by topic.DELETE /event/topics/{topic}removes the config (204, idempotent).- Configs never block publishing. Expired events are swept about once a minute.
await acme.eventBroker.topics.put('chat', { max_events: 50_000, ttl_seconds: 604_800 });
const window = await acme.eventBroker.topics.get('orders'); // { default: true, … } if unset