Pub/sub - API - REST
Publishing messages and getting them from queues over REST - endpoints, parameters and samples.
Overview
If you're new to the publish/subscribe pattern, start with What is publish/subscribe?
Before making use of the REST pub/sub API, a REST endpoint needs to be created with HTTP Basic Auth credentials and appropriate permissions.
REST integration with publish/subscribe is built around three operations:
| Operation | REST |
|---|---|
| Publishing | POST /pubsub/topic/{topic_name} |
| Getting messages from queues | POST /pubsub/messages/get |
| Acknowledging messages | POST /pubsub/messages/ack |
To make use of any of these endpoints, a REST client must use HTTP Basic Auth credentials previously assigned to it by Zato admins
REST clients can subscribe to topics if they have proper subscription permissions. Subscribing to the same topic multiple times is safe and has no effect. All messages from all subscribed topics are delivered to a single queue per user.
- REST clients receive their messages in one of two ways:
- Pull-style: clients call
/pubsub/messages/getto retrieve messages on demand - Push-style: Zato delivers messages to configured REST endpoints as soon as they arrive
- Pull-style: clients call
- REST clients receive their messages in one of two ways:
OpenAPI definition

In your Dashboard at http://localhost:8183, click
EDA → Download OpenAPIto download the complete specification of the interface, for instance, to generate API clients from it, or to use it with tools such as PostmanYou can also download the specification from GitHub
Demo credentials, topics and subscriptions

