Topics
A topic is a named stream of messages. Topics are concrete names; patterns are only used for permissions. Use public flags for open read/publish access, and permissions or share tokens for scoped access.
Naming
Topic names are at least 3 characters and use only a–z, A–Z,
0–9, ., -, and _.
The dot is the recommended hierarchy separator (NATS-style):
alerts
alerts.disk
alerts.disk.full
deploy.prod.api
home.frontdoor
Topics are concrete. Subscribing to alerts.disk does not
subscribe you to alerts.cpu. Wildcard subscriptions don't exist;
you subscribe to each name explicitly. Wildcards do exist for permissions
(see Permissions).
Access flags
Every topic has two independent public access flags. By default both are false,
unless PINGD_DEFAULT_PUBLIC_READ or PINGD_DEFAULT_PUBLIC_PUBLISH
is set. Without public access, a new topic is private.
The full access matrix:
publicRead | publicPublish | Default access |
|---|---|---|
| false | false | private; owner, admin, matching permission, or share token only |
| true | false | public read, restricted publish |
| false | true | restricted read, public publish |
| true | true | public read and publish |
Admin and owner access are resolved before permissions, so they always have read/publish
access. For non-owners, a matching deny permission overrides public flags.
Share tokens
For per-topic credentials, the owner or an admin creates a share token with fixed access:
ro, wo, or rw.
Clients send the token in X-Topic-Token.
curl http://localhost:7685/topics/alerts/messages \
-H 'X-Topic-Token: tk_...' \
-H 'Content-Type: application/json' \
-d '{ "payload": { "body": "Hello" } }'
Share tokens can expire and can be rotated or revoked without changing the topic's public flags. See Permissions for details.
Endpoints
| Method | Path | Description |
|---|---|---|
| GET | /topics | List topics visible to caller |
| POST | /topics | Create topic (auth required) |
| GET | /topics/:name | Get a topic |
| PATCH | /topics/:name | Update public flags (owner or admin) |
| DELETE | /topics/:name | Delete topic (owner or admin) |
| GET | /topics/:name/stats | Stats (admin only) |
| GET | /topics/:name/shares | List share tokens (owner or admin) |
| POST | /topics/:name/shares | Create share token (owner or admin) |
| PATCH | /topics/:name/shares/:id | Update share token (owner or admin) |
| POST | /topics/:name/shares/:id/rotate | Rotate share token (owner or admin) |
| DELETE | /topics/:name/shares/:id | Revoke share token (owner or admin) |
Create
curl -s http://localhost:7685/topics \
-H 'Authorization: Bearer $TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"name": "alerts.critical",
"publicRead": true,
"publicPublish": false
}'
pingd-cli topics create \
--name alerts.critical \
--public-read
import requests
requests.post(
"http://localhost:7685/topics",
headers={"Authorization": "Bearer TOKEN"},
json={
"name": "alerts.critical",
"publicRead": True,
"publicPublish": False,
},
)
The caller becomes the owner.
Update
curl -s -X PATCH http://localhost:7685/topics/alerts.critical \
-H 'Authorization: Bearer $TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"publicRead": false,
"publicPublish": false
}'
pingd-cli topics update \
--name alerts.critical \
--no-public-read \
--no-public-publish
import requests
requests.patch(
"http://localhost:7685/topics/alerts.critical",
headers={"Authorization": "Bearer TOKEN"},
json={
"publicRead": False,
"publicPublish": False,
},
)
Owner-or-admin only. Omitted fields keep their existing values.
Delete
curl -s -X DELETE http://localhost:7685/topics/alerts.critical \
-H 'Authorization: Bearer $TOKEN'
pingd-cli topics delete --name alerts.critical
import requests
requests.delete(
"http://localhost:7685/topics/alerts.critical",
headers={"Authorization": "Bearer TOKEN"},
)
Cascades to messages, deliveries, subscriptions, share tokens, and webhooks attached to the topic. Pattern permissions are not topic-owned rows and are not deleted.
Stats
Admin-only. Returns counts of messages, active subscriptions, deliveries, and recent activity for capacity planning.
curl -s http://localhost:7685/topics/alerts.critical/stats \
-H 'Authorization: Bearer $TOKEN'
pingd-cli topics stats --name alerts.critical
import requests
response = requests.get(
"http://localhost:7685/topics/alerts.critical/stats",
headers={"Authorization": "Bearer TOKEN"},
)
print(response.json())
Naming conventions
Use dots to namespace by domain. Examples that work well in practice:
alerts.disk,alerts.cpu,alerts.networkdeploy.prod.api,deploy.staging.webhome.frontdoor,home.dishwasherci.github.repo-name
Then a permission like alerts.> covers everything under alerts,
and a CI service token can be limited to deploy.>.