Channels and Delivery
Channels are where inbox policy lives: who may send, what a message must carry, and how delivery behaves. Creating a channel requires a current tenant administrator or live service principal, plus creation authority in the chosen workspace. A regular organization member cannot create channels just by claiming an admin role in a JWT. Channel reads and lists follow workspace/channel reader rules, including explicit grants and their expiry or revocation.
Creating channels
snug inbox channel create --name docs4.alerts \
--description "Docs guide channel" \
--actions-allowed --scheduled-delivery-allowed
snug inbox channel list
snug inbox channel get --channel-id 0199e100-0000-7000-8000-00000000000bThe created channel (captured live) - note the server assigns a random
channel_id, which is what every send and filter refers to, not the
name:
{
"channel_id": "0199e100-0000-7000-8000-00000000000b",
"name": "docs4.alerts",
"workspace_id": "root",
"allowed_producers": [],
"default_priority": "normal",
"retention_days": 90,
"actions_allowed": true,
"technical_notes_required": false,
"delivery_policy": {
"pubsub_topic": null,
"scheduled_delivery_allowed": true,
"websocket_fanout": false
},
"created_by": "docs-wave-admin", ...
}Use --workspace-id (HTTP workspace_id) when creating a channel in a named
workspace; omission selects the account root. Share channel reader/editor/manager
access through /api/v1/access/inbox-channels/{channel_id}/grants. Editor grants
allow producing; manager grants permit sharing and bypassing the producer allowlist.
None grants access to another recipient's messages, counts, threads or actions.
There is no delete or update endpoint - channel policy is fixed at
creation. channel list speaks the
standard list contract: q over name and
description (GET /api/v1/inbox/channels?q=docs4, or -q docs4), filters on
default_priority, actions_allowed, technical_notes_required,
created_by, created_at, and updated_at, and sorts on created_at
(newest first by default) and name.
Policy gates on send
Each gate below applies to a restricted channel created with --producer svc-docs4 --technical-notes-required:
- Producer allowlist - a sender first needs channel editor/manager or
workspace creation authority. An empty
allowed_producerslist adds no extra restriction. A nonempty list admits only the listed principal IDs or channel managers; other producers receive403 producer_not_allowed. Sender identity and kind come from the verified actor and cannot be supplied as a privilege flag. - Technical notes - with
technical_notes_required, a send must include technical notes with a non-empty summary (CLI--notes, HTTPtechnical_notes.summary) or it fails with400 technical_notes_required. Notes are structured handoff context: summary, risk level, open questions, successor hint. - Actions gate - attaching actions on a channel without
actions_allowedfails with400 actions_not_allowed. - Scheduled delivery gate - a future
deliver_aton a channel withoutscheduled_delivery_allowedfails with400 scheduled_delivery_not_allowed.
Scheduled delivery
On a channel that allows it, a future deliver_at returns
"status": "scheduled" and the message stays invisible to the recipient
until due:
snug inbox send --to user_123 --channel 0199e100-0000-7000-8000-00000000000b \
--title "Scheduled ping" --msg "See you soon" \
--deliver-at 2026-08-28T05:04:01ZPromotion is automatic: the server runs delivery workers on a roughly one-second tick. The message was absent from the list immediately after sending and present a few seconds after its due time, with no manual step.
Expiry and self-destruct
Two per-message controls, both HTTP-only fields on send:
expires_at- the message is swept once the timestamp passes.self_destruct_after_read_seconds- a countdown that starts when the message is read. With a 2-second fuse: after reading and waiting, the message was not deleted but redacted - title replaced with[self-destructed], body emptied, and the message auto-archived.
The same background workers that promote scheduled messages run these sweeps continuously.
Manual maintenance
POST /api/v1/inbox/maintenance/run (CLI: snug inbox maintenance)
force-runs one round of the promotion, expiry, and self-destruct sweeps
and reports what it did for the current tenant. It requires live tenant
administrator authority; a regular member receives 403 insufficient_permissions:
{ "promoted": 0, "expired": 0, "self_destructed": 0 }Since the server sweeps on its own, this endpoint is for operations - forcing a sweep in tests or after bulk imports - not something clients need in normal use.
Thread retention
Thread summaries record delivery history. Their message count and highest priority remain after messages expire or are deleted. The latest-message ID identifies the last delivery and may no longer resolve after deletion. Unread counts are computed from the currently retained unread messages. Thread list filters, sorting and pagination run in PostgreSQL.
Self-destruction redacts the latest title in a matching thread summary in the same
transaction as the message. Deleting the latest message replaces that summary title
with [deleted]. An older message's deletion or self-destruction never overwrites a
newer delivery's title. The summary's delivery counts remain intact.
