Webhooks
Register an HTTPS URL on a project. After a successful Data API write, Tefily POSTs a JSON payload to every matching webhook. Failed deliveries are retried with exponential backoff (up to five attempts) and never fail the original API call.
Configure webhooks in the console (Database → Automation → Webhooks) or with the admin API / MCP tools.
Events
Section titled “Events”Empty events means all of these. Unknown names are rejected.
| Event | When |
|---|---|
record.created |
Single document create |
record.created_many |
Bulk POST array (one delivery, not one per row) |
record.updated |
Single document update |
record.deleted |
Single document delete |
record.updated_many |
Bulk PATCH (one delivery, not one per row) |
record.deleted_many |
Bulk collection DELETE |
file.uploaded |
Upload session completed |
file.deleted |
File deleted from a record |
auth.registered |
End-user register |
auth.logged_in |
End-user login |
auth.password_reset.requested |
Reset email sent for an existing user |
auth.password_reset.completed |
Password actually changed |
webhook.ping |
Manual ping from the console or API |
Reads (list / get / download) and schema-admin changes do not fire webhooks.
Internal collections _usage_events, _files, and _auth_tokens never emit record.* events. Auth methods emit auth.* instead of duplicating record.* for _users. Direct CRUD on _users still emits record.*.
Collection filter
Section titled “Collection filter”collections is an allow-list of table names. Empty means every collection. Auth events and webhook.ping ignore this filter.
Payload
Section titled “Payload”{ "id": "<deliveryId>", "event": "record.updated", "projectId": "...", "collection": "posts", "timestamp": "2026-09-15T18:00:00.000Z", "actor": { "type": "project", "userId": "..." }, "data": { }}actor.type is project, platform, service, or anonymous.
data by event:
- create / update:
record(after). Update also includesprevious. - delete:
record(the deleted document). - bulk create:
countandrecords. - bulk update / delete:
filter,count, andpatchon update-many. - file:
fileId,fieldName,filename,contentType,size,recordId, plusrecordwhen available. - auth:
user(password fields stripped). Login does not include the JWT.
If the UTF-8 JSON of data is larger than 100 × 1024 bytes, the whole data object is replaced by { "_truncated": true }, plus _id when data.record._id or data._id exists. Bulk events often have no single _id, so the replacement may be only { "_truncated": true }.
Headers
Section titled “Headers”| Header | Value |
|---|---|
Content-Type |
application/json |
X-Kallax-Event |
Event name |
X-Kallax-Delivery |
Delivery id |
X-Kallax-Signature |
sha256=<hex> when you set a signing secret |
X-Kallax-Signature is omitted when the secret is empty. The algorithm is HMAC-SHA256 over the raw body, hex-encoded, with the header value sha256=<hex>. rawBody must be the exact bytes received, not JSON.stringify(JSON.parse(body)).
import { createHmac, timingSafeEqual } from 'node:crypto';
function verifyKallaxSignature(secret, rawBody, header) { if (!header?.startsWith('sha256=')) return false; const expected = createHmac('sha256', secret).update(rawBody).digest('hex'); const got = header.slice('sha256='.length); const a = Buffer.from(expected); const b = Buffer.from(got); if (a.length !== b.length) return false; return timingSafeEqual(a, b);}Delivery
Section titled “Delivery”Success is HTTP 200–299. Any other status, or a thrown error, is a failure. A webhook failure never fails the original API call.
maxAttempts defaults to 5. Attempts 1–4 stay pending. Attempt 5 marks the delivery failed and clears nextRetryAt.
Backoff after a failure is min(3600, 2^attempt) seconds, with the attempt counted after it is incremented. The first failure waits 2 seconds, then 4, 8, and 16. The wait is capped at 3600 seconds.
The truncation rule above replaces the whole data payload. Stored response bodies in delivery history are cut to 2000 characters. That cut does not change the outbound payload.
A project can have at most 20 webhooks, on all plans. Create beyond the cap fails with A project may have at most 20 webhooks. See Usage and limits.
Admin API
Section titled “Admin API”Requires a platform JWT or PAT with schema read (list) or schema update (create / update / delete / ping).
| Method | Path |
|---|---|
| GET / POST | /api/projects/:projectId/webhooks |
| GET / PATCH / DELETE | /api/projects/:projectId/webhooks/:id |
| GET | /api/projects/:projectId/webhooks/:id/deliveries |
| POST | /api/projects/:projectId/webhooks/:id/ping |
The signing secret is returned once on create. Later list/get responses include hasSecret and secretLastFour only.
URLs are validated against SSRF (no loopback, private, or metadata IPs). Production requires HTTPS.
To send an email instead of an HTTP call, see Email triggers.
See Endpoints, Files, and End-user auth.