v30.0
Notifuse/notifusev30.0Apr 24, 2026by pierre-b
AI Summary
This major release implements Standard Webhooks specification compliance, migrates timezone data from deprecated Kiev to Kyiv, fixes silent task dispatch failures caused by auth proxies, improves scheduler performance, and adds a new AWS region.
Key Highlights
- Breaking: Webhook signatures conform to Standard Webhooks spec with whsec_ prefix
- Data migration: Europe/Kiev rewritten to Europe/Kyiv across workspaces, contacts, segments, broadcasts
- Feature: Task dispatch no longer swallowed by auth proxies (now refuses redirects)
- Feature: Scheduler tick no longer waits on in-flight HTTP dispatches
- Feature: Added AWS region eu-central-2 (Zurich)
Breaking Changes
- Webhook signatures now conform to Standard Webhooks specification
- Existing webhook secrets rotated to whsec_ format - operators must copy new secret and update verification code
- If ingress performs HTTP→HTTPS redirect, operators must set $API_ENDPOINT to final HTTPS URL
New Features
- Task dispatch no longer swallowed by auth proxies
- Scheduler tick no longer waits on in-flight dispatches
- AWS region eu-central-2 (Zurich) added to S3 provider and integrations
Full Release Notes
## Breaking Changes - **Webhooks**: Signatures now conform to the [Standard Webhooks](https://github.com/standard-webhooks/standard-webhooks/blob/main/spec/standard-webhooks.md) specification and match the published verification code in the docs (#318) - Stored secrets are now prefixed with `whsec_` and the 32 random bytes after the prefix are base64-decoded before use as the HMAC key (previously the 44-char base64 string was used directly as raw bytes, making the published Python/JS/Go/PHP verification snippets always fail) - V30 migration rotates every existing webhook secret to the new format. Subscriptions, URLs, event filters, enabled state, and delivery history are preserved; only the secret value changes - **Consumer action required**: copy the new `whsec_…` secret from the console into your environment and update your verification code to the spec-compliant form shown in the docs. Deliveries that fire during the gap will retry automatically once the consumer's secret is updated ## Data migration - **Timezone**: `Europe/Kiev` is rewritten to the IANA-canonical `Europe/Kyiv` across `workspaces.settings`, `contacts.timezone`, `segments.timezone`, and `broadcasts.schedule.timezone`. Stored `Europe/Kiev` continued to resolve at runtime via Go's tzdata alias, but the console dropdown (which no longer lists the obsolete name) showed an empty selection for affected rows. The `contacts` triggers are briefly disabled around the rename so it does not emit `contact.updated` webhook events or fill `contact_timeline` with rename entries. ## Other changes - **Task dispatch no longer swallowed by auth proxies (#320, #317)**: The scheduler's internal `POST /api/tasks.execute` client now refuses to follow redirects (`CheckRedirect = http.ErrUseLastResponse`). Previously, an auth-walling reverse proxy (Cloudflare Access, Authelia, oauth2-proxy, Traefik Forward Auth, etc.) sitting in front of the API could respond with a 302 to its login page; Go's default `http.Client` followed the redirect as a GET, the login page returned 200 OK HTML, and the dispatcher logged "dispatched successfully" while the task never ran. The 302 is now surfaced in the non-200 branch (with the `Location` header logged) so the misconfiguration is loud instead of silent. **Operator note**: if your ingress performs an HTTP→HTTPS redirect on the API path, set `$API_ENDPOINT` to the final HTTPS URL — the dispatch client will no longer silently upgrade it. - **Task scheduler**: Scheduler tick no longer waits on in-flight HTTP dispatches, so one slow recurring task can't delay dispatch of others on the same tick. Stale tasks left in `running` with an expired `timeout_after` are now reclaimed by `MarkAsRunningTx` on a subsequent tick instead of looping on 409 indefinitely (#317). - **Task dispatch observability**: The scheduler-side "Task execution request dispatched successfully" log now includes the HTTP `status_code`, and `tasks.execute` logs an entry line on the handler side. Diffing the two streams makes any remaining silent-interception failure mode visible. - **Feature**: Added AWS region `eu-central-2` (Europe, Zurich) to the S3 provider and integrations region selectors (#316).