Skip to main content
Every webhook delivery carries a JSON body with the same envelope structure, regardless of event type. This page explains each field and the two most important ones to get right in your integration: sequence and applicationId.

The envelope

The body is byte-for-byte identical across every delivery and replay of the same event. Anything that varies per delivery attempt — the delivery ID, attempt count, timestamp, signature — lives in the HTTP headers instead.

Events, deliveries, and attempts

Three distinct records stand behind every webhook that reaches you, and each carries its own identifier and its own timestamps. Keeping them straight is the key to reconciling the various timestamps and the sequence logic below. The split follows one rule: anything intrinsic to the eventid, type, sequence, originalCreateDate, data — lives in the body and never changes; anything describing this particular HTTP request — delivery ID, attempt number, attempt type, timestamp, signature — lives in the headers and is regenerated per attempt.
When ordering business state, trust the event, never the attempt. A replay of an old event arrives with a fresh Sphere-Timestamp (so it passes signature tolerance checks), but its sequence and originalCreateDate still reflect when the state change actually occurred. Ordering by Sphere-Timestamp would make a replayed old event look newer than events that superseded it — ordering by sequence keeps replays harmless.

Payloads carry the state change, not the full resource

Webhook payloads deliberately contain the minimum you need to react: the resource ID, and the transition from previousStatus to status. They do not contain the full resource object. Most reactions — routing on the new status, updating your own database row, notifying your operations team — work from the payload alone. When you need the complete resource (full verification criteria, bank account details, transfer amounts), fetch it from the resource’s GET endpoint:
Because the payload is minimal and immutable, a replayed event never carries stale data pretending to be fresh — it describes a transition that happened at originalCreateDate. If you always GET the resource for its current state before acting on side effects, replays are harmless.

The sequence field

sequence is a monotonically increasing integer scoped to a single resource instance — one counter per customer, one per transfer, and so on, keyed by data.id. It is assigned when the event is created and never changes, so it reflects the true order in which state changes occurred even when deliveries arrive out of order. Because delivery order is not guaranteed, use sequence to guard against stale updates:
  1. Store the highest sequence you have processed per resource instance — for example, a lastSphereSequence column on the customer row in your own database.
  2. When an event arrives, compare its sequence to the stored value for that data.id.
  3. If incoming.sequence <= stored.sequence, the event is stale or a duplicate — acknowledge with a 2xx and skip the update.
  4. Otherwise, apply the update and store the new sequence.
You do not need a global counter across your account — just per-entity tracking, colocated with the resource state you already maintain.
Do not assume sequence values you receive are contiguous. If your endpoint subscribes to a subset of a resource’s events, you will observe gaps — use the <= staleness comparison above, never gap detection.

Why both sequence and originalCreateDate?

They answer different questions. originalCreateDate tells you when a state change happened — wall-clock time, useful for display, audit trails, and time-window queries. But wall-clock time is an unreliable ordering key: two rapid transitions on the same resource can land close enough together that their timestamps collide, and a timestamp comparison has no way to break the tie. sequence exists to make ordering unambiguous — a strictly increasing integer per resource instance, so any two events for the same resource always have a definite order, no matter how close together they occurred. Rule of thumb: order and deduplicate by sequence; display and audit by originalCreateDate.

The applicationId field

Every payload includes data.applicationId — the SpherePay application the event belongs to. Webhook endpoints are registered per application, and events are only ever delivered for resources owned by the endpoint’s application. This matters most when you operate multiple SpherePay applications that share one webhook receiver URL. Registering the same URL under two applications is perfectly valid — but your handler then receives events from both, and each application’s endpoint has its own signing secret. Use applicationId to route each event to the right application context in your system (and to select the right secret when verifying signatures).
You can find each application’s ID on the Settings page of the SpherePay integrator dashboard.
Last modified on August 11, 2026