SettleMint
Webhooks

Webhook endpoints

Configure DALP webhook endpoints, delivery privacy, idempotent mutations, signed receiver handling, retries, replay, and chain-of-custody proofs.

Overview

Webhook endpoints deliver selected DALP events to an external HTTPS URL. Use them when an integration needs pushed event delivery instead of polling token or account collections.

DALP also exposes inbound provider callback endpoints when an external provider must report decisions back to the platform. Provider callbacks are not webhook endpoint subscriptions. DALP owns these fixed intake routes and processes them before any customer-facing event delivery happens.

Use the webhook events reference and the AsyncAPI manifest to check event names, lifecycle states, and payload schemas before choosing endpoint subscriptions.

Endpoint model

Create endpoints with POST /api/v2/webhooks. The request includes:

FieldBehaviour
urlRequired HTTPS target URL for delivery.
displayNameOptional label, up to 200 characters.
subscriptionsEvent patterns to deliver. Defaults to *.final, *.retracted, and *.recalled.
defaultPayloadShapeMust be thin when creating an endpoint. Switch to fat later with a PATCH request and the required field acknowledgement.
counterSignedReceiptsOptional flag for endpoints that return signed delivery receipts.

DALP accepts only public HTTPS receiver URLs. When you create an endpoint or change its URL, DALP resolves the hostname and rejects the request if the URL does not use https://, the hostname cannot be resolved, or any resolved address points to a blocked private, loopback, link-local, carrier-grade NAT, documentation, or IPv4 multicast range. Development and test deployments can explicitly allow loopback URLs for local integration tests; production endpoint URLs must resolve to public addresses.

The same check runs before delivery. If DNS later changes an accepted hostname to a blocked private or non-public address range, DALP will not dispatch the delivery to that address. Keep webhook receiver DNS stable, public, and under the operating team's control.

The create and rotate-secret responses reveal the signing secret once. Later reads return endpoint metadata and secret status, not the cleartext signing secret. If a client retries the same create or rotate request with the same idempotency key, DALP returns the same response envelope with signingSecret: null so the cleartext secret is not exposed again. Store the first dalp_whsk_... value securely, and do not overwrite it with null from an idempotent retry.

Mutation idempotency

Webhook endpoint mutations accept the Idempotency-Key header. Send a stable key when creating an endpoint, updating endpoint settings, rotating secrets, retrying deliveries, replaying events, recalling events, or changing secret state from an automated workflow. If the network drops after DALP accepts the request, retry the same request with the same key instead of submitting a second mutation.

Reuse an idempotency key only for the same request body. Reusing the key for a different body is rejected so one key cannot accidentally describe two different operations.

Keep API mutation idempotency separate from event consumption. The Idempotency-Key protects the request you send to DALP. Your webhook receiver still has to verify the delivered event and dedupe side effects.

Receiver verification and deduplication

Every delivered webhook should be handled as a signed, at-least-once message. Verify the raw request body with the endpoint signing secret before parsing the event. Use verifyWebhook from the DALP SDK when you want the same verify-first pattern used by the event reference examples.

After verification, dedupe each delivery by the webhook-id header before applying side effects. For replayed or retried events, also dedupe the business effect by stable domain fields that survive across deliveries, such as chain ID, transaction hash, log index, resource ID, and lifecycle state when the event type includes them. A replay is another delivery of the same business event, not a new business event.

During signing-secret rotation, keep both the active and previous secrets available to your receiver until the 24-hour overlap ends. DALP may still deliver already-enqueued work signed with the previous secret during that window.

Payload privacy

DALP delivers thin payloads by default. Thin payloads omit configured personal-data fields for event types such as identity registration, access-control role changes, asset issuance, compliance freeze recalls, and token transfers.

Create the endpoint as thin first. Switching an endpoint to fat requires a later PATCH /api/v2/webhooks/{id} request with a fatEventsAcknowledgment.fieldsAcknowledged list that covers every additional field implied by the endpoint's subscriptions. DALP rejects the update when the acknowledgement does not match the subscription set.

Delivery operations

