Channels
Every channel has a type and a config object shaped by that type. Each type’s config is
validated with a .strict() schema: a key that is not listed below is rejected with 400, never
silently dropped or stored.
Config: { to }
to— a valid email address. This is the recipient; the channel is the target, so there is no separate “who receives this” setting.
Config: { webhookUrl }
webhookUrl— must be anhttps://hooks.slack.com/...incoming-webhook URL. Any other host or scheme is rejected.
webhook
Section titled “webhook”Config: { url, secret }
url— the endpoint WireWatch delivers to. Any validhttp(s)URL.secret— a non-empty string used to sign every delivery. See Webhooks for the signature scheme and a sample that verifies it.
pagerduty
Section titled “pagerduty”Config: { routingKey }
routingKey— a PagerDuty Events API v2 integration key.
opsgenie
Section titled “opsgenie”Config: { apiKey, region }
apiKey— an Opsgenie Alert API integration key.region—usoreu. Opsgenie is two separate instances per region, and this decides which one WireWatch talks to.
Seal and redact
Section titled “Seal and redact”Every secret field above is encrypted at rest and decrypted only just-in-time to send — a read never returns it. What a read gives back instead differs by type, and two of them give back nothing:
| Type | Secret field | Returned on read |
|---|---|---|
email |
none | the whole config |
slack |
webhookUrl |
{} |
webhook |
secret |
{ url } |
pagerduty |
routingKey |
{} |
opsgenie |
apiKey |
{ region } |
A Slack webhook URL and a PagerDuty routing key never reappear once saved: reading the channel back
gives an empty config, not a masked or partial value. That is not a bug and it does not mean the
save failed — if you need to confirm what you entered, the dashboard cannot show you, and the field
has to be re-entered to change it. webhook.secret and opsgenie.apiKey behave the same way; only
their non-secret sibling fields (url, region) come back.