# Webhooks

Ripple delivers webhook notifications to your registered HTTPS endpoint when a transaction changes state.

Setup
Webhook endpoint registration is handled by Ripple during onboarding. Contact your Ripple representative to register or update your endpoint URL.

## Configuration

- Your callback URL must be an HTTPS endpoint with a valid public key certificate. HTTP endpoints are not supported.
- Authenticated callback URLs are not supported.
- Contact your Ripple liaison to register or update your callback URL.


## Security

### Signature verification (optional)

Each webhook request includes two headers for verifying authenticity:

| Header | Description |
|  --- | --- |
| `ripple-signature` | Encrypted signature value |
| `ripple-signature-timestamp` | Timestamp when the notification was created |


To verify the signature:

1. Concatenate the `ripple-signature-timestamp` value and the raw request body, separated by a `.` (period).
2. Decrypt the `ripple-signature` using the public key provided by your Ripple liaison.
3. If the decrypted value matches your concatenated string, the webhook is authentic and unaltered.


Tip
Validate the timestamp by comparing it to your current time to detect stale or replayed notifications.

### IP allowlisting (optional)

You can restrict inbound webhook traffic to Ripple's IP addresses. Contact your Ripple liaison for the current list of IP addresses to allowlist.

## Delivery guarantees and retry policy

- Delivery order across events for the same transaction is not guaranteed — always use `updatedAt` to determine the most recent state.
- If additional transaction detail is needed beyond the webhook payload, use `GET /v1/stablecoin/transactions/{id}`.


**At-least-once delivery:** Your endpoint may receive the same event more than once. Use the transaction `id` and `updatedAt` fields to deduplicate.

**Multiple PROCESSING webhooks:** Multiple `PROCESSING` webhooks may be delivered for the same transaction as it advances through Ripple's internal processing stages. Treat these as progress updates — use `updatedAt` to determine the latest state and deduplicate by `id`.

**Expected response:** Ripple expects your webhook endpoint to return an HTTP `200` response. Any other response code is treated as a failure.

### Retry policy

If your endpoint fails to return a `200` response, Ripple retries with exponential backoff:

| Retry | Delay after previous attempt |
|  --- | --- |
| 1 | 1 minute |
| 2 | 2 minutes |
| 3 | 4 minutes |
| 4 | 8 minutes |
| 5 | 16 minutes |
| 6 | 32 minutes |
| 7+ | 1 hour |


Retries continue up to 75 times, spanning approximately 72 hours after the initial failure.

If all retries are exhausted, the event is dropped. Use [Get a transaction](/products/stablecoin/api/reference/rlusd-openapi#operation/getTransaction) as a fallback to reconcile any missed events.

## Webhook payload


```json
{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "eventType": "STABLECOIN_TRANSACTION",
  "eventVersion": 1,
  "eventData": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "type": "REDEMPTION",
    "sourceHash": "4F2A8B1C9D3E7F6A0B5C4D8E2F1A9B3C7D6E0F5A4B8C2D1E9F3A7B6C0D5E8F",
    "status": "COMPLETED",
    "updatedAt": "2026-03-17T10:05:00Z"
  },
  "createDate": "2026-03-17T10:05:04.263Z"
}
```

| Field | Type | Description |
|  --- | --- | --- |
| `id` | string (UUID) | Unique event identifier |
| `eventType` | string | Always `STABLECOIN_TRANSACTION` |
| `eventVersion` | integer | Schema version (currently `1`) |
| `createDate` | string (ISO 8601) | Timestamp when the event was created |
| `eventData.id` | string (UUID) | Transaction ID |
| `eventData.type` | string | null | Transaction type (`ISSUANCE`, `REDEMPTION`, `BRIDGE`) |
| `eventData.status` | string | New transaction status |
| `eventData.sourceHash` | string | null | Source on-chain transaction hash, if available |
| `eventData.destinationHash` | string | null | Destination on-chain transaction hash, if available |
| `eventData.updatedAt` | string (ISO 8601) | Timestamp of the status change |


## Transaction lifecycle

### Issuance (USD → RLUSD)

Ripple mints RLUSD automatically upon confirmed receipt of fiat.


```
USD received → [PROCESSING] → on-chain settlement → [COMPLETED]
```

| Status | When | Notes |
|  --- | --- | --- |
| `PROCESSING` | Transaction created | `eventData.id` is your reference ID for this transaction. |
| `COMPLETED` | On-chain settlement confirmed | `eventData.destinationHash` contains the on-chain transaction hash. |


### Redemption (RLUSD → USD)

#### Auto-Redemption (Default)

Ripple redeems RLUSD and initiates fiat settlement automatically upon receipt of on-chain RLUSD.


```
RLUSD received on-chain → [PROCESSING] → fiat settled → [COMPLETED]
```

| Status | When | Notes |
|  --- | --- | --- |
| `PROCESSING` | RLUSD received on-chain | `eventData.sourceHash` contains the on-chain transaction hash. |
| `COMPLETED` | Fiat settlement confirmed. |  |