Skip to main content

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

FieldTypeDescription
eventIdstringStable identifier for this logical event. Use it as your idempotency key.
eventTypestringEvent name in resource.action form.
eventVersionpositive integerVersion of this event's external contract.
occurredAtISO 8601 stringUTC time when Sakneen recorded the event.
sourcestringAlways sakneen.
organizationIdstringSakneen organization that owns the event.
correlationIdstringGroups events produced by the same business mutation.
resource.typestringResource family, such as client or wallet_cheque.
resource.idstringStable identifier of the changed resource.
resource.versionpositive integerMonotonically increasing resource state version.
dataobjectEvent-specific current state described by the event contract.

Event version and resource version

These fields serve different purposes:

  • eventVersion changes only when Sakneen publishes a new version of an event contract.
  • resource.version increases 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.