SettleMint
API referenceWebhooks

Consuming webhook events

How a receiver reads DALP webhook deliveries: outcomes, identifiers, ordering, retries, Resend and Replay, receipts, payload shape and retractions.

A DALP webhook delivery is at least once. The platform can send one event more than once, and a Replay sends an earlier outcome again under a new event id. This page states how a receiver reads an event's outcome, tells deliveries apart, relies on ordering, handles retries, uses receipts, and applies a retraction. Endpoint registration and signature verification are in the setup guide.

Outcome model

An API response that accepts a write request does not mean the transaction is final on chain. Many write routes queue the transaction, so the response confirms only that the platform accepted the instruction. The lifecycle state of an event tells you how far the fact has progressed. The lifecycle page defines each state. The idempotency and async settlement guide covers the write response.

A chain reorganization (reorg) replaces recent blocks with a competing set of blocks. The platform sends a final event for a chain log only after the block passes the chain's configured reorg depth.

SignalWhat it tells youWhat it does not tell you
A write response that accepted the requestThe platform accepted the instruction.That the transaction reached the chain or is final.
A provisional eventThe platform reports a fact that can still change. A reorg can still remove the block of a chain log.That the fact is complete.
A final eventThe platform reports the fact as complete. The block of a chain log passed the reorg depth.That no retraction can follow. A trade bust retracts a settled trade that the platform already reported as final.
A retracted eventAn earlier event no longer stands.That your endpoint received the earlier event. Retractions covers this case.

Identifiers and deduplication

Verify the exact raw body and its signature before trusting an event or using its identifiers. The setup guide documents verification. A lost response can cause a duplicate delivery, so a successful verification does not mean the event is new.

IdentifierWhere it appearsSame across attemptsUse it to
webhook-id header and evt_id body fieldEvery delivery. Both hold the same value, the id of the event.Yes. A retry and a Resend keep it. A Replay mints a new one.Deduplicate deliveries of one event.
webhook-delivery-id headerEvery delivery.No. Each attempt gets a new value.Identify one attempt, and name it in a counter-signed receipt.
source_id body fieldEvery event except a test event.Yes. A Replay keeps it.Recognize the same outcome of one event name when it returns under a new event id.
request.idempotency_key body fieldRequest correlation metadata when the transaction's caller attribution is unambiguous.Yes, when present.Correlate with a request when the stored event supplies a key. Never deduplicate deliveries on it.

The platform adds the headers webhook-delivery-id and webhook-endpoint-id to the three headers of the open Standard Webhooks specification: webhook-id, webhook-timestamp and webhook-signature. The webhook-endpoint-id header names your endpoint and stays the same for it. The setup guide lists every header.

Deduplicate deliveries on webhook-id. A retry, a Resend, and a send that the platform repeats after it stops before it records an attempt all keep the webhook-id of the first attempt. Answer a webhook-id you already handled with a 2xx response.

A Replay is a new event with a new evt_id, so webhook-id does not match it. Its source_id and its payload identifiers match the original. When you recover through a Replay, deduplicate outcomes on source_id, or on payload identifiers such as the transactionHash and logIndex of a token transfer.

For each endpoint, the platform stores at most one event with a given source_id, excluding Replay and test events. A provisional event and the final event for the same fact have different source_id and evt_id values, because the source_id includes the event name and version. Match them through the payload identifiers.

The optional request.idempotency_key is a correlation field, not a delivery deduplication key. A chain-sourced event includes the caller's key when the transaction can be attributed to one organization and one nonempty caller key, and that organization owns the endpoint. Conflicting attribution, a missing key or an endpoint in another organization leaves the field absent. A Replay or retraction preserves a key already present in the stored event. When the field is absent, correlate through the payload identifiers rather than inventing a key.

The helper verifyWebhook in @settlemint/dalp-sdk/verify-webhook accepts an optional replayStore. With a store, it returns REPLAYED_EVENT for a webhook-id it has seen before. The store records the id when verification succeeds, so a retry after your handler failed also returns REPLAYED_EVENT.

Ordering

