Breaking Changes
- Webhooks: Signatures now conform to the Standard Webhooks 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
- Stored secrets are now prefixed with
Data migration
- Timezone:
Europe/Kievis rewritten to the IANA-canonicalEurope/Kyivacrossworkspaces.settings,contacts.timezone,segments.timezone, andbroadcasts.schedule.timezone. StoredEurope/Kievcontinued 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. Thecontactstriggers are briefly disabled around the rename so it does not emitcontact.updatedwebhook events or fillcontact_timelinewith rename entries.
Other changes
- Task dispatch no longer swallowed by auth proxies (#320, #317): The scheduler's internal
POST /api/tasks.executeclient 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 defaulthttp.Clientfollowed 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 theLocationheader 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_ENDPOINTto 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
runningwith an expiredtimeout_afterare now reclaimed byMarkAsRunningTxon 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, andtasks.executelogs 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).