OperationAPI route
List endpointsGET /api/v2/webhooks
Read endpoint metadataGET /api/v2/webhooks/{id}
Update URL, subscriptions, payload shape, receipt mode, or disabled statePATCH /api/v2/webhooks/{id}
Disable an endpointDELETE /api/v2/webhooks/{id}
Enqueue a test eventPOST /api/v2/webhooks/{id}/test-events
List delivery attemptsGET /api/v2/webhooks/{id}/deliveries
Read one delivery attemptGET /api/v2/webhooks/{id}/deliveries/{deliveryId}
Retry one delivery eventPOST /api/v2/webhooks/{id}/deliveries/{deliveryId}/retries
Replay historical eventsPOST /api/v2/webhooks/{id}/replays
Recall an eventPOST /api/v2/webhooks/events/{evtId}/recall
Get chain-of-custody proofGET /api/v2/webhooks/events/{evtId}/chain-of-custody
Rotate the signing secretPOST /api/v2/webhooks/{id}/rotate-secret
Revoke the previous signing secretPOST /api/v2/webhooks/{id}/revoke-previous-secret
Read delivery statisticsGET /api/v2/webhooks/stats

When updating an endpoint URL while deliveries are pending, pass acknowledgePending=true only when you intend DALP to retarget those queued attempts to the new URL.

Secret rotation keeps the previous signing secret valid for a 24-hour overlap. Revoke the previous secret after DALP has observed delivery under the new secret.

Retry, replay, and consumer idempotency

Use the retry and replay routes for different recovery jobs:

Recovery jobUse it whenRequest shapeConsumer expectation
Retry one deliveryOne recorded delivery attempt needs to be scheduled again for the same event.POST /api/v2/webhooks/{id}/deliveries/{deliveryId}/retriesDedupe by the webhook-id header before applying side effects.
Replay an eventA known event must be enqueued for the endpoint again.POST /api/v2/webhooks/{id}/replays with evtId and optional chainIdTreat the replay as another delivery of the same event, not as a new business event.
Replay a block rangeA receiver was offline or a new endpoint must catch up from historical chain events.POST /api/v2/webhooks/{id}/replays with fromBlock, optional toBlock, chainId, and confirmLargeRange for large rangesDedupe delivery attempts by webhook-id. Dedupe business side effects by stable payload fields such as transaction hash, log index, and lifecycle state when the event type includes them.

Replay responses return a replayId, the endpointId, and eventsEnqueued. The response also includes snapshotToBlock when DALP bounded the replay to a chain snapshot. Replays enqueue delivery work; they do not change the original event's lifecycle state.

For request-to-chain reconciliation, keep Platform API idempotency and webhook outcome handling separate. A cached mutation response proves that DALP accepted the synchronous request for that idempotency key. The webhook event proves the later chain outcome. See idempotency and on-chain outcome for the consumer-side reconciliation pattern.

Delivery failure classes and retries

Each recorded delivery attempt carries a failureClass when it did not succeed. List attempts with GET /api/v2/webhooks/{id}/deliveries or read one with GET /api/v2/webhooks/{id}/deliveries/{deliveryId} to see the class for a failed attempt. The same classes back the delivery and failure views in the Console.

DALP only re-attempts failures that a later delivery can plausibly recover from. A failure that would return the same result on every retry is terminal: DALP stops re-attempting it and records the failed delivery. Use the class to decide whether to wait for an automatic retry or to fix the receiver and trigger a manual retry. Automatic retries stop once an event is more than three days old, even when the failure class is retryable; if a delivery has been failing for longer than that, trigger a manual retry or replay instead of waiting.

Failure classMeaningRetried automatically
HTTP_4XXDeterministic client error from the receiver, such as 400, 401, 403, 404, or 422.No (terminal)
HTTP_4XX_RETRYABLEA 408 Request Timeout or 429 Too Many Requests response.Yes
HTTP_5XXServer error response from the receiver, such as 500, 502, or 503.Yes
DNS_FAILThe receiver hostname could not be resolved.Yes
TLS_FAILThe TLS or certificate handshake with the receiver failed.Yes
CONNECT_TIMEOUTThe connection to the receiver timed out or was aborted.Yes
READ_TIMEOUTThe receiver accepted the connection but did not return a response body in time.Yes
INVALID_RESPONSEThe receiver returned a response DALP could not classify as success.Yes
RECEIPT_TIMEOUTA counter-signed receipt was not submitted before the receipt window closed.Yes
RECEIPT_INVALID_SIGA submitted counter-signed receipt failed signature verification.No (terminal)
RECEIPT_HASH_MISMATCHA submitted counter-signed receipt did not match the delivered event hash.No (terminal)