The platform assigns each event a position in its endpoint's delivery sequence. A later eligible event waits while an earlier event remains pending, including during backoff. A successful attempt, a terminal failure, or exhaustion of the retry window releases the later events. A missing counter-signed receipt can reopen an event for retry.

A linked correction waits for its cause. The platform sends it after the event it replaces is delivered, or after that event can no longer be delivered. This permits a correction to identify an event your system never received.

The platform gives no guarantee of:

  • Order between endpoints. Each endpoint has its own sequence.
  • Delivery of a chain final event before the events recorded after it. An event that waits for chain finality does not hold back later events, so its delivery can follow theirs.

A Replay takes the next place in the endpoint's sequence, after every event the platform already recorded.

Retries

Your response decides what the platform does next.

Your endpoint answersThe platform
A 2xx statusMarks the attempt delivered and does not retry.
408 or 429Retries. Use these statuses to ask for a later attempt.
Any other 4xx statusTreats the response as terminal, does not retry, and ends delivery of the event.
A 5xx statusRetries.
A redirect or any other status. The platform follows no redirects.Retries.
No answer within 20 seconds, a refused or reset connection, a Domain Name System (DNS) lookup failure, or a Transport Layer Security (TLS) handshake failureRetries.

The receipt rules also apply after a 2xx response when receipts are enabled.

The platform waits before each retry. The base wait doubles with each failed attempt: 30 seconds after attempt 1, 60 seconds after attempt 2, 2 minutes after attempt 3. The platform multiplies the base wait by a random factor from 0.7 to 1.3. The wait never exceeds three days or the time left in the retry window. An attempt times out after 20 seconds.

The retry window is three days. It starts when the platform records the event, not at the first attempt.

At exhaustion, the platform abandons automatic delivery, writes a warning log, and records a failed trace span. Later eligible events can proceed. The recorded attempts remain available in the endpoint's delivery history, under Event deliveries in the Console. A terminal failure also stops automatic delivery. Resend and Replay provide recovery actions after the receiver is repaired.

A run of failed attempts can also disable the endpoint. The platform queues no new events for a disabled endpoint. The Webhook Delivery concept describes the circuit breaker that does this.

Resend and replay

Resend and Replay are authenticated Platform API requests. The authentication guide describes the accepted credentials. The v2 API reference defines their request, response and error bodies; the event-delivery signing secret is not a replacement for API authentication.

Both actions send an event again. They differ in what they keep.

PropertyResendReplay
RequestPOST /api/v2/webhooks/{webhookId}/deliveries/{deliveryId}/retriesPOST /api/v2/webhooks/{webhookId}/replays
What it selectsOne attempt, which must be the latest attempt of its event.A block range on one chain, or one event by evt_id.
Event idThe same evt_id and webhook-id.A new evt_id for each event.
source_idThe same.The same.
Attempt historyAdds one attempt to the event. Earlier attempts keep their recorded outcome.Creates a new event with its own attempt history.
is_replayUnchanged.true on every replayed event. A live event has no is_replay field.

A Resend queues one more attempt. It runs even when an earlier attempt succeeded, so your endpoint can receive an event it already acknowledged. The call returns deliveryId and scheduled. The value scheduled is false, and the platform changes nothing, when any of these holds:

  • The attempt is not the latest attempt of its event.
  • The event was replaced or cancelled after a reorg, so the platform no longer delivers it.
  • A newer attempt is already claimed, or an earlier Resend has not yet produced an attempt.

A retry waiting in backoff does not block a Resend.

A Resend does not restart the retry window. The platform measures the window from when it recorded the event. A failed Resend attempt on an event older than three days gets no retry.

A Replay takes either a block range or one event. The block range holds fromBlock, an optional toBlock, and chainId. The single event holds evtId and an optional chainId. The platform resends the stored payload with its lifecycle state, so a replayed provisional event is still provisional.

Do not use Replay arrival order or a global ranking of lifecycle_state values to replace a business record. Follow the event family's correlation and transition rules in the catalogue. A replayed provisional transfer does not undo its final confirmation. Retain explicit supersedes relationships so that an older observation cannot restore a fact already withdrawn. If the Replay's relationship to your record is unclear, reconcile the resource before overwriting that record.

