Skip to content

The webhooks feature must be enabled using a feature flag on your Ripple Custody instance. Contact your Ripple liaison if you're unable to access the feature.

Use this page to manage webhook channels with the Event Distribution Service (EDS) API. Webhooks push event notifications to an HTTPS endpoint that you control. To pull event history for reconciliation or audit workflows, see Manage events with the API.

Webhook actions

ActionAPI procedureAPI reference
Create a webhook channelCreate a webhook channelCreate a channel
List webhook channelsList webhook channelsGet all channels
Get webhook channel detailsGet webhook channel detailsGet channel details
Update a webhook channelUpdate a webhook channelUpdate a channel
Test a webhook channelTest a webhook channelTest a channel
Delete a webhook channelDelete a webhook channelDelete a channel
List delivery events across channelsTrack webhook delivery eventsGet all events
List delivery events for a channelTrack webhook delivery eventsGet all events for a channel
Get delivery event detailsTrack webhook delivery eventsGet channel event details

Before you start

Prepare the following values:

ValueDescription
domainIdDomain that owns the webhook channel.
JWT_TOKENJWT for an authenticated API user.
createdBy or lastUpdatedByUser ID for the user creating or updating the channel.
Webhook URLHTTPS endpoint where Ripple Custody sends event notifications.
Event typesEvent payload.type values to subscribe to, such as IntentCreated, IntentUpdated, or IntentClosed.

You must be a user with the eds-manager role to create and manage webhook channels for your domain.

Choose event types

You can subscribe to many event types when configuring a webhook. For detailed information about each event type and complete payload structures, see Event payload reference.

For intent state changes, subscribe to IntentUpdated to receive updates when an intent is approved or rejected. Subscribe to IntentClosed to receive updates when an intent reaches its final state.

Webhook callback payload

When a subscribed event occurs, Ripple Custody sends a minimal event payload to your webhook URL. The callback body uses the event shape returned by the Events API and is designed for easy parsing.

{
  "domainId": "25aaec0d-e8dc-44b6-8070-9231f1ddadf0",
  "payload": {
    "id": "35e4d8d9-f943-484b-865c-c736679ba0cc",
    "type": "IntentCreated"
  },
  "id": "03424a3f-bdfc-4521-b8b2-933a8ff13cce",
  "sequenceNumber": 369,
  "savedAt": "2025-03-07T14:22:37.389Z"
}
FieldDescription
domainIdDomain where the event was generated.
payloadEvent-specific payload. The payload includes a type discriminator.
idUnique event ID.
sequenceNumberEvent sequence number. Sequence numbers are strictly increasing, but may not be contiguous.
savedAtTimestamp when the event was saved.

For event-specific payload fields and event type names, see Event payload reference.

Create a webhook channel

Call POST /v1/domains/{domainId}/channels to create a webhook channel.

curl -X POST "${CUSTODY_API_URL}/v1/domains/${DOMAIN_ID}/channels" \
  -H "Authorization: Bearer ${JWT_TOKEN}" \
  -H "Content-Type: application/json" \
  -d @create-webhook-channel.json

The request body uses the EDS_WebhookChannelCreate schema:

{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "name": "My Webhook Channel",
  "supportedEventTypes": [
    "IntentCreated",
    "IntentUpdated",
    "IntentClosed"
  ],
  "createdBy": "b7c8d9e0-f1a2-3456-bcde-f23456789012",
  "type": "WEBHOOK",
  "url": "https://your-domain.com/webhook-endpoint"
}

Create request fields

FieldTypeRequiredDescription
idstring, UUIDYesUnique identifier for the webhook channel.
namestringYesDescriptive channel name.
supportedEventTypesarray of stringsYesEvent payload.type values to subscribe to.
createdBystring, UUIDYesUser ID for the user creating the channel.
typestringYesChannel type. For webhooks, use WEBHOOK.
urlstringYesWebhook endpoint URL where events are sent.
statusstringNoInitial channel status. Supported values are ACTIVE and DISABLED.
maxRetriesintegerNoMaximum number of retry attempts for failed webhook deliveries.

The API returns the created channel:

{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "domainId": "25aaec0d-e8dc-44b6-8070-9231f1ddadf0",
  "name": "My Webhook Channel",
  "supportedEventTypes": [
    "IntentCreated",
    "IntentUpdated",
    "IntentClosed"
  ],
  "type": "WEBHOOK",
  "status": "ACTIVE",
  "maxRetries": 3,
  "url": "https://your-domain.com/webhook-endpoint",
  "createdBy": "b7c8d9e0-f1a2-3456-bcde-f23456789012",
  "lastUpdatedBy": "b7c8d9e0-f1a2-3456-bcde-f23456789012",
  "createdAt": "2025-03-07T14:22:37.389Z",
  "lastUpdatedAt": "2025-03-07T14:22:37.389Z",
  "errorRate": 0
}