A terminal HTTP_4XX means the request reached your receiver and was rejected for a reason that will not change on retry, such as authentication, authorization, a missing route, or a request your handler considers invalid. Fix the receiver, then trigger a manual retry with POST /api/v2/webhooks/{id}/deliveries/{deliveryId}/retries. Return 408 or 429 instead when your receiver is temporarily unable to accept the delivery and you want DALP to keep retrying on its own.

Event recall

Use event recall when a previously recorded compliance freeze event should no longer be treated as the current event in the webhook timeline. Recall is available only for event types with a registered .recalled variant in the event manifest. DALP records the recalled event, the original event it supersedes, and the recall reason.

curl --request POST "$DALP_API_URL/api/v2/webhooks/events/evt_01h.../recall" \
  --header "X-Api-Key: $DALP_API_TOKEN" \
  --header "Idempotency-Key: recall-evt-01h-20260608" \
  --header "Content-Type: application/json" \
  --data '{"reason":"Corrected compliance event after review"}'

The path has one parameter:

ParameterRequiredBehaviour
evtIdYesExisting webhook event id to mark as recalled.

The request body has one field:

FieldRequiredBehaviour
reasonYesHuman-readable recall reason, from 1 to 2000 characters.

The response returns the original event id as evtId, the new recalled event id as recalledEvtId, the event it supersedes as supersedes, the submitted reason, and recalledByUserId for the API caller who submitted the recall. Delivered recalled webhook events identify the recall with supersedes. Fat deliveries also include the reason in reasonCode; default thin deliveries omit that field, so use the API response if you need the submitted reason or caller attribution. Send an Idempotency-Key when recall is driven by automation so a retry cannot create a second recall event for the same request.

The caller must have the compliance recall permission for the active organisation. If the caller does not have that permission, DALP returns the same not-found style error used for unavailable webhook events.

Ripple Custody inbound callbacks

POST /api/webhooks/ripple is the route Ripple Custody calls to report intent events. Ripple calls this route when a custody intent changes state. DALP parses the provider envelope and acknowledges intermediate events. Terminal approval or rejection events are dispatched to the custody approval monitor for the matching intent.

This route is separate from outbound webhook endpoints created with POST /api/v2/webhooks:

DirectionPurposeWho configures the URLPublic API surface
Outbound webhook endpointDALP sends selected platform events to your HTTPS receiverYou create and manage the receiver URL/api/v2/webhooks and child routes
Ripple Custody callbackRipple Custody sends intent state changes back to DALPThe platform exposes the DALP callback URL to the provider integrationPOST /api/webhooks/ripple

Accepted provider envelope

DALP reads the Ripple Custody event type from payload.type, not from a top-level type field. The envelope can include provider event metadata such as domainId, event id, savedAt, and sequenceNumber.

{
  "domainId": "25aaec0d-e8dc-44b6-8070-9231f1ddadf0",
  "id": "03424a3f-bdfc-4521-b8b2-933a8ff13cce",
  "payload": {
    "id": "35e4d8d9-f943-484b-865c-c736679ba0cc",
    "type": "IntentApproved"
  },
  "savedAt": "2026-05-19T07:32:00.000Z",
  "sequenceNumber": 369
}

Terminal approval events resolve the custody approval as approved. Terminal rejection, failure, expiry, closed, or denied events resolve it as rejected. Intermediate events are acknowledged without changing the approval monitor. Malformed or unrecognised events are also acknowledged without a monitor update.

Authentication and request limits

The Ripple callback body is capped at 64 KB before DALP verifies a signature or parses JSON. Requests over the cap return 413.

If RIPPLE_WEBHOOK_SECRET is set, DALP verifies an HMAC-SHA256 signature from x-ripple-webhook-signature, with x-webhook-signature as a fallback header. A signature mismatch returns 410 so the provider stops retrying a permanently unauthenticated delivery.

In production, DALP refuses to process Ripple callbacks when RIPPLE_WEBHOOK_SECRET is not set unless the deployment explicitly opts out with RIPPLE_INSECURE_NO_HMAC=1. Non-production deployments can proceed without the HMAC secret, but the integration then relies on HTTPS and network allowlisting at the deployment boundary.

Replay and retry behaviour

When the provider envelope includes both domainId and sequenceNumber, DALP records the highest sequence number seen for each (domainId, intent) pair. A duplicate or stale sequence is acknowledged with 200 and is not dispatched again. If the deduplication write fails, DALP still dispatches the terminal event because the approval monitor is idempotent for repeated resolution signals.