A Replay is subject to these rules:

  • The platform rejects it while the endpoint is disabled or its circuit breaker is open.
  • A range wider than 10,000 blocks needs confirmLargeRange set to true.
  • An organization can start at most 10 Replays per minute.
  • The platform does not replay an event that a reorg replaced or cancelled.

If a Replay response is lost, repeating the request can queue the same outcomes again with new event ids. Deduplicate those outcomes by source_id; do not assume the second request repeats the first response. The Resend conditions above still apply to its original deliveryId, so neither operation earns a blanket safe-retry rule for API failures.

Delivery history retention

The platform periodically deletes settled delivery history more than 30 days old. It measures the age from when delivery ended, not from when the event was recorded. The event's delivery attempts and counter-signed receipts are removed with it.

This cleanup includes final and retracted events. It also includes provisional events recorded inside the platform, such as trading-venue.order-status.provisional and trading-venue.price-alert.triggered: those events do not become final. Pending deliveries, test events and provisional observations from chain logs are outside this cleanup.

The 30-day retention period does not extend the three-day retry window. Keep your receiver's business records and acknowledgements for as long as your audit policy requires; the platform's delivery history is not a permanent archive.

Counter-signed receipts

The platform signs each delivery over webhook-id, webhook-timestamp and the exact body. The helper verifyWebhook rejects a timestamp more than five minutes from your clock by default. Its timestampToleranceSeconds option changes that tolerance. Before an attempt, the platform re-signs a stored envelope whose signature is at least four minutes old.

A 2xx response records that your endpoint answered. A counter-signed receipt records your system's acknowledgement of the exact body, signed with the endpoint's webhook signing secret. The endpoint setting counterSignedReceipts enables this acknowledgement. After a successful attempt, the platform schedules a deadline for the receipt.

Receipt submission requires Platform API authentication as well as the consumer signature. The v2 API reference defines the request and response contract for POST /api/v2/webhook-receipts.

A successful submission returns the receipt resource. A repeated valid submission within the receipt window updates the receipt for that delivery, including its verification timestamp; the response need not be identical. A delivery already marked as receipt-timed-out is rejected rather than reopened.

You post the receipt to POST /api/v2/webhook-receipts with deliveryId, evtId, endpointId, consumerSignature and innerEventHash. The platform accepts a valid signature made with the endpoint's active secret or its previous secret during rotation. The signing string has five lines, joined with \n, with no trailing newline.

LineValue
1The scheme name dalp.whr.v1.
2The webhook-delivery-id of the delivery you answer.
3The webhook-endpoint-id of the delivery.
4The webhook-id of the delivery.
5The body hash: sha256: followed by the lowercase hexadecimal SHA-256 digest of the exact body you received.

SHA-256 means Secure Hash Algorithm 256. The receipt signature is a keyed-hash message authentication code (HMAC) with SHA-256 over the signing string, written in hexadecimal. The key is the endpoint signing secret without its dalp_whsk_ prefix, decoded from base64. In Node.js, signWebhookReceipt and buildReceiptSigningString in @settlemint/dalp-sdk/sign-webhook-receipt produce the signature and the string.

The receipt window is 30 seconds by default. The platform never allows less than 1 second or more than 60 seconds. The window starts after your 2xx response.

ReceiptThe platform
Verifies and matches the bodyRecords the receipt.
Has a signature that does not verifyRejects it with status 401 and the failure class RECEIPT_INVALID_SIG.
Arrives after the window closedRejects it with status 401 and the failure class RECEIPT_WINDOW_CLOSED.
Has a hash that differs from the sent bodyRejects it with status 401 and RECEIPT_HASH_MISMATCH. It marks the attempt RECEIPT_HASH_MISMATCH, schedules no retry, and settles the event.
Does not arrive within the windowMarks the attempt RECEIPT_TIMEOUT and retries on the normal backoff. The retry repeats the same webhook-id.

