<!--
Sitemap:
- [Stridge — The infrastructure bridging crypto payments](/index): Crypto payment infrastructure for modern fintechs. Accept on any chain, settle through the cheapest route, and pay out in any asset — all from a single SDK.
- [API Reference](/api-reference/): Stridge REST API reference — complete endpoint documentation for deposits, payouts, Universal Deposit Addresses, settlements, and supported networks.
- [Changelog](/changelog): Release notes for Stridge SDKs and developer tools.
- [Stridge Gateway Kit](/gateway/): Drop-in deposit and withdraw flows for crypto apps. Mount a single React provider, render a dialog, and ship any-to-any payments in minutes.
- [Getting Started](/getting-started): Get started with Stridge — pick your integration shape, generate keys, and make your first call from the React Kit, the TypeScript SDK, or the REST API.
- [Supported Networks](/networks): Blockchain networks and tokens supported by the Stridge payment infrastructure — network_id (SLIP-44), EIP-155 chain IDs, and the available native and stablecoin assets per chain.
- [TypeScript SDK](/sdk/): TypeScript client for the Stridge Gateway API. Used internally by @stridge/kit and exposed for backend and server integrations that need direct API access.
- [Security](/security/): Stridge Security — how the Stridge KMS protects wallet keys and signs transactions without ever exposing private keys.
- [Universal Deposit Addresses](/uda/): Universal Deposit Addresses (UDA) — one multi-chain deposit address per user, with automatic cross-chain settlement to a fixed destination.
- [Webhooks](/webhooks/): Stridge webhooks — signed HTTP POSTs for deposits, UDA settlements, wallets, and balances. Verify HMAC, handle retries, and use the Dashboard to inspect event payloads.
- [Gateway HTTP API](/gateway/http): Raw HTTP contract for the Stridge Gateway — supported-assets catalogue, gateway/start provisioning, and per-owner status polling.
- [UDA Quickstart](/uda/quickstart): Create your first Universal Deposit Address and trace a deposit end-to-end — from the POST call, through webhooks, to a settled transaction on the destination chain.
- [Settlements](/uda/settlements): UDA settlements — lifecycle, routing scenarios, fees, and the settlement record API. Reconcile deposits with webhooks; the Dashboard shows each settlement end-to-end.
- [UDA Webhook Events](/uda/webhooks): Reference for the three webhook events UDA deposits emit — deposit.confirmed, uda.settlement.created, and uda.settlement.completed — with payloads and lifecycle guidance.
- [Get a single deposit transaction by ID](/api-reference/deposits/get-a-single-deposit-transaction-by-id): Get details of a specific deposit transaction by its unique ID
- [Get a single deposit transaction by transaction id](/api-reference/deposits/get-a-single-deposit-transaction-by-transaction-id): One row per matching tx_id; multiple same-tx transfers are separate rows. Returns the latest by on-chain time (then id). Use GET /v1/deposits with tx_id filter
- [List deposit transactions](/api-reference/deposits/list-deposit-transactions): Get a paginated list of deposit transactions for the authenticated tenant with filtering support
- [Get blockchain assets](/api-reference/networks/get-blockchain-assets): Get a list of all supported blockchain assets (tokens and native assets).
- [Get blockchain networks](/api-reference/networks/get-blockchain-networks): Get a list of all supported blockchain networks.
- [Get network list](/api-reference/networks/get-network-list): Get a public list of all networks with category grouping.
- [Get tenant network](/api-reference/networks/get-tenant-network): Get a specific network for the authenticated tenant by network ID and contract address
- [Get tenant networks](/api-reference/networks/get-tenant-networks): Get a list of networks available to the authenticated tenant with their enabled status
- [Update tenant network status](/api-reference/networks/update-tenant-network-status): Update the enabled status of a network for the authenticated tenant
- [Create payout](/api-reference/payouts/create-payout): Creates a new payout from the tenant's vault wallet to an external address
- [Create payout with USD amount](/api-reference/payouts/create-payout-with-usd-amount): Creates a new payout converting a USD amount to crypto at current rate
- [Get payout by ID](/api-reference/payouts/get-payout-by-id): Retrieves a payout by its ID
- [Get vault address by network](/api-reference/payouts/get-vault-address-by-network): Get the vault address for a specific network
- [Get vault balances](/api-reference/payouts/get-vault-balances): Get balances for all vault addresses with optional filtering
- [Get vault total value](/api-reference/payouts/get-vault-total-value): Get the total USD value across all vault assets
- [List payouts](/api-reference/payouts/list-payouts): Lists payouts for a vault with filtering and pagination
- [List vault addresses](/api-reference/payouts/list-vault-addresses): Get all vault addresses for the authenticated tenant
- [List vaults](/api-reference/payouts/list-vaults): List all vault accounts for the authenticated tenant
- [Transfer from vault to external address](/api-reference/payouts/transfer-from-vault-to-external-address): Transfer assets from the tenant's vault wallet to an external address.
- [Get a settlement](/api-reference/settlements/get-a-settlement): Fetch a single settlement by ID. A settlement is created per confirmed deposit on a UDA address and carries the lifecycle state, scenario, and routing tx ids.
- [Create a UDA address](/api-reference/uda/create-a-uda-address): Allocate a new Universal Deposit Address for the tenant. If a UDA for the (tenant, owner) pair already exists, the existing record is returned with 200 instead
- [Get a cross-chain / cross-token quote](/api-reference/uda/get-a-cross-chain-cross-token-quote): Returns an indicative quote for routing from/to given (chain, token) pair. USD fields are omitted until a price feed is wired in.
- [Get a UDA address](/api-reference/uda/get-a-uda-address): Fetch a single UDA address by ID, including its delegation status.
- [List settlements for a UDA address](/api-reference/uda/list-settlements-for-a-uda-address): List all settlements that have been created for a given UDA address, optionally paginated.
- [List UDA addresses](/api-reference/uda/list-uda-addresses): List UDA addresses belonging to the authenticated tenant. Supports filtering by owner and status and pagination via limit/offset.
- [List UDA-supported chains](/api-reference/uda/list-uda-supported-chains): Returns every chain with `uda_support=true` along with its native currency and configured token contracts. Rows are grouped by network.
- [Retire a UDA address](/api-reference/uda/retire-a-uda-address): Mark a UDA address as retired. Future deposits will no longer trigger settlements; any already-confirmed settlements continue to run to completion.
- [Update a UDA address](/api-reference/uda/update-a-uda-address): Update the destination, accepted tokens, or status of an existing UDA. Owner is immutable.
-->

