webhooks
Manage a project's webhook targets — list, create, rotate the signing secret, and deactivate
webhooks manages the HTTPS endpoints Solwyn delivers signed project events to. It has four subcommands — list, create, rotate, and delete — and every one requires a user login (JWT). A project key is rejected with exit 3 before any request is made, with a hint that names the fix: unset SOLWYN_API_KEY and run solwyn login, or log out and back in if the key came from the keychain.
Webhook targets are project-scoped. Resolve the project with --project, SOLWYN_PROJECT_ID, or a default_project in your config file; a missing project exits 2 with project_required.
A webhook's signing secret is shown exactly once — when the target is created and again when it is rotated. list returns only an eight-character prefix, and there is no command that reads a secret back. If you lose it, rotate the webhook.
Webhooks need a paid plan (Production and above). On the Free tier, create relays the API's upgrade response and exits 1 with a link to the dashboard's billing page. See Webhooks for the delivery contract, payload shapes, and event catalogue.
webhooks list
List the project's active webhook targets with masked secret prefixes.
$ solwyn --project proj_0123456789abcdef01234567 webhooks list
ID URL Events Secret prefix
wh_a1b2 https://hooks.example.com/solwyn budget_threshold a1b2c3d4...| Contract | |
|---|---|
| Auth | JWT |
| Exit codes | 0 success · 1 generic/API · 2 usage · 3 auth · 5 not found |
| JSON schema | solwyn.webhooks-list.v1 |
Each entry carries id, url, events, is_active, secret_prefix, and created_at. The CLI refuses a list response that contains a signing secret — it exits 1 rather than print one.
webhooks create
Create a target and reveal its signing secret once.
solwyn --project <project_id> webhooks create --url <https-url> [--events <list>]| Option | Type | Default | Purpose |
|---|---|---|---|
--url | HTTPS URL | required | Destination. The API requires a public HTTPS endpoint and rejects private or loopback addresses. |
--events | string | * | Comma-separated event names, or * for every event. Names are passed through unchanged, so future event types work without a CLI upgrade. |
| Contract | |
|---|---|
| Auth | owner/admin JWT (project.write) |
| Exit codes | 0 success · 1 generic/API · 2 usage · 3 auth · 5 not found |
| JSON schema | solwyn.webhooks-create.v1 |
A malformed --url exits 2 before any credential is resolved. The event names Solwyn currently emits are listed in Webhook events.
$ solwyn --project proj_0123456789abcdef01234567 webhooks create \
--url https://hooks.example.com/solwyn --events budget_threshold,budget_exceeded
Field Value
ID wh_a1b2
URL https://hooks.example.com/solwyn
Events budget_threshold,budget_exceeded
Active true
Secret prefix a1b2c3d4...
Created 2026-09-01T14:30:00Z
╭──────────────── One-time webhook signing secret ─────────────────╮
│ a1b2c3d4… │
╰──────────────────────────────────────────────────────────────────╯The panel prints the full secret — 64 hexadecimal characters, truncated here. In JSON output the same value appears as signing_secret, so a script can capture it directly:
{"schema":"solwyn.webhooks-create.v1","id":"wh_a1b2","url":"https://hooks.example.com/solwyn","events":"budget_threshold,budget_exceeded","is_active":true,"secret_prefix":"a1b2c3d4...","created_at":"2026-09-01T14:30:00Z","signing_secret":"a1b2c3d4…"}Store it in a secret manager before the terminal scrolls. The --help epilog carries the delivery contract your receiver must implement: verify X-Solwyn-Signature as sha256=<hex HMAC-SHA256 of the raw body>, use Idempotency-Key to deduplicate retries, and note that no timestamp header or replay window is defined. Verifying signatures has worked examples.
webhooks rotate
Replace a target's signing secret and reveal the new one once. The old secret stops working immediately — there is no grace window. The CLI displays this effect before confirmation or --yes.
solwyn --project <project_id> webhooks rotate <webhook_id> [--yes]| Contract | |
|---|---|
| Auth | owner/admin JWT (project.write) |
| Exit codes | 0 success · 1 generic/API · 2 usage or confirmation · 3 auth · 5 not found |
| JSON schema | solwyn.webhooks-rotate.v1 |
$ solwyn --project proj_0123456789abcdef01234567 webhooks rotate wh_a1b2 --yes
Field Value
ID wh_a1b2
Key version 2
Secret prefix c3d4e5f6...
╭──────────────── One-time webhook signing secret ─────────────────╮
│ c3d4e5f6… │
╰──────────────────────────────────────────────────────────────────╯The response carries key_version, which increments on every rotation. Rotating a target that has already been deactivated fails with exit 1 and the hint to create a new target instead; an unknown id exits 5.
webhooks delete
Deactivate a target. Deliveries stop; the target no longer appears in list. The CLI displays deactivation effects before confirmation or --yes.
$ solwyn --project proj_0123456789abcdef01234567 webhooks delete wh_a1b2 --yes
Field Value
Project proj_0123456789abcdef01234567
Webhook ID wh_a1b2
Deleted true| Contract | |
|---|---|
| Auth | owner/admin JWT (project.write) |
| Exit codes | 0 success · 1 generic/API · 2 usage or confirmation · 3 auth · 5 not found |
| JSON schema | solwyn.webhooks-delete.v1 |
The API returns no body on success; the CLI synthesizes the confirmation from the project and webhook ids.
Rotate/delete refuse without a TTY and without --yes (exit 2 before HTTP). Decline, EOF or Ctrl-C submits no write. Effects remain on stderr under --json; keep streams separate. After an uncertain rotation or deletion, inspect the target before deliberately retrying. These writes stay CLI-only.
Related
- Webhooks — payload shape, retries, and the dashboard's webhook settings
- Webhook events — every event type and which are emitted today
- Verifying signatures — HMAC verification in your receiver
notifications— human-facing channels instead of machine delivery