API

Notifications

Configure channels, subscriptions, and alert delivery.

The Notifications API decides who hears about events like a failed deploy or an expiring SSL cert, and how. You register channels (where alerts go — email, webhook, Slack, Discord, Microsoft Teams, or the in-app bell), toggle subscriptions (which event categories reach each channel), set org-wide defaults for new members, and read deliveries (the alert feed behind the bell icon). In the dashboard this is the Settings → Notifications page. Channels, subscriptions, and deliveries are per-user; defaults are per-org.

Available on every instance

This module ships on both self-hosted and cloud instances. There is no dedicated openship CLI command — manage notifications from the dashboard or these endpoints directly.

Categories

Categories are the stable, user-facing event groups (e.g. deploy.failed, backup.failed, domain.expiring) that subscriptions and defaults key off. They live in code, not the database, so GET /api/notifications/categories is a static registry — each entry has an id, group, label, description, and defaultEnabled.

The response also carries a groups array ({ id, label }, already in display order) that the categories' group field points into — deployment, app_health, backups, jobs, domains, members, billing. The billing group and its categories are omitted outside Openship Cloud, where nothing can fire them.

const result = await ship.notifications.categories();
console.log(result);
curl "$OPENSHIP_URL/api/notifications/categories" \
  -H "Authorization: Bearer $OPENSHIP_TOKEN"

Create a channel

A channel is a destination. The config object is shape-checked per kind; secrets in it (webhook signing keys, Slack URLs, Telegram bot tokens) are stored encrypted and never returned in full.

const result = await ship.notifications.createChannel({
  kind: "email",
  label: "On-call inbox",
  config: {
    address: "ops@example.com",
  },
});
console.log(result);
curl -X POST "$OPENSHIP_URL/api/notifications/channels" \
  -H "Authorization: Bearer $OPENSHIP_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"kind":"email","label":"On-call inbox","config":{"address":"ops@example.com"}}'

Prop

Type

The config shape depends on kind:

Prop

Type

Getting a Teams webhook URL

In Teams, create a Workflow with the "When a Teams webhook request is received" trigger and use the URL it generates. Legacy webhook.office.com connector URLs are also accepted. The URL is stored encrypted and comes back as webhookUrlConfigured in responses, never in full.

Getting a Telegram bot token and chat id

Message @BotFather → /newbot for the token. A bot can only write to a chat that has already started it, so send the bot a message (or add it to your group) first. For the chat id, call https://api.telegram.org/bot<token>/getUpdates and read result[].message.chat.id — group ids are negative. Editing a Telegram channel without resending botToken keeps the stored one.

New channels start enabled: true. An in_app channel is verified immediately; every other kind starts unverified and must be verified (via a test send) before it will deliver — flip verified with PATCH.

Update a channel

Send only the fields you want to change. Changing config on a non-in_app channel resets verified to false, since the destination may have moved.

PATCH /api/notifications/channels/:id

Prop

Type

Subscribe a channel to a category

A subscription is one toggle in the (user, org, category, channel) grid. PUT is an idempotent upsert — send the same triple again to flip enabled. The channelId must be a channel you own.

const result = await ship.notifications.upsertSubscription({
  category: "deploy.failed",
  channelId: "chan_123",
  enabled: true,
});
console.log(result);
curl -X PUT "$OPENSHIP_URL/api/notifications/subscriptions" \
  -H "Authorization: Bearer $OPENSHIP_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"category":"deploy.failed","channelId":"chan_123","enabled":true}'

Prop

Type

Org defaults

Defaults seed the subscription grid for new members of the org. Setting a default is admin-only (notifications:admin); reading them is not.

PUT /api/notifications/defaults

Prop

Type

Read the alert feed

GET /api/notifications/deliveries returns your recent deliveries in the active org — this is the history behind the bell icon. GET /api/notifications/deliveries/unseen-count powers the badge, and POST /api/notifications/deliveries/:id/seen clears one.

const result = await ship.notifications.listDeliveries({
  unseen: true,
  limit: 20,
});
console.log(result);
curl "$OPENSHIP_URL/api/notifications/deliveries?unseen=true&limit=20" \
  -H "Authorization: Bearer $OPENSHIP_TOKEN"

Prop

Type

Errors

400 — invalid channel or missing fields

The kind isn't one of email/webhook/in_app/slack/discord/msteams/telegram, label is missing, or the config failed its per-kind check (a malformed email, a non-http(s) webhook URL, a Slack URL that isn't https://hooks.slack.com/..., a Discord URL that isn't https://discord.com/api/webhooks/..., a Teams URL that isn't an https Workflow or webhook.office.com URL, or a Telegram token/chat id that isn't in <id>:<secret> / numeric-or-@name form). Subscriptions need category, channelId, and a boolean enabled; defaults need category and a boolean defaultEnabled.

404 on a per-user route

The channel, subscription, or delivery :id doesn't belong to you (or was deleted). List your own with the matching GET route to get valid ids.

Operations

OperationSDKREST API
List supported notification categories and events.notifications.categories()GET /api/notifications/categories
notifications:read
List configured delivery channels.notifications.listChannels()GET /api/notifications/channels
notifications:read
Create a delivery channel.notifications.createChannel(input)POST /api/notifications/channels
notifications:write
Read notification subscriptions.notifications.listSubscriptions()GET /api/notifications/subscriptions
notifications:read
Create or update a subscription.notifications.upsertSubscription(input)PUT /api/notifications/subscriptions
notifications:write
Read default notification routing.notifications.listDefaults()GET /api/notifications/defaults
notifications:read
Set default notification routing for a category.notifications.upsertDefault(input)PUT /api/notifications/defaults
notifications:admin
Read notification delivery history.notifications.listDeliveries(input?)GET /api/notifications/deliveries
notifications:read
Count notifications the user has not seen.notifications.unseenCount()GET /api/notifications/deliveries/unseen-count
notifications:read
Update channel configuration or rotate credentials.notifications.updateChannel(id, input)PATCH /api/notifications/channels/:id
notifications:write
Test the channel’s delivery configuration.notifications.testChannel(id)POST /api/notifications/channels/:id/test
notifications:write
Remove a delivery channel.notifications.removeChannel(id)DELETE /api/notifications/channels/:id
notifications:write
Remove a subscription.notifications.removeSubscription(id)DELETE /api/notifications/subscriptions/:id
notifications:write
Mark the selected notifications seen.notifications.markSeen(id)POST /api/notifications/deliveries/:id/seen
notifications:write

On this page