webhooks:manage. Its secret is returned once; store it securely. Separate subscriptions should serve different projects/environments. A destination must be a public HTTPS DNS hostname on port 443. Private/local addresses and redirects are rejected; TLS verification remains enabled.
message.status and message.received, supply explicit granted senderIds. Shared-only events need no customer-owned number and accept an empty array.
Events contain metadata, not message bodies, OTPs or provider keys.
message.received reports metadata only; developer message-content retrieval is not provided by the current service-key contract.
Signature contract
Headers retain their existingX-Sweefta-* names:
timestamp + '.' + exact-raw-JSON-body. Do not parse and reserialize before verification. Use constant-time comparison and reject stale timestamps (recommended tolerance: five minutes). Then check the signed body’s id matches the event-ID header and deduplicate that ID durably.
A reusable Node.js verifier is included in examples/verify-webhook.mjs in this documentation directory, with tests. In Express, register express.raw({ type: 'application/json', limit: '256kb' }) for this route before any global JSON parser. Verify bytes, persist a deduplicated event in a transaction, enqueue your work, then return 2xx quickly.
Delivery and recovery
Delivery is at least once, can be delayed and can arrive out of order. Event IDs remain stable across retries; timestamp/signature are recalculated for each attempt. Do not assume provider events or statuses arrive in order. Check the authoritative GET endpoint when needed. 2xx acknowledges delivery. HTTP 400/401/403/404/410 is terminal; other failures retry with bounded exponential backoff, at most eight attempts. A subscription disabled before delivery cancels pending work. Use/webhooks/{id}/deliveries to inspect metadata. There is no public manual-redelivery endpoint in this version.
Rotating a secret immediately invalidates the old secret; coordinate the receiver change. Webhook egress defaults to disabled until infrastructure validation. The default transport fails closed under a generic forward proxy; operators must configure reviewed SSRF-safe egress before enabling it.