Channel response fields

FieldDescription
idUnique channel ID.
domainIdDomain that owns the channel.
nameChannel name.
supportedEventTypesEvent types subscribed by the channel.
typeChannel type. Webhook channel responses use WEBHOOK.
statusChannel status. Supported response values are ACTIVE and DISABLED.
maxRetriesMaximum number of retry attempts for failed webhook deliveries.
urlWebhook endpoint URL.
createdByUser ID for the user who created the channel.
lastUpdatedByUser ID for the user who last updated the channel.
createdAtTimestamp when the channel was created.
lastUpdatedAtTimestamp when the channel was last updated.
errorRateWebhook delivery error rate.

List webhook channels

Call GET /v1/domains/{domainId}/channels to retrieve all webhook channels for a domain.

curl -X GET "${CUSTODY_API_URL}/v1/domains/${DOMAIN_ID}/channels" \
  -H "Authorization: Bearer ${JWT_TOKEN}"

The response is an array of channel objects.

Get webhook channel details

Call GET /v1/domains/{domainId}/channels/{channelId} to retrieve one webhook channel.

curl -X GET "${CUSTODY_API_URL}/v1/domains/${DOMAIN_ID}/channels/${CHANNEL_ID}" \
  -H "Authorization: Bearer ${JWT_TOKEN}"

The response is a channel object.

Update a webhook channel

Call PATCH /v1/domains/{domainId}/channels/{channelId} to update a webhook channel. Include only the fields you need to change.

curl -X PATCH "${CUSTODY_API_URL}/v1/domains/${DOMAIN_ID}/channels/${CHANNEL_ID}" \
  -H "Authorization: Bearer ${JWT_TOKEN}" \
  -H "Content-Type: application/json" \
  -d @update-webhook-channel.json

The request body uses the EDS_ChannelUpdate schema:

{
  "name": "Operations Webhook Channel",
  "supportedEventTypes": [
    "IntentCreated",
    "IntentUpdated",
    "IntentClosed"
  ],
  "status": "active",
  "maxRetries": 3,
  "lastUpdatedBy": "b7c8d9e0-f1a2-3456-bcde-f23456789012"
}
FieldTypeDescription
namestringNew channel name.
supportedEventTypesarray of stringsNew list of event types to subscribe to.
statusstringNew channel status. The update schema supports active and disabled.
maxRetriesintegerNew maximum number of retry attempts for failed webhook deliveries.
lastUpdatedBystring, UUIDUser ID for the user updating the channel.

The update request schema uses lowercase active and disabled values. Channel responses use uppercase ACTIVE and DISABLED values.

The API returns the updated channel object.

Test a webhook channel

Call POST /v1/domains/{domainId}/channels/{channelId}/test to test a webhook channel. The operation does not define a request body.

curl -X POST "${CUSTODY_API_URL}/v1/domains/${DOMAIN_ID}/channels/${CHANNEL_ID}/test" \
  -H "Authorization: Bearer ${JWT_TOKEN}"

The API returns 200 OK when the test request is accepted.

Delete a webhook channel

Call DELETE /v1/domains/{domainId}/channels/{channelId} to delete a webhook channel. The operation does not define a request body.

curl -X DELETE "${CUSTODY_API_URL}/v1/domains/${DOMAIN_ID}/channels/${CHANNEL_ID}" \
  -H "Authorization: Bearer ${JWT_TOKEN}"

The API returns 200 OK when the channel is deleted.

Track webhook delivery events

EDS delivery events are operational records for webhook delivery attempts. They are different from the event payload sent to your webhook endpoint.

TaskEndpoint
List delivery events across all channels in a domainGET /v1/domains/{domainId}/channels/events
List delivery events for one channelGET /v1/domains/{domainId}/channels/{channelId}/events
Get one delivery eventGET /v1/domains/{domainId}/channels/{channelId}/events/{eventId}

List all delivery events across channels:

curl -X GET "${CUSTODY_API_URL}/v1/domains/${DOMAIN_ID}/channels/events" \
  -H "Authorization: Bearer ${JWT_TOKEN}"

List delivery events for one channel:

curl -X GET "${CUSTODY_API_URL}/v1/domains/${DOMAIN_ID}/channels/${CHANNEL_ID}/events" \
  -H "Authorization: Bearer ${JWT_TOKEN}"

