SOLWYN
Commands

notifications / channels

Reusable account notification channels and each project's delivery routing, with secrets that never touch argv

Two command groups configure where alerts are delivered. channels manages the account's reusable delivery destinations — Slack, PagerDuty, Microsoft Teams, Discord, and Telegram — each with stored credentials and an id. notifications manages one project's routing: which channel ids it uses, a severity floor, an event-type allow-list, and whether email and SMS are on. Budget rules reference the same channel ids, so a channel is created once and used everywhere.

Both groups share one rule for credentials: a secret is never a command-line argument. Supply it on stdin with --secret-stdin, inside a JSON object with --config-stdin, or through the SOLWYN_CHANNEL_SECRET environment variable. Reads mask every stored secret to its final four characters, and any echo of a secret you supplied — in a success payload or an API error — is replaced with [REDACTED]. Unlike a webhook signing secret, a channel credential is never revealed, not even once.

Channels need a paid plan (Production and above). A Free-tier account gets the API's upgrade response on channels create, exit 1, with a link to the dashboard's billing page. See Alerts & notifications for the dashboard view of the same settings.

channels

Every channels subcommand requires a user login (JWT); a project key exits 3 before any request. create, update, test, and delete additionally require the account owner role — the API answers 403 and the CLI exits 3 with a hint to inspect your role with solwyn whoami.

Contract
AuthJWT; owner for mutations
Exit codes0 success · 1 generic/API or delivery failure · 2 usage · 3 auth · 5 not found
JSON schemassolwyn.channels.list.v1 · solwyn.channels.v1 · solwyn.channels.test.v1 · solwyn.channels.delete.v1

What each type needs

TypeCredential fieldsRequired to create
slackwebhook_url, bot_token, channelwebhook_url, or bot_token plus channel
pagerdutyrouting_key, api_tokenrouting_key
teamswebhook_urlwebhook_url
discordwebhook_urlwebhook_url
telegrambot_token, chat_idbot_token plus chat_id

The first field listed for each type is its primary secret — the one --secret-stdin and SOLWYN_CHANNEL_SECRET fill unless you name another with --secret-field. These requirements are checked locally, so a misconfigured create exits 2 without a network call.

channels list

Terminal
$ solwyn channels list
ID      Type   Name
ch_one  slack  Ops

The table shows three columns; the JSON payload carries every channel's full configuration with secrets masked ("webhook_url":"****abcd").

channels show

Terminal
$ solwyn channels show ch_one
Field              Value
ID                 ch_one
Account            acct_one
Type               slack
Name               Ops
slack.webhook_url  ****abcd
slack.bot_token    —
slack.channel      —
Created            2026-09-01T12:00:00Z
Updated            2026-09-02T12:00:00Z

Secret fields retain only their final four characters. The CLI masks defensively — even if the API returned a full value, the output would still show ****abcd.

channels create

Terminal
solwyn channels create --type <type> --name <name> \
  [--secret-stdin] [--secret-field <field>] [--channel <id>] [--chat-id <id>] | [--config-stdin]
OptionTypeDefaultPurpose
--typeslack | pagerduty | teams | discord | telegramrequiredChannel type. Immutable after creation.
--namestringrequiredDisplay name; must not be blank.
--secret-stdinbooleanfalseRead the primary secret (or the --secret-field) from stdin. Without it, SOLWYN_CHANNEL_SECRET is consulted.
--secret-fieldstringtype's primaryWhich secret field the stdin or environment value fills. Must name a secret field for the type.
--channelstringnoneSlack destination id, for bot-token mode.
--chat-idstringnoneTelegram destination id.
--config-stdinbooleanfalseRead the whole type-specific configuration as a JSON object from stdin, secrets included. Cannot be combined with the four options above.

Two ways to supply the credential:

Terminal
$ printf '%s' "$SLACK_WEBHOOK_URL" | solwyn channels create --type slack --name Ops --secret-stdin

For Slack bot-token mode, name the field and the destination:

Terminal
$ printf '%s' "$SLACK_BOT_TOKEN" | solwyn channels create \
    --type slack --name Ops --secret-stdin --secret-field bot_token --channel C0123456789
Terminal
$ echo '{"routing_key":"'"$PD_KEY"'","api_token":"'"$PD_TOKEN"'"}' \
    | solwyn channels create --type pagerduty --name On-call --config-stdin

The object may set any field of the type, including optional secrets. A key outside the type's field set, a non-string value, or a masked ****… value is a usage error.

stdin is read only when a flag opts in, so an interactive create never blocks waiting for input. A blank secret, or none at all when the type requires one, exits 2. The output is the same table as channels show.

channels update

Terminal
solwyn channels update <channel_id> [--name <name>] [--secret-stdin] [--secret-field <field>] [--channel <id>] [--chat-id <id>] | [--config-stdin]