# Webhooks

Stridge webhooks send real-time HTTP notifications when activity happens in your account — deposits, wallet assignments, transaction lifecycle updates, and balance changes — so you don't have to poll the API.

## How it works

:::::steps

### An event is created

Deposits, wallets, transactions, and balance changes generate events when account activity occurs.

### Stridge matches subscribers

Active webhook subscribers for your tenant are filtered by event type.

### Stridge signs and sends the payload

Each delivery is wrapped in a standard envelope, signed with **HMAC SHA-256**, and sent as an HTTP `POST` to your webhook URL.

### Stridge retries failed deliveries

If your endpoint returns a non-2xx response or times out, Stridge retries with exponential backoff.

:::::

:::info
Deliveries follow the [Standard Webhooks specification](https://github.com/standard-webhooks/standard-webhooks/blob/main/spec/standard-webhooks.md) with an envelope-based payload.
:::

## Event types

### Wallets & deposits

| Event                     | Description                  | Trigger                                               |
| ------------------------- | ---------------------------- | ----------------------------------------------------- |
| `deposit.new`             | New deposit detected         | A blockchain transaction is seen for your address     |
| `deposit.confirmed`       | Deposit confirmed            | A deposit reaches its confirmation target             |
| `address.assigned`        | Address assigned to an owner | A wallet address is assigned to a user or owner       |
| `transaction.broadcasted` | Transaction broadcasted      | A transaction is submitted to the blockchain          |
| `transaction.confirmed`   | Transaction confirmed        | A transaction reaches required confirmations          |
| `transaction.failed`      | Transaction failed           | A transaction fails on-chain                          |
| `balance.updated`         | Balance updated              | A wallet balance changes                              |

### Universal Deposit Addresses

| Event                        | Description            | Trigger                                                                |
| ---------------------------- | ---------------------- | ---------------------------------------------------------------------- |
| `uda.settlement.created`     | Settlement started     | Routing Engine accepted a UDA deposit and began executing the route    |
| `uda.settlement.completed`   | Settlement completed   | Destination transaction landed; funds are in the destination token     |
| `uda.settlement.failed`      | Settlement failed      | All provider attempts exhausted; deposit untouched, manual resolution  |

See [UDA Webhook events](/uda/webhooks) for full UDA payload
references.

## Dashboard: history and payloads

Configure endpoints under **Dashboard → Webhooks**, then use the same page to **review deliveries**: each row is an event (for example `uda.settlement.completed`). Open a row to see **status**, **event type**, **timestamp**, and the **exact JSON body** your server would receive—handy while building handlers or comparing against [settlement records](/uda/settlements).

![Stridge Dashboard: Webhooks list with the details panel open on a completed uda.settlement.completed delivery, showing id, state, provider, scenario, tx ids, token addresses, and amounts](/webhooks/dashboard-webhook-event-details.png)

## Delivery format

Every delivery uses the same envelope:

```json
{
  "id": "7401d9c7-e29d-4374-8952-af40f05168b7",
  "version": "1",
  "type": "deposit.new",
  "time": "2026-02-08 09:46:54.699313",
  "payload": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "network_symbol": "ethereum",
    "tx_hash": "0xabc123...",
    "amount": "100.50",
    "owner": "user@example.com"
  }
}
```

| Field     | Description                                  |
| --------- | -------------------------------------------- |
| `id`      | Unique event idempotency key                 |
| `version` | Webhook format version, currently `1`        |
| `type`    | Event type such as `deposit.new`             |
| `time`    | Event timestamp                              |
| `payload` | Event-specific payload data                  |

## Signature verification

Each request includes three headers:

| Header              | Description                                  |
| ------------------- | -------------------------------------------- |
| `webhook-id`        | Unique event idempotency key                 |
| `webhook-signature` | HMAC SHA-256 signature, hex-encoded          |
| `webhook-timestamp` | Unix timestamp when Stridge sent the request |

The signature is computed as:

```text
message   = webhook-timestamp + "." + raw_request_body
signature = HMAC-SHA256(signing_secret, message)
```

Verify it before trusting the body:

:::code-group

```ts [Node.js]
import { createHmac, timingSafeEqual } from 'node:crypto'

export function verifyWebhookSignature(
  secret: string,
  body: string,
  timestamp: string,
  receivedSignature: string,
) {
  const message = `${timestamp}.${body}`
  const expected = createHmac('sha256', secret).update(message).digest('hex')
  return timingSafeEqual(Buffer.from(expected), Buffer.from(receivedSignature))
}
```

```go [Go]
func verifyWebhookSignature(secret, body, timestamp, receivedSignature string) bool {
    message := timestamp + "." + body
    h := hmac.New(sha256.New, []byte(secret))
    h.Write([]byte(message))
    expected := hex.EncodeToString(h.Sum(nil))
    return hmac.Equal([]byte(expected), []byte(receivedSignature))
}
```

```python [Python]
import hmac, hashlib

def verify_webhook_signature(secret, body, timestamp, received_signature):
    message = f"{timestamp}.{body}"
    expected = hmac.new(secret.encode(), message.encode(), hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, received_signature)
```

:::

:::warning
Always verify the signature before processing the payload. Reject requests with old timestamps to reduce replay risk.
:::

## Retry behavior

Stridge retries failed deliveries with exponential backoff — **up to 5 retries, 10 s initial delay, 10 min cap**. Any `2xx` response marks the delivery as successful.

| Attempt | Delay       |
| ------- | ----------- |
| 1       | Immediate   |
| 2       | 10 seconds  |
| 3       | 20 seconds  |
| 4       | 40 seconds  |
| 5       | 80 seconds  |
| 6       | 160 seconds |

## Consumer checklist

* **Verify every signature** — check `webhook-signature` with the `webhook-timestamp`.
* **Deduplicate by `webhook-id`** — retries will deliver the same event more than once.
* **Respond fast** — return `2xx` immediately after enqueuing; process asynchronously.
* **Expect duplicates** — idempotent handlers are required, not optional.