An invalid signature rejects the receipt submission without settling the event or scheduling a new delivery. Correct the signature and submit it again while the receipt window is open. If no valid receipt arrives by the deadline, the receipt-timeout path retries delivery within the event's retry window.

A late submission does not reopen its receipt window or schedule another attempt. Submit a receipt for the next delivery if the platform retries it. A rejected receipt submission and a retry of the webhook delivery are separate operations.

Payload shape

Use the machine-readable event definitions or the SDK's Webhook types for each event's envelope and payload schema. Those schemas are separate from the consent field-path list described below.

Each endpoint has a payload shape. The shape controls whether the personal data fields of an event reach your endpoint. Each event defines its own personal data fields, such as the payer address of a trade fee.

ShapePersonal data fieldsHow an endpoint gets it
thinThe platform removes them from the payload before it signs the payload.Every new endpoint starts thin.
fatThe platform keeps only the fields you acknowledged by name.An update sets defaultPayloadShape to fat and lists the fields in fatEventsAcknowledgment.

A removed field is absent from the payload. It is not null, so read personal data fields as optional. The platform shapes the payload when it records the event for the endpoint. A later change of shape affects new events only, and a Replay sends the stored payload.

The platform rejects a request that creates an endpoint as fat. A switch to fat needs fatEventsAcknowledgment.fieldsAcknowledged to list every personal data field of the events the subscriptions match, written as <eventType>.<fieldPath>. The list includes the fields of the retractions of those events. A list that misses a field is rejected with status 422 and the error WEBHOOK_FAT_ACK_INCOMPLETE, id DALP-0517. The same check runs when an update changes the subscriptions of a fat endpoint. The platform records who acknowledged the fields, and when.

The Console endpoint editor prepares and records the required acknowledgment for the selected subscriptions. An endpoint read returns its stored fatEventsAcknowledgment.fieldsAcknowledged, not a computed list for a proposed subscription change. The event manifest and the public DALP-0517 error body do not supply that complete consent list. Do not infer consent paths from a sample payload.

Retractions

A retraction withdraws an earlier reported fact. When present, supersedes holds the evt_id of the event it replaces. The named event can be one your endpoint never received.

  • After a reorg removes a block, the platform retracts only an event for which it recorded a successful delivery to your endpoint. Otherwise, it cancels the event and sends no retraction.
  • For committed-state retractions such as trading-venue.trade-settled.retracted, the platform looks up the earlier event id created for your endpoint. This lookup does not require a successful delivery. The supersedes field is absent when no earlier endpoint event id exists, for example because the endpoint did not yet exist.
  • When the platform recorded the earlier event but could not deliver it, the retraction names an event you never received. The platform sends the retraction once the earlier event can no longer be delivered.

Your handler can have applied a chain observation even when its HTTP acknowledgement was lost. Without a recorded successful delivery, the platform can cancel that observation without sending a retraction. Absence of a correction is therefore not confirmation of the canonical chain state. Keep uncertain effects provisional and reconcile them before confirming your business record.

Consumer handling follows these rules:

  • Match by supersedes. If it is absent or unknown, use the payload identifiers, such as tradeId. Reverse only effects your system actually applied.
  • Retain the retraction and audit-log any unknown supersedes reference. An unknown reference alone is not a processing failure. Do not invent a reversal for an action your system never applied.
  • Keep the superseding state if the original arrives later. A Replay can deliver an older observation after a newer one.

The .retracted name suffix does not always mean a retracted lifecycle state. For example, token.corporate-action.retracted has state final and no envelope supersedes link. Match this event through its payload identifiers. Read the event's type as well as lifecycle_state.

The lifecycle state recalled is reserved. The platform sends no event with this state today.

  • Event catalogue: every event the platform sends, when it sends it, and what to do with it.
  • Lifecycle states: what each state means, with worked sequences.
  • Subscriptions: the patterns that select events, and the events the default subscriptions skip.
  • Setup guide: endpoint registration, headers and signature verification.
  • Webhook Delivery: the delivery model and endpoint recovery.

On this page