Change the name, the credentials, or both. At least one is required. Omitted values stay unchanged, and the type cannot change — the CLI reads the existing channel first to learn its type, then writes.

  • Passing a masked value (****abcd) back keeps the stored credential.
  • With --config-stdin, a JSON null clears exactly that field: {"bot_token": null}. The API refuses a clear that would leave the channel unusable (for example, removing a Slack channel's only webhook URL) and the CLI relays that constraint with exit 1.
  • Setting SOLWYN_CHANNEL_SECRET counts as a credential update even with no flags.

channels show

Terminal
solwyn channels show chan_example

Read one channel by ID with masked configuration, using solwyn.channels.v1. Any JWT role can read it; no credential is revealed.

channels test

Send a real test message through a stored channel using its stored credentials. No secret input is needed.

Terminal
$ solwyn channels test ch_one
Field    Value
Success  true
Message  Test sent

A delivery the API reports as failed — success: false on an HTTP 200 — still exits 1 after printing the payload, so a script can gate on the exit code alone.

channels delete

Delete a channel. The API also removes its id from every project's notification settings and from every budget rule's channel_ids. Deletion displays routing effects on stderr and requires confirmation or --yes. Without a TTY and without --yes, it exits 2 before HTTP. Decline, EOF or Ctrl-C submits no deletion.

Terminal
$ solwyn channels delete ch_one --yes
Field    Value
Id       ch_one
Deleted  true

Use channels delete ID --yes only after reviewing its removal and routing effects. Channel deletion is CLI-only.

notifications

notifications manages one project's routing and requires a project; a missing one exits 2. show and set accept either credential — a project key or a login — though writes need a full-scope key or owner/admin JWT (project.write). notifications test email is the exception: it sends to your account address, so it requires a login.

Contract
Authany (full-scope key for writes); test email requires JWT
Exit codes0 success · 1 generic/API or delivery failure · 2 usage · 3 auth · 5 not found
JSON schemassolwyn.notifications.v1 · solwyn.notifications.test.v1

notifications show

Terminal
$ solwyn --project proj_0123456789abcdef01234567 notifications show
Field                 Value
Channels              ch_one
Severity              warning
Events                all events
Email                 true
SMS                   false
Available channels    email, sms, slack
SMS allowed events    budget_exceeded
Email allowed events  budget_threshold

The last three rows report the account's tier capabilities — which channel kinds the plan unlocks and which event types email and SMS may carry — so you can see why a setting has no effect before you change it. The JSON payload adds the full (masked) channel objects under channels, alongside channel_ids, severity_threshold, enabled_event_types, email, sms_config, and capabilities.

notifications set

Change only the settings you name; everything else is preserved.

Terminal
solwyn --project <project_id> notifications set [OPTIONS]
OptionTypePurpose
--channelstring, repeatableChannel id. Repeating replaces the whole reference list.
--clear-channelsbooleanRemove every channel reference.
--severityinfo | low | warning | medium | high | criticalSeverity floor — events below it are not delivered.
--eventstring, repeatableEvent type to allow. Repeat for several; the API accepts future event names.
--all-eventsbooleanAllow every event type (clears the allow-list).
--email / --no-emailbooleanTurn email delivery on or off.
--sms / --no-smsbooleanTurn SMS delivery on or off. SMS needs Production or above, a verified phone number, and consent.
--reset-emailbooleanReset email to its enabled default.
--reset-smsbooleanReset SMS to its disabled default.

A setting and its clear or reset option cannot be combined (--channel with --clear-channels, --event with --all-events, --email with --reset-email, --sms with --reset-sms); running set with no options at all is also a usage error. Both exit 2. The response is the same as notifications show.

Terminal
$ solwyn --project proj_0123456789abcdef01234567 notifications set \
    --channel ch_one --channel ch_two --severity high --event budget_exceeded

notifications test

Test delivery for one channel kind, or check SMS eligibility.

Terminal
solwyn --project <project_id> notifications test <slack|pagerduty|sms|email> [--secret-stdin]
ChannelInputWhat happens
slackwebhook URL via --secret-stdin or SOLWYN_CHANNEL_SECRETSends a real test message.
pagerdutyrouting key via --secret-stdin or SOLWYN_CHANNEL_SECRETSends a real test event.
smsnoneChecks eligibility only — no message is sent.
emailnone; requires JWTSends a real email to the account's alert address.

This command tests a credential you hold, before you store it. To test a channel that is already stored, use channels test <id>. Passing --secret-stdin with sms or email exits 2. As with channels test, a failed delivery reported on an HTTP 200 exits 1.

Terminal
$ solwyn --project proj_0123456789abcdef01234567 notifications test sms
Field    Value
Success  true
Message  SMS eligibility confirmed (no message sent).

On this page