Authentication and scope
Every endpoint requires an authenticated session and workspace context. A workspace-scoped channel is managed byADMIN or OWNER. A personal channel
is managed only by its owner. Channel-side agent pairing uses the same rule.
Template endpoints are workspace-wide and require ADMIN or OWNER.
Secrets and destination addresses are not returned by the agent-pairing API.
Agent access is default-deny: an agent can send only after a human grants the
specific (channel, agent) pairing.
All routes require authentication and workspace context. Missing workspace
context is 400; no authenticated user is 401; a non-member is 403.
Handler/database failures are 500 unless a route below specifies another
status.
Channel contracts
GET /api/v1/notification-channels
Returns 200 OK with an object containing a channels array. The default
scope includes all workspace channels and the authenticated user’s personal
channels. ?scope=all is an admin overview that also includes other members’
personal channels, but redacts their destination fields. Secrets are never
returned.
POST /api/v1/notification-channels
Creates a channel and returns 201 Created. Workspace channels require
ADMIN or OWNER; personal: true lets any member create a channel owned by
the authenticated user. The server ignores any client-supplied owner.
type is email, webhook, or shoutrrr. Email uses to; shoutrrr uses
provider plus provider-specific fields (or the compatibility
shoutrrr_url). events defaults to ["run.failed"] and accepts
completed, failed, or all; an empty categories list means every
category; min_priority defaults to low. The response includes secret
only on this create response. For a webhook it is the HMAC secret; for
shoutrrr it is the composed service URL.
PATCH /api/v1/notification-channels/{id}
Auth: authenticated workspace member; workspace channels require ADMIN
or OWNER, personal channels require their owner.
Updates only supplied settings and returns 200 OK with
{ "updated": "nch_01..." }. Optional fields are enabled (boolean),
categories (array; empty means every category), min_priority (low,
medium, high, or urgent), and events (legacy completed, failed, or
all). Workspace channels require ADMIN or OWNER; personal channels
require their owner. Invalid input is 400; an unavailable channel is 404.
POST /api/v1/notification-channels/{id}/test
Sends a synthetic run.completed event and returns 200 OK with
{ "ok": true, "channel_id": "nch_01..." }. A delivery failure returns
502; authorization follows the PATCH rule.
DELETE /api/v1/notification-channels/{id}
Deletes the channel and returns 200 OK with { "deleted": "nch_01..." }.
Missing or unauthorized channels return 404 or 403 respectively.
POST /api/v1/notification-channels/test
Auth: authenticated workspace member with workspace context.
Tests an unsaved draft without persisting it. The body accepts the delivery
fields needed to compose a channel (type, url/to, or provider plus
fields, with optional secret) and the response is 200 OK with
{ "ok": true }. Invalid drafts return 400; a provider or mailer failure
returns 502.
type must be email, webhook, or shoutrrr. Email drafts require to,
webhook drafts require url, and shoutrrr drafts require a known provider and
all provider fields (or a composed shoutrrr_url).
Agent pairing
GET /api/v1/notification-channels/{id}/agents
Auth: authenticated workspace member; channel access follows the channel
owner/manage permission.
Lists agents allowed to send to the channel.
POST /api/v1/notification-channels/{id}/agents
Auth: authenticated workspace member with manage permission for the
channel (ADMIN/OWNER for workspace channels, owner for personal channels).
Allows an agent from the current workspace to send to the channel.
Request:
DELETE /api/v1/notification-channels/{id}/agents/{agentId}
Revokes the pairing. Response:
404 when the agent was not paired with the channel.
Invalid path or JSON input is 400; an unauthorized personal channel is
403; a pairing-store failure is 500.
Provider registry
GET /api/v1/notification-providers
Auth: any authenticated workspace member. Request: no body.
Response: 200 OK:
500.
PATCH /api/v1/notification-providers/{provider}
Auth: ADMIN or OWNER. Request: JSON { "enabled": true }.
Response: 200 OK with { "provider": "slack", "enabled": true }.
Unknown providers return 404; invalid JSON returns 400; a settings write
failure returns 500. Disabling a provider blocks new channel creation but
does not delete or disable existing channels.
Notification templates
Templates change the wording of notifications generated by Crewship. They do not rewrite text authored by a routinenotify step or by an agent.
GET /api/v1/notification-templates
Lists workspace overrides. An empty channel_id applies to every channel.
ADMIN or OWNER. Request: no body. Response: 200 OK
with { "templates": [...] }; 400 when workspace context is missing, 401
without authentication, 403 for a non-member or insufficient role, and
500 for the template query.
PUT /api/v1/notification-templates
Creates or replaces one category/channel override.
200 OK. Empty title and body remove the
override. Categories and template references are validated on write; invalid
input returns 400.
Auth: ADMIN or OWNER. Request: JSON { "category", "channel_id", "title", "body" }. Response: 200 OK with the saved template;
400 for invalid JSON, category, or template reference; 401 without
authentication; 403 for a non-member or insufficient role; and 500 for a
persistence failure.
Supported references are {{ vars.<fact> }}, {{ source.title }},
{{ source.body }}, {{ source.category }}, and {{ source.kind }}. Missing
facts render as empty; if a rendered title or body is empty, Crewship keeps the
producer’s original wording.
DELETE /api/v1/notification-templates
Removes an override. category is required; channel_id is optional.
204 No Content. Deleting an override that does not exist is
intentionally idempotent.
Auth: ADMIN or OWNER. Request: required category and optional
channel_id query parameters; no body. Statuses: 204 No Content, 400
when category or workspace context is missing, 401 without authentication,
403 for a non-member or insufficient role, or 500 for a delete failure.
Delivery log
GET /api/v1/notification-deliveries
Lists outbound delivery attempts for the current workspace. This endpoint is
restricted to ADMIN and OWNER because the log spans every recipient.
Response:
error is omitted when there is no recorded error. The result is ordered
newest first and is always an object containing a deliveries array, including
when no rows match.