Webhooks overview
Sursa records an event for every important change: a card is published, verified or archived, an announcement is read, a question goes unanswered. You can receive events in two ways, and use both together:
| Webhooks | Event feed | |
|---|---|---|
| How | Sursa sends each event to your HTTPS address as it happens. | You read GET /v1/webhook-events when you want. |
| Latency | Seconds. | As often as you poll. |
| Needs | A public HTTPS receiver. | Only an API key with the admin role and the webhooks:manage scope. |
| Good for | Reacting to changes: notify, sync, start a workflow. | Batch jobs, catching up after downtime, reconciliation. |
Both carry the same events with the same IDs. Every event is kept in the feed for 30 days, whether or not any webhook was subscribed to it.
The event
{
"id": "evt_0123456789abcdef0123456789abcdef",
"type": "card.updated",
"created_at": "2026-10-24T10:00:03Z",
"org_id": 1,
"api_version": "1.60.0",
"sequence": 1042,
"object": {"type": "card", "id": "3f2c9a7e-5b1d-4c8e-9f0a-1b2c3d4e5f60"},
"payload": "full",
"data": {
"card": {"id": "3f2c9a7e-5b1d-4c8e-9f0a-1b2c3d4e5f60", "title": "Refund policy", "collection": "support", "version": 4},
"actor_id": 7,
"previous_attributes": {"title": "Refunds"}
},
"test": false
}
| Field | Meaning |
|---|---|
id | The ID of the event, evt_ and 32 hexadecimal characters. The same in every delivery attempt and in the feed. |
type | What happened, as <object>.<past-tense verb>: card.updated, access_request.resolved. |
created_at | When the change happened, in UTC. |
api_version | The version of the API whose schema data follows. |
object | The type and ID of the object the event is about. |
data | The details. Its shape depends on the type and is described in the event catalog. |
data.previous_attributes | In *.updated events: the earlier values of the fields that changed. |
sequence, payload, test | Only in webhook deliveries: the position in the order of the endpoint, the payload mode, and whether this is a test event. |
data holds only what any reader of the object could see through the API. It never contains access lists, the
permissions of other people or hidden fields. Reasons in events are short neutral codes such as no_hits,
restricted or index_failed.
Event types
Events cover these areas:
| Area | Examples |
|---|---|
| Cards | card.created, card.updated, card.published, card.archived, card.deleted, card.indexed, card.index_failed |
| Verification | card.verified, card.unverified, verification.expired, verification.requested |
| Structure | collection.created, folder.updated |
| Collaboration | comment.created, draft.publish_requested, announcement.sent, announcement.read |
| Answers | question.unanswered, question.feedback_created, access_request.created |
| People and access | user.created, user.deactivated, group.member_added, api_key.expiring |
| Sources and import | source.sync_completed, import.sync_completed, import.document_failed |
| Jobs | job.completed, job.failed, export.ready |
| Webhooks | webhook.endpoint_disabled, webhook.ping |
The complete list with the schema and an example of each event is in the event catalog of the
API reference. GET /v1/webhooks/catalog returns the
types available on your installation.
New event types are added over time, and existing events gain fields. Event types are never renamed or removed. Your receiver must skip types and fields it does not know.
Who receives what
An endpoint receives an event only if the object of the event is visible to the endpoint, in the same way as to an
API key: by its role, its data profile and its collections. An endpoint limited to the support collection never
receives events about cards in finance. Events about people, keys, sources, imports, jobs, exports, billing,
applications and webhooks themselves go only to endpoints with the admin role.
Within that, each endpoint chooses its events:
- by type, with masks:
card.*for every card event,*for every event; - by collection and by tag, for card events.
The payload mode of an endpoint is full (the event with data, the default) or thin (the event without data:
your receiver reads the object through the API with its own key, and always sees its current state).
Delivery in short
- An HTTPS
POSTwith the event as JSON, signed with the endpoint's secret in two formats: Standard Webhooks (webhook-signature) and the earlierX-KB-Signature. - Any
2xxanswer within 10 seconds is a success. - A failure is retried for almost three days with growing pauses.
Retry-Afterin a429or503answer is respected;410disables the endpoint; 10 failures in a row pause it until it is resumed. - Deliveries to one endpoint are sent strictly in order. A slow endpoint does not delay other endpoints.
- The same event can arrive more than once: drop duplicates by
webhook-id.
Receive webhooks walks through a complete receiver, with signature checks in Node.js, Python and Go.
Manage endpoints
| Task | Endpoint |
|---|---|
| Create an endpoint and get its secret | POST /v1/webhooks |
| Change the address, events or state | PATCH /v1/webhooks/{webhook_id} |
| Send a test event | POST /v1/webhooks/{webhook_id}/test |
| Rotate the secret | POST /v1/webhooks/{webhook_id}/rotate-secret |
| Resume a paused endpoint | POST /v1/webhooks/{webhook_id}/resume |
| See deliveries and answers | GET /v1/webhooks/{webhook_id}/deliveries |
| Send a delivery again | POST /v1/webhooks/{webhook_id}/deliveries/{delivery_id}/redeliver |
Managing endpoints needs a key with the admin role and the webhooks:manage scope, or an administrator in the admin
interface. An organization can have up to 20 endpoints. Webhooks are part of the organization's plan; without them,
these endpoints answer 403 with the code webhooks.feature_disabled.