In your Dashboard at http://localhost:8183, click
EDA → Import test configto auto-configure demo credentials, and a few topics, so that you can quickly try out the REST APIThe demo credentials are user.1/password.1
Note that the test config does not survive container restarts and it's meant to be used during development and testing, for your convenience, but the configuration is real, your actual credentials or topics will look similarly
Publishing messages
Topic name must be provided in the URL path. Message data and optional parameters are given as JSON payload.
| Verb | URL |
|---|---|
| POST | /pubsub/topic/{topic_name} |
Request
| Parameter | Datatype | Required | Notes |
|---|---|---|---|
| data | any | Yes | Actual data of the message that is being published. Can be a string or a JSON object. |
| priority | integer | --- | Message priority from 0 to 9 (0=lowest, 9=highest). Defaults to 5 if not given. |
| expiration | integer | --- | Expiration in seconds. Defaults to 31536000 (1 year) if not given. |
| correl_id | string | --- | Correlation ID for message tracking. Defaults to the request correlation ID if omitted. |
| in_reply_to | string | --- | ID of message this is replying to. |
| ext_client_id | string | --- | External client identifier for logging and audit purposes. |
| pub_time | string | --- | Custom publication time in ISO format with timezone (e.g., "2025-01-01T12:00:00+00:00"). Server sets to current time if not provided. |
Response
| Parameter | Datatype | Required | Notes |
|---|---|---|---|
| is_ok | boolean | Yes | Whether the operation succeeded |
| cid | string | Yes | Correlation ID for request tracking |
| msg_id | string | Yes | Unique message ID |
| status | string | Yes | HTTP status description (e.g., "200 OK") |
Samples
OK, data sent and message ID returned:
$ curl -XPOST http://user.1:password.1@localhost:11223/pubsub/topic/orders.processed \
-d '{"data":"Order #12345 has been processed", "priority": 7}'
{
"is_ok": true,
"cid": "correlation-id-123",
"msg_id": "zpsm.20250829-074432-7264-d47439a9f-abc",
"status": "200 OK"
}
$
Error, no data sent on input:
$ curl -XPOST http://user.1:password.1@localhost:11223/pubsub/topic/orders.processed \
-d '{}'
{
"is_ok": false,
"cid": "correlation-id-456",
"details": "Invalid request data",
"status": "400 Bad Request"
}
$
Getting messages from queues
Messages from all subscribed topics are retrieved through a single endpoint. Optional parameters control the number and size of messages returned.
Each retrieved message stays in the queue until the client acknowledges it through /pubsub/messages/ack:
- A call to
/pubsub/messages/gethands the messages out to this client and reserves them for 30 seconds, during which no other call receives them. - The client processes the messages and sends their
msg_idvalues to/pubsub/messages/ack, which removes them from the queue. - A message that was not acknowledged within the 30 seconds is handed out again by the next call to
/pubsub/messages/get. A response that never reached the client, for instance because the connection was lost, therefore loses no messages.
A client that processes the same message twice with the same result needs no further precautions. Otherwise, it records the msg_id of each processed message and skips a message whose msg_id it already processed. The reservation period is set through the Zato_PubSub_Pull_Lease_Seconds environment variable of the server.
| Verb | URL |
|---|---|
| POST | /pubsub/messages/get |
Request
| Parameter | Datatype | Required | Notes |
|---|---|---|---|
| max_messages | integer | --- | Maximum number of messages to retrieve. Defaults to 50, maximum is 1000. |
| max_len | integer | --- | Maximum total length of message data in bytes. Defaults to 20000000 (20 MB), which is also the maximum value. A message larger than this is returned on its own. |
Response
| Parameter | Datatype | Required | Notes |
|---|---|---|---|
| is_ok | boolean | Yes | Whether the operation succeeded |
| cid | string | Yes | Correlation ID for request tracking |
| messages | array | --- | Array of messages (possibly empty if none were enqueued) |
| data | any | --- | Message data (present for single message response) |
| meta | object | --- | Message metadata (present for single message response) |
| message_count | integer | Yes | Number of messages returned |
| status | string | Yes | HTTP status description (e.g., "200 OK") |
Message metadata fields
| Field | Datatype | Notes |
|---|---|---|
| topic_name | string | Topic the message was published to |
| size | integer | Message size in bytes |
| priority | integer | Message priority (0-9) |
| expiration | integer | Message expiration time in seconds |
| msg_id | string | Unique message identifier |
| delivery_attempt | integer | How many times the message was retrieved, 1 for the first retrieval and higher for each repeated one |
| correl_id | string | Correlation ID for message tracking |
| pub_time_iso | string | When the message was published (ISO format with timezone) |
| recv_time_iso | string | When the message was received by the system (ISO format with timezone) |
| expiration_time_iso | string | When the message will expire (ISO format with timezone) |
| time_since_pub | string | Time elapsed since message was published (duration format) |
| time_since_recv | string | Time elapsed since message was received (duration format) |
| ext_client_id | string | External client identifier (optional) |
| in_reply_to | string | ID of message this is replying to (optional) |
| sub_key | string | Subscription key for the receiving user |
Samples
OK, multiple messages returned:
$ curl -XPOST http://user.1:password.1@localhost:11223/pubsub/messages/get \
-d '{"max_messages": 5}'
{
"is_ok": true,
"cid": "correlation-id-789",
"messages": [
{
"data": {
"order_id": 12345,
"status": "completed"
},
"meta": {
"topic_name": "orders.processed",
"size": 45,
"priority": 5,
"expiration": 3600,
"msg_id": "zpsm.20250829-074432-7264-d47439a9f-abc",
"delivery_attempt": 1,
"correl_id": "order-12345",
"pub_time_iso": "2025-01-01T12:00:00+00:00",
"recv_time_iso": "2025-01-01T12:00:01+00:00",
"expiration_time_iso": "2025-01-01T13:00:00+00:00",
"time_since_pub": "0:00:30.123456",
"time_since_recv": "0:00:30.123456"
}
}
],
"message_count": 1,
"status": "200 OK"
}
$
OK, no messages available:
$ curl -XPOST http://user.1:password.1@localhost:11223/pubsub/messages/get
{
"is_ok": true,
"cid": "correlation-id-101",
"messages": [],
"message_count": 0,
"status": "200 OK"
}
$
Error, no subscription found for user:
$ curl -XPOST http://user.1:password.1@localhost:11223/pubsub/messages/get
{
"is_ok": false,
"cid": "correlation-id-102",
"details": "No subscription found for user",
"status": "401 Unauthorized"
}
$
Acknowledging messages
Messages retrieved from a queue are removed from it when the client acknowledges them by their msg_id values.
| Verb | URL |
|---|---|
| POST | /pubsub/messages/ack |
Request
| Parameter | Datatype | Required | Notes |
|---|---|---|---|
| msg_ids | array | Yes | The msg_id values of the messages to acknowledge, at most 1000 of them. |
Response
| Parameter | Datatype | Required | Notes |
|---|---|---|---|
| is_ok | boolean | Yes | Whether the operation succeeded |
| cid | string | Yes | Correlation ID for request tracking |
| ack_count | integer | --- | How many of the messages were still in the queue and were removed from it |
| status | string | Yes | HTTP status description (e.g., "200 OK") |
Samples
OK, both messages acknowledged:
$ curl -XPOST http://user.1:password.1@localhost:11223/pubsub/messages/ack \
-d '{"msg_ids": ["zpsm.20250829-074432-7264-d47439a9f-abc", "zpsm.20250829-074433-1182-a03b5c71e-abc"]}'
{
"is_ok": true,
"cid": "correlation-id-103",
"ack_count": 2,
"status": "200 OK"
}
$
OK, the messages were already acknowledged earlier:
$ curl -XPOST http://user.1:password.1@localhost:11223/pubsub/messages/ack \
-d '{"msg_ids": ["zpsm.20250829-074432-7264-d47439a9f-abc"]}'
{
"is_ok": true,
"cid": "correlation-id-104",
"ack_count": 0,
"status": "200 OK"
}
$
Data format
- All requests and responses use JSON format
- Authentication is always with HTTP Basic Auth
- All responses include an
is_okboolean field indicating success or failure - All responses include a
cidfield for correlation tracking - Error responses include a
detailsfield with error description - Success responses include a
statusfield with HTTP status description
Success response example:
Error response example:
{
"is_ok": false,
"cid": "correlation-id-456",
"details": "Authentication failed",
"status": "401 Unauthorized"
}
Topic name restrictions
- Maximum length: 200 characters
- Only ASCII characters are permitted
- The "#" character is not allowed
- Topic names are case-insensitive
Getting started with EDA
- What is EDA?
What Event-Driven Architecture is and how it helps in systems integrations
- Topics and message queues
Understanding the concepts of topics that messages are published to and queues that messages are read from
- Publishers and subscribers
How APIs and systems can communicate with the broker to publish and subscribe to their messages
- Security and access control
How to grant and secure access to your topics and message queues