Usage
Sending
Section titled “Sending”Two dispatch modes, and the difference matters operationally:
POST /notification/:type/sync inline send, returns the provider receiptPOST /notification/:type/async queue to the outbox; a daemon delivers{ "templatename": "welcome-onboarding", "data": { "firstname": "Alex" }, "provider_context": { }, "idempotency_key": "optional-caller-supplied-key"}Use sync when the caller needs to know the send succeeded — a password reset, a one-time
code, anything where the user is waiting on the message to continue. Use async for
everything else; the outbox daemon owns retries, provider latency stays off your request path,
and you get durability with it.
Addressing
Section titled “Addressing”Three ways to say who receives the message, in increasing order of how much the block does for you.
By explicit recipient
Section titled “By explicit recipient”The provider_context.to form above. The caller supplies the address. Use it when you genuinely
have an address and no user record — a transactional email to someone who is not a user yet.
By user
Section titled “By user”POST /notify/multi{ "templatename": "welcome-onboarding", "user": "myrealm:user-ulid", "data": { "firstname": "Alex" }}The block resolves the user’s preferred channel and contact details from their stored preferences, then dispatches. Prefer this form. Passing raw addresses works but bypasses preference resolution, which means every feature that sends something has to independently remember whether this person opted out of SMS.
By list
Section titled “By list”POST /notify/list{ "templatename": "monthly-newsletter", "list": "list-ulid", "data": { "month": "May" }}Templates and data
Section titled “Templates and data”A send names a template and supplies data. The template owns wording, formatting and
per-channel variants; the caller owns the values. That split is what lets copy change without a
deploy, and it is why the API takes a template name rather than a rendered body.
GET /template?name=… one templateGET /template the whole listIn-app inbox
Section titled “In-app inbox”For the in-app channel the block also serves the reader side, so you do not build an inbox:
PATCH /inapp/user paginated list of unseen notificationsGET /inapp/user/new unseen countPUT /inapp/user mark as seen, by idGET /inapp/user/new is the one to poll for a badge count — it is cheap and returns a number
rather than a page of records.
POST /notificationlist createGET /notificationlist listPUT /notificationlist updateDELETE /notificationlist/:id deleteLists are saved recipient sets. They belong here rather than in your application because suppression applies at send time — a recipient who opted out stays on the list and simply does not receive, which is the behaviour you want when they opt back in.
- Operations — provider configuration, routing and monitoring