> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sendlyy.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Signed webhooks

> Authenticate exact payload bytes and handle at-least-once delivery.

Create a subscription using `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.

```json theme={null}
{
  "projectId": "<project-uuid>",
  "environmentId": "<environment-uuid>",
  "senderIds": [],
  "name": "Shared service events",
  "url": "https://your-app.example/sendlyy-events",
  "events": ["verify.message-status", "verification.status", "notify.message-status"]
}
```

For dedicated `message.status` and `message.received`, supply explicit granted `senderIds`. Shared-only events need no customer-owned number and accept an empty array.

| Event | Data |
| - | - |
| `message.status` | Dedicated `messageId`, `status`, `occurredAt` |
| `message.received` | Dedicated inbound `messageId`, `conversationId`, `occurredAt`; no message body |
| `notify.message-status` | Shared `messageId`, `status`, `occurredAt` |
| `verify.message-status` | Shared authentication `messageId`, `status`, `occurredAt`; no OTP or recipient |
| `verification.status` | `verificationId`, `status` for completed/locked checks |

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 existing `X-Sweefta-*` names:

```http theme={null}
X-Sweefta-Event-Id: <stable-event-id>
X-Sweefta-Timestamp: <unix-seconds>
X-Sweefta-Signature: sha256=<lowercase-hex-hmac>
```

Compute HMAC-SHA256 with the signing-secret string as the UTF-8 key, over `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.

```javascript theme={null}
import { verifySendlyyWebhook } from './verify-webhook.mjs';

app.post('/sendlyy-events', express.raw({ type: 'application/json', limit: '256kb' }), async (req, res) => {
  const event = verifySendlyyWebhook(req.body, req.headers, process.env.SENDLYY_WEBHOOK_SECRET);
  if (!event) return res.sendStatus(401);
  // Persist event.id once and enqueue work atomically in your own database.
  await acceptEventOnce(event);
  return res.sendStatus(200);
});
```

### 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.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.