Register a webhook
Webhooks
Requires bearer token.
Returns the signing secret ONCE in `secret`. Store it — used to verify `X-Tidvis-Signature` (HMAC-SHA256 over the raw body).
### Exempel-callback från Tidvis
```http
POST /your-webhook HTTP/1.1
Content-Type: application/json
X-Tidvis-Event: agreement.signed
X-Tidvis-Delivery: 9f1c3a7e-2b4d-4e6a-8c1f-1234567890ab
X-Tidvis-Signature: sha256=8a2c…d4f9
{
"event": "agreement.signed",
"event_type": "agreement.signed",
"delivery_id": "9f1c3a7e-2b4d-4e6a-8c1f-1234567890ab",
"created_at": "2026-06-20T12:00:00Z",
"agreement_id": "a1b2c3d4-1111-4aaa-9bbb-000000000001",
"status": "signed",
"participant": {
"id": "b2c3d4e5-2222-4bbb-9ccc-000000000010",
"email": "anna@acme.se"
},
"data": {
"agreement_id": "a1b2c3d4-1111-4aaa-9bbb-000000000001",
"status": "signed",
"participant": {
"id": "b2c3d4e5-2222-4bbb-9ccc-000000000010",
"email": "anna@acme.se"
}
}
}
```
Verifiera signaturen i Node:
```ts
import { createHmac, timingSafeEqual } from 'crypto';
const header = req.headers['x-tidvis-signature']; // 'sha256=…'
const signature = header.replace(/^sha256=/, '');
const expected = createHmac('sha256', WEBHOOK_SECRET).update(rawBody).digest('hex');
if (!timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) throw new Error('bad signature');
```
Request body
url: string (uri) requiredevents: array required
Example
{
"url": "https://acme.se/webhooks/tidvis",
"events": [
"agreement.signed",
"agreement.completed",
"agreement.cancelled"
]
}
Responses
- 201 — Created
- 400 — Invalid request
- 401 — Missing or invalid bearer token
- 403 — Forbidden — missing scope, wrong plan, or sub-account license required
- 404 — Not found
- 409 — Conflict
- 429 — Rate limit exceeded
- 500 — Server error