DALP returns provider-facing status codes with these meanings:

ConditionResponseEffect
Valid terminal event dispatched to the approval monitor200Delivery accepted
Intermediate, malformed, unrecognised, duplicate, or stale event200Delivery acknowledged without a monitor update
Body exceeds 64 KB413Delivery rejected as too large
Signature mismatch when the HMAC secret is configured410Delivery rejected permanently
Approval monitor is not reachable yet, or a retryable dispatch error occurs503Provider can retry delivery
Approval monitor rejects the signal as a permanent client error410Provider can stop retrying delivery

Related pages:

Fireblocks Custody inbound callbacks

POST /api/webhooks/fireblocks is the route Fireblocks Custody calls to report transaction status events. Fireblocks calls this route when a vault transaction changes state. DALP reads the terminal decision and resolves the matching custody approval, so a pending Fireblocks transaction clears as soon as the provider pushes the result instead of waiting on the next status poll.

This route lets a Fireblocks approval resume on a push rather than a poll. DALP keeps polling Fireblocks as a backstop, so an approval still resolves even if a webhook delivery is missed. You do not call this route; the platform exposes the callback URL to the Fireblocks workspace, and Fireblocks delivers status updates to it.

Like the Ripple Custody callback, this route is separate from the outbound webhook endpoints created with POST /api/v2/webhooks:

DirectionPurposeWho configures the URLPublic API surface
Outbound webhook endpointDALP sends selected platform events to your HTTPS receiverYou create and manage the receiver URL/api/v2/webhooks and child routes
Fireblocks Custody callbackFireblocks sends transaction status changes back to DALPThe platform exposes the DALP callback URL to the Fireblocks workspacePOST /api/webhooks/fireblocks

Accepted provider events

DALP acts only on Fireblocks transaction status events (transaction.status.updated and transaction.approval_status.updated) that carry a transaction id and a terminal status:

  • A transaction that has cleared its authorization policy and is confirming or completed resolves the custody approval as approved.
  • A transaction that was cancelled, rejected, blocked, failed, or timed out resolves it as rejected.

Intermediate, unrelated, or unrecognised events are acknowledged without changing the custody approval. DALP routes the decision to whichever approval is waiting on that Fireblocks transaction id, whether it is a provider-native broadcast approval or a sign-only approval.

Authentication and request limits

The Fireblocks callback body is capped at 64 KB before DALP verifies a signature or parses JSON. Requests over the cap return 413.

The callback endpoint is unauthenticated: no API key or bearer token is required to call it. DALP verifies the detached JWS in the Fireblocks-Webhook-Signature header against the Fireblocks public keys published at the workspace's JWKS endpoint. The endpoint is region-specific, so configure the JWKS URL that matches the Fireblocks workspace. Key rotation is automatic because the signature header selects the signing key. A request whose signature does not verify is acknowledged with 200 and is not acted on, so an unverifiable delivery cannot resolve a custody approval and Fireblocks does not retry a payload that can never succeed.

Provider-facing status codes

ConditionResponseEffect
Valid terminal status resolved to the custody approval200Delivery accepted
Intermediate, unrecognised, or already-resolved event200Delivery acknowledged without changing the approval
Signature does not verify, or the payload is not valid JSON200Delivery acknowledged without changing the approval
Body exceeds 64 KB413Delivery rejected as too large
Restate or the approval monitor is unreachable, or a retryable transport error occurs503Provider can retry delivery

Because an unverifiable or malformed delivery returns 200, the polling backstop remains the safety net for any decision a webhook never delivers.

Related pages:

DFNS Custody inbound callbacks

POST /api/webhooks/dfns is the route DFNS Custody calls to report signing and approval events. DFNS calls this route when a signature request or its approval policy reaches a final decision. DALP reads the terminal decision and resolves the matching custody approval, so a pending DFNS signature clears on the provider's push instead of waiting on the next status poll.

You do not call this route. The platform exposes the callback URL to your DFNS application, and DFNS delivers events to it. Like the Ripple and Fireblocks callbacks, it is separate from the outbound webhook endpoints created with POST /api/v2/webhooks:

DirectionPurposeWho configures the URLPublic API surface
Outbound webhook endpointDALP sends selected platform events to your HTTPS receiverYou create and manage the receiver URL/api/v2/webhooks and child routes
DFNS Custody callbackDFNS sends signing and approval decisions back to DALPThe platform exposes the DALP callback URL to your DFNS applicationPOST /api/webhooks/dfns

