Event Envelope
Every Sakneen outbound webhook sends one immutable JSON event envelope.
{
"eventId": "019c0ea7-6316-7ff2-a880-cf6a7a659a9e",
"eventType": "client.created",
"eventVersion": 1,
"occurredAt": "2026-07-30T10:30:00.000Z",
"source": "sakneen",
"organizationId": "64f1a0d6d5d0a14a5c0e8a10",
"correlationId": "019c0ea7-6316-7ab4-8be3-c2f5bca42287",
"resource": {
"type": "client",
"id": "64f1a0d6d5d0a14a5c0e8a20",
"version": 1
},
"data": {
"clientId": "64f1a0d6d5d0a14a5c0e8a20",
"clientCode": 1234,
"name": "Ahmed Ali",
"phoneNumber": "+201000000000"
}
}
Envelope fields
| Field | Type | Description |
|---|---|---|
eventId | string | Stable identifier for this logical event. Use it as your idempotency key. |
eventType | string | Event name in resource.action form. |
eventVersion | positive integer | Version of this event's external contract. |
occurredAt | ISO 8601 string | UTC time when Sakneen recorded the event. |
source | string | Always sakneen. |
organizationId | string | Sakneen organization that owns the event. |
correlationId | string | Groups events produced by the same business mutation. |
resource.type | string | Resource family, such as client or wallet_cheque. |
resource.id | string | Stable identifier of the changed resource. |
resource.version | positive integer | Monotonically increasing resource state version. |
data | object | Event-specific current state described by the event contract. |
Event version and resource version
These fields serve different purposes:
eventVersionchanges only when Sakneen publishes a new version of an event contract.resource.versionincreases as a specific resource changes.
Route on both eventType and eventVersion:
const handler = handlers[`${event.eventType}.v${event.eventVersion}`];
if (!handler) {
throw new Error("Unsupported Sakneen event contract");
}
await handler(event);
Do not silently process a version your integration does not understand.
Correlated events
One Wallet mutation can produce multiple events. For example, applying a new
schedule can update the Wallet and create, update, or supersede installments.
Those events have unique eventId values but share a correlationId and
occurredAt.
Correlation is provided for tracing; each event must still be processed and deduplicated independently.
Optional fields
Optional fields are omitted when unavailable. Do not require optional fields to exist and do not treat omission as an empty string or zero.
Sakneen may add new optional fields to an existing event version. Receivers should ignore unknown fields while continuing to validate the fields they use.