Get one delivery event:

curl -X GET "${CUSTODY_API_URL}/v1/domains/${DOMAIN_ID}/channels/${CHANNEL_ID}/events/${EVENT_ID}" \
  -H "Authorization: Bearer ${JWT_TOKEN}"

Delivery event list operations return an array of EDS_Event objects. The delivery event detail operation returns one EDS_Event object.

{
  "id": "c0c54215-77e8-4e8f-8b0f-b3d60269f2f7",
  "channelId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "channelName": "My Webhook Channel",
  "type": "IntentCreated",
  "status": "FAILED",
  "createdAt": "2025-03-07T14:22:37.389Z",
  "lastUpdatedAt": "2025-03-07T14:22:40.889Z",
  "retriedCount": 3,
  "payload": "{\"id\":\"35e4d8d9-f943-484b-865c-c736679ba0cc\",\"type\":\"IntentCreated\"}"
}
FieldDescription
idUnique delivery event ID.
channelIdWebhook channel ID.
channelNameWebhook channel name.
typeEvent type associated with the delivery event.
statusDelivery status. Supported values are PENDING, SUCCESS, and FAILED.
createdAtTimestamp when the delivery event was created.
lastUpdatedAtTimestamp when the delivery event was last updated.
retriedCountNumber of retry attempts recorded for the delivery event.
payloadEvent payload stored as a string.

Delivery behavior

If a webhook delivery fails, for example if your endpoint is unavailable or returns an error, Ripple Custody retries delivery using exponential backoff.

Retry behavior

  1. Ripple Custody sends the event to your webhook endpoint.
  2. If delivery fails, the system waits and retries using exponential backoff.
  3. After the maximum number of retry attempts is exhausted, the delivery event is marked as FAILED and automatic retries stop.

The default retry behavior is:

ParameterDefaultDescription
Max retries3Number of retry attempts before marking the delivery event as FAILED.
Initial interval500 msWait time before the first retry.
Multiplier2Factor applied to increase wait time between retries.
Max interval5000 msUpper limit for wait time between retries.

With the default values, if delivery fails, the system retries after 500 ms, then 1000 ms, then 2000 ms.

The EDS channel schema exposes maxRetries for channel configuration. Other retry timing settings are instance-level operational configuration and require coordination with Ripple teams to modify.

Timeout configuration

ParameterDefaultDescription
Request timeout30 secondsMaximum time to wait for your endpoint to respond.
Connection timeout10 secondsMaximum time to establish a connection to your endpoint.

If your endpoint does not respond within the timeout period, the delivery is considered failed and is retried.

HTTP status code handling

Status code rangeBehavior
2xxDelivery successful, no retry.
3xxRedirects are not followed. Delivery is treated as failed and retried.
4xxDelivery failed and retried, except for 410 Gone.
410Delivery failed, no retry. The endpoint is treated as permanently unavailable.
5xxDelivery failed and retried.
TimeoutDelivery failed and retried.
Connection errorDelivery failed and retried.

To prevent retries for a specific event, return 410 Gone. For all other cases, return 2xx to acknowledge successful receipt or return another status code to allow retries.

Rate limiting

Webhook deliveries are not rate-limited by default. Design your endpoint to handle:

  • Multiple concurrent webhook deliveries.
  • Bursts of events during high activity periods.
  • Retry attempts for failed deliveries.

If your endpoint cannot keep up with event volume, consider:

  • Implementing a queue to buffer incoming webhooks.
  • Scaling your webhook receiver horizontally.
  • Using AMQP queues instead for guaranteed delivery and backpressure handling.

Handle failed deliveries

Use EDS delivery events, the Events API, and any configured AMQP integration when recovering from webhook delivery failures:

  1. Check delivery event records for FAILED status.
  2. Use retriedCount and lastUpdatedAt to understand retry activity.
  3. Use List events with sortBy=sequenceNumber to reconcile the event history your system processed.
  4. Page through Events API results with startingAfter; the Events API schema does not define time-range filters.
  5. If your deployment includes an AMQP queue integration, inspect the queue to recover missed events. Contact Ripple support for help with AMQP-based recovery.
  6. Process any missing event IDs or sequence numbers in your integration.

Secure your webhook endpoint

Secure the endpoint that receives webhook callbacks:

  • Use HTTPS endpoints.
  • Validate incoming requests.
  • Implement authentication or authorization for your receiver.
  • Use IP allowlisting if required by your environment.

Want to manage webhooks with the UI instead? See Manage webhooks in the UI.