Skip to main content

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

MethodEndpointDescription
POST/publish/{topic}Publish a message
GET/consume/{topic}Consume / long-poll for messages
POST/ack/{topic}/{id}Acknowledge a message
POST/requeueRe-queue a message (increment retry count)
POST/webhook/{topic}Register a push webhook
POST/api/topicsCreate a topic manually
GET/api/statsGet broker statistics
GET/api/queues/peekPeek at queue contents (non-destructive)
GET/dashboardInteractive web dashboard

POST /publish/{topic}

Publish a message to a topic. The topic is created automatically on first publish.

Path Parameters

ParameterDescription
topicTopic name. Must match ^[a-zA-Z0-9._-]+$. Max 255 characters.

Query Parameters

ParameterTypeDescription
ttldurationTime-To-Live. Message is dropped if not consumed before expiry. Examples: 30s, 5m, 1h
delaydurationDelivery delay. Message is hidden until this duration passes. Examples: 10s, 1m
broadcastboolIf 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

StatusDescription
202 AcceptedMessage accepted and persisted
400 Bad RequestEmpty payload or invalid topic name
413 Request Entity Too LargePayload exceeds 2MB
429 Too Many RequestsQueue 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

ParameterDescription
topicTopic name, or a wildcard pattern like orders.*

Query Parameters

ParameterTypeDefaultDescription
timeoutduration0sHold connection open this long if queue is empty (long-polling). E.g., 5s, 10s
limitint1Number of messages to extract in one call
auto_ackboolfalseIf 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

StatusDescription
200 OKMessages returned
404 Not FoundQueue 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 Encoding

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

StatusDescription
200 OKMessage acknowledged
404 Not FoundMessage 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

StatusDescription
202 AcceptedMessage re-queued or moved to DLQ
400 Bad RequestMissing id or topic
404 Not FoundTopic 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

StatusDescription
201 CreatedWebhook registered
400 Bad RequestMissing 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 Conflict if the topic already exists (idempotent-safe)

Response

StatusDescription
201 CreatedTopic created
409 ConflictTopic already exists
400 Bad RequestInvalid 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 StatusMeaningTypical Cause
400 Bad RequestMalformed requestMissing topic, empty body, invalid duration
404 Not FoundResource not foundEmpty queue (on consume), unknown message ID
405 Method Not AllowedWrong HTTP verbUsing GET on a POST-only endpoint
409 ConflictAlready existsCreating a topic that already exists
413 Request Entity Too LargePayload too bigPayload exceeds 2MB
429 Too Many RequestsBackpressureQueue RAM limit (100k messages) reached
500 Internal Server ErrorBroker errorRare; 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";
?>