HTTP REST API Reference
TinyMQ exposes a language-agnostic HTTP API. Any client capable of making HTTP requests — curl, Python requests, PHP, Node.js, Rust — can interact with the broker without any special libraries.
Base URL: http://localhost:7800 (or your PORT setting)
Endpoints Summary
| Method | Endpoint | Description |
|---|---|---|
POST | /publish/{topic} | Publish a message |
GET | /consume/{topic} | Consume / long-poll for messages |
POST | /ack/{topic}/{id} | Acknowledge a message |
POST | /requeue | Re-queue a message (increment retry count) |
POST | /webhook/{topic} | Register a push webhook |
POST | /api/topics | Create a topic manually |
GET | /api/stats | Get broker statistics |
GET | /api/queues/peek | Peek at queue contents (non-destructive) |
GET | /dashboard | Interactive web dashboard |
POST /publish/{topic}
Publish a message to a topic. The topic is created automatically on first publish.
Path Parameters
| Parameter | Description |
|---|---|
topic | Topic name. Must match ^[a-zA-Z0-9._-]+$. Max 255 characters. |
Query Parameters
| Parameter | Type | Description |
|---|---|---|
ttl | duration | Time-To-Live. Message is dropped if not consumed before expiry. Examples: 30s, 5m, 1h |
delay | duration | Delivery delay. Message is hidden until this duration passes. Examples: 10s, 1m |
broadcast | bool | If true, delivers to all waiting consumers simultaneously (ephemeral — not persisted) |
Request Body
Raw bytes (JSON, plain text, binary). Maximum size: 2MB.
curl -X POST "http://localhost:7800/publish/orders.eu?ttl=10m&delay=5s" \
-H "Content-Type: application/json" \
-d '{"user_id": 42, "item": "laptop"}'
Response
| Status | Description |
|---|---|
202 Accepted | Message accepted and persisted |
400 Bad Request | Empty payload or invalid topic name |
413 Request Entity Too Large | Payload exceeds 2MB |
429 Too Many Requests | Queue RAM limit (100k messages) reached |
{"status": "accepted", "topic": "orders.eu"}
GET /consume/{topic}
Consume one or more messages from a topic. Supports long-polling.
Path Parameters
| Parameter | Description |
|---|---|
topic | Topic name, or a wildcard pattern like orders.* |
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
timeout | duration | 0s | Hold connection open this long if queue is empty (long-polling). E.g., 5s, 10s |
limit | int | 1 | Number of messages to extract in one call |
auto_ack | bool | false | If true, messages are ACK'd immediately upon delivery |
# Consume with 10s long-poll, batch of 5, auto-acknowledged
curl "http://localhost:7800/consume/orders.eu?timeout=10s&limit=5&auto_ack=true"
Response
| Status | Description |
|---|---|
200 OK | Messages returned |
404 Not Found | Queue empty or timeout expired with no messages |
Single message (limit=1, default):
{
"id": "a1b2c3d4-7c89-4b1a-9f5e-123456789abc",
"topic": "orders.eu",
"payload": "eyJ1c2VyX2lkIjogNDIsICJpdGVtIjogImxhcHRvcCJ9",
"timestamp": "2026-06-18T10:00:00Z",
"retry_count": 0
}
Multiple messages (limit > 1):
[
{ "id": "...", "topic": "orders.eu", "payload": "...", "timestamp": "...", "retry_count": 0 },
{ "id": "...", "topic": "orders.eu", "payload": "...", "timestamp": "...", "retry_count": 0 }
]
payload is returned as Base64-encoded bytes. Decode with your language's Base64 decoder.
echo "eyJ1c2VyX2lkIjogNDIsICJpdGVtIjogImxhcHRvcCJ9" | base64 -d
# {"user_id": 42, "item": "laptop"}
POST /ack/{topic}/{id}
Acknowledge a message, removing it from RAM and writing an ACK record to the WAL.
Required when auto_ack=false.
curl -X POST http://localhost:7800/ack/orders.eu/a1b2c3d4-7c89-4b1a-9f5e-123456789abc
Response
| Status | Description |
|---|---|
200 OK | Message acknowledged |
404 Not Found | Message not found or already acknowledged |
{"status": "success", "message": "Message acknowledged"}
POST /requeue
Re-queue a message, incrementing its retry_count. After 3 attempts, the broker routes it to {topic}.dlq.
The request body must be a full message JSON object (as returned by /consume).
curl -X POST http://localhost:7800/requeue \
-H "Content-Type: application/json" \
-d '{"id": "a1b2...", "topic": "orders.eu", "payload": "eyJ...", "timestamp": "...", "retry_count": 1}'
Response
| Status | Description |
|---|---|
202 Accepted | Message re-queued or moved to DLQ |
400 Bad Request | Missing id or topic |
404 Not Found | Topic does not exist |
POST /webhook/{topic}
Register a URL to receive messages from a topic via HTTP POST (push/webhook pattern).
curl -X POST http://localhost:7800/webhook/orders.eu \
-H "Content-Type: application/json" \
-d '{"url": "https://api.my-service.com/incoming"}'
Response
| Status | Description |
|---|---|
201 Created | Webhook registered |
400 Bad Request | Missing or invalid URL |
{"status": "webhook_registered"}
Multiple webhooks can be registered on the same topic. Each will receive the full raw payload as the POST body.
POST /api/topics
Pre-initialize a topic without publishing a message. Useful for ensuring a topic exists before wiring up consumers.
curl -X POST http://localhost:7800/api/topics \
-H "Content-Type: application/json" \
-d '{"name": "analytics.events"}'
Validation
- Name must be 1–255 characters
- Must match
^[a-zA-Z0-9._-]+$ - Returns
409 Conflictif the topic already exists (idempotent-safe)
Response
| Status | Description |
|---|---|
201 Created | Topic created |
409 Conflict | Topic already exists |
400 Bad Request | Invalid name format |
GET /api/stats
Returns a JSON snapshot of all active topics and broker totals.
curl http://localhost:7800/api/stats
{
"stats": [
{
"Name": "orders.eu",
"MessageCount": 12,
"WaitingConsumers": 2,
"IsDLQ": false,
"HasWebhooks": false
},
{
"Name": "orders.eu.dlq",
"MessageCount": 1,
"WaitingConsumers": 0,
"IsDLQ": true,
"HasWebhooks": false
}
],
"total_webhooks": 0
}
GET /api/queues/peek
Read up to 10 messages from a queue without consuming them. No ACK is triggered, no WAL record is written.
curl "http://localhost:7800/api/queues/peek?queue=orders.eu"
[
{
"id": "a1b2c3d4-...",
"topic": "orders.eu",
"payload": "eyJ...",
"timestamp": "2026-06-19T10:00:00Z",
"retry_count": 0
}
]
Returns an empty array [] if the queue is empty.
Error Reference
| HTTP Status | Meaning | Typical Cause |
|---|---|---|
400 Bad Request | Malformed request | Missing topic, empty body, invalid duration |
404 Not Found | Resource not found | Empty queue (on consume), unknown message ID |
405 Method Not Allowed | Wrong HTTP verb | Using GET on a POST-only endpoint |
409 Conflict | Already exists | Creating a topic that already exists |
413 Request Entity Too Large | Payload too big | Payload exceeds 2MB |
429 Too Many Requests | Backpressure | Queue RAM limit (100k messages) reached |
500 Internal Server Error | Broker error | Rare; check broker logs |
Language Examples
Python
import requests
import base64
base = "http://localhost:7800"
# Publish
requests.post(f"{base}/publish/orders",
json={"user_id": 42},
headers={"Content-Type": "application/json"})
# Consume
resp = requests.get(f"{base}/consume/orders?auto_ack=true&timeout=5s")
if resp.status_code == 200:
msg = resp.json()
payload = base64.b64decode(msg["payload"]).decode("utf-8")
print(f"Got message: {payload}")
Node.js
const fetch = require('node-fetch');
const base = 'http://localhost:7800';
// Publish
await fetch(`${base}/publish/orders`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ user_id: 42 })
});
// Consume
const resp = await fetch(`${base}/consume/orders?auto_ack=true&timeout=5s`);
if (resp.ok) {
const msg = await resp.json();
const payload = Buffer.from(msg.payload, 'base64').toString('utf-8');
console.log('Got message:', payload);
}
PHP
<?php
$base = 'http://localhost:7800';
// Publish
$ch = curl_init("$base/publish/orders");
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(['user_id' => 42]));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_exec($ch);
curl_close($ch);
// Consume
$ch = curl_init("$base/consume/orders?auto_ack=true&timeout=5s");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$msg = json_decode($response, true);
$payload = base64_decode($msg['payload']);
echo "Got message: $payload\n";
?>