Accepted provider events

DALP resolves the custody approval from a terminal DFNS event that carries a signature id:

  • A completed signature event, or an approved policy decision for a policy-gated sign, resolves the custody approval as approved.
  • A rejected, failed, or denied signature or policy event resolves it as rejected.

Both signing paths are covered: provider-native signature events and policy-gated signs that finish with an approval-policy decision rather than a signature event. Intermediate or unrecognised events are acknowledged without changing the custody approval, and so are events without a recognisable signature id.

Authentication and request limits

The DFNS callback body is capped at 64 KB before DALP verifies a signature or parses JSON. Requests over the cap return 413.

The callback endpoint is unauthenticated: no API key or bearer token is required to call it. DALP verifies an HMAC-SHA256 signature from the x-dfns-webhook-signature header against the configured DFNS webhook secret, using a constant-time comparison. The signature value is accepted with or without a leading sha256= prefix. A delivery whose signature does not verify is acknowledged with 200 and is not acted on, so an unverifiable delivery cannot resolve a custody approval and DFNS does not retry a payload that can never succeed.

If the DFNS webhook secret is not configured, DALP cannot verify deliveries and returns 503 so DFNS retries after the secret is set, rather than dropping a terminal approval.

Provider-facing status codes

ConditionResponseEffect
Valid terminal event resolved to the custody approval200Delivery accepted
Intermediate, unrecognised, or unmatched event200Delivery acknowledged without changing the approval
Signature does not verify, or the payload is not valid JSON200Delivery acknowledged without changing the approval
Body exceeds 64 KB413Delivery rejected as too large
Webhook secret not configured, or a retryable dispatch error occurs503Provider can retry delivery

Because an unverifiable or malformed delivery returns 200, the polling backstop remains the safety net for any decision a webhook never delivers.

Related pages:

Counter-signed receipts

Enable counterSignedReceipts when the receiving system must prove that it accepted a delivered event. DALP accepts receipts only for deliveries queued with counter-signed receipts enabled. Each receipt record stores the submitted signature, inner event hash, receipt time, and verification status.

OperationAPI route
List counter-signed webhook receiptsGET /api/v2/webhook-receipts
Read one counter-signed webhook receiptGET /api/v2/webhook-receipts/{id}
Submit a consumer counter-signed receiptPOST /api/v2/webhook-receipts

A receipt submission includes deliveryId, evtId, endpointId, consumerSignature, and innerEventHash. The consumer signature is an HMAC-SHA256 signature over the inner event hash. Generate it with the endpoint signing secret after removing the dalp_whsk_ prefix, or use the DALP SDK helper that normalizes webhook secrets for Standard Webhooks. DALP also compares the submitted hash with the delivered event body, so a receipt only verifies when the signature and delivered payload hash both match.

Receipt window

The receipt window is short. After delivering an event to a counter-signed endpoint, DALP waits a default of 30 seconds, and never more than 60 seconds, for the consumer to submit its receipt. Submit the receipt as part of handling the delivery rather than on a deferred or batched schedule.

Late receipts are rejected after the receipt window closes, and the attempt is recorded with the RECEIPT_TIMEOUT failure class. Because RECEIPT_TIMEOUT is retried automatically, a consumer that misses the window should acknowledge the next retry attempt instead of trying to repair the timed-out delivery.

Audit proof

DALP records delivery rows with the fields that were redacted during delivery preparation. It also records hop hashes for the prepared payload.

Use GET /api/v2/webhooks/events/{evtId}/chain-of-custody when an audit workflow needs proof for one event. The response uses the standard single-resource envelope:

{
  "data": {
    "evtId": "evt_01h...",
    "hops": [
      {
        "stage": "outbox-write",
        "contentHash": "sha256:4f7c...",
        "signedBy": "0x...",
        "recordedAt": "2026-05-13T07:32:00.000Z"
      }
    ],
    "merkleRoot": "7a1f...",
    "platformSignature": "dalp-platform:7a1f..."
  },
  "links": {
    "self": "/v2/webhooks/events/evt_01h.../chain-of-custody"
  }
}

The hops array lists the recorded delivery stages and content hashes. signedBy is present when a hop has a recorded signer. Downstream systems can compare the hop hashes with the merkleRoot and platform signature when they need evidence of what DALP prepared for delivery.

Related pages:

On this page