> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ramphub.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Webhooks

Register your merchant endpoint in the dashboard, then verify every signature before you update local state.

> **Why this page matters**
> Webhooks are the main signal that keeps your app in sync with RampHub. If you get this right, the rest of the trade lifecycle is much easier to trust.

## Headers

| Header                | Description                                     |
| --------------------- | ----------------------------------------------- |
| `x-ramphub-signature` | HMAC-SHA256 signature of the raw request body.  |
| `x-ramphub-event`     | Lifecycle event name for the delivery.          |
| `x-ramphub-delivery`  | Unique delivery id for idempotency and retries. |

## Signing secret

When you register a webhook endpoint in the business dashboard, RampHub generates a signing secret for that endpoint. Treat that secret as a server-side credential for the system that receives the webhook.

* Store the secret in the receiver's environment or secret manager.
* Never put it in a browser bundle or public config file.
* Copy it when the dashboard reveals it and keep it on the receiving server only.
* Verify `x-ramphub-signature` against the raw request body before you trust the payload.
* Keep using `monitor-status` as the fallback path when a webhook is delayed or missing.
* If you rotate the endpoint secret, update the receiving server immediately.

## Events

| Event                   | Description                                                                                                                                                                                                                                                                                                  |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `transaction.created`   | Transaction record created and provider instructions are available.                                                                                                                                                                                                                                          |
| `transaction.updated`   | Non-terminal lifecycle update from the provider or settlement flow. Dashboard labels this using the current stage, such as `Order placed`, `Awaiting settlement`, `Forwarded to provider`, `Awaiting customer payment`, `Invoice created`, `Settling with provider`, `Marked completed`, or `Marked failed`. |
| `transaction.completed` | Transaction is completed in RampHub.                                                                                                                                                                                                                                                                         |
| `transaction.failed`    | Transaction moved to a failed terminal state.                                                                                                                                                                                                                                                                |

### Common stage labels

These are the most common labels you will see in the dashboard when a delivery arrives as `transaction.updated`:

* `Order placed`
* `Awaiting settlement`
* `Forwarded to provider`
* `Awaiting provider funding confirmation`
* `Awaiting customer payment`
* `Invoice created`
* `Settling with provider`
* `Ready for settlement`
* `Awaiting user payout`
* `Marked completed`
* `Marked failed`

## Sample payload

```json theme={null}
{
  "id": "evt_01hzyx8j3m4w9v0g8s2f6t",
  "type": "transaction.completed",
  "createdAt": "2026-04-20T12:00:00.000Z",
  "livemode": true,
  "data": {
    "transactionId": "RH-TX-AB12CD34",
    "status": "completed",
    "provider": "UseBread",
    "asset": "USDT",
    "chain": "base"
  }
}
```

## Signature verification

```js theme={null}
const crypto = require("crypto");

function verifyRampHubWebhook(rawBody, signature, secret) {
  const computed = crypto
    .createHmac("sha256", secret)
    .update(rawBody)
    .digest("hex");

  return crypto.timingSafeEqual(
    Buffer.from(computed),
    Buffer.from(signature),
  );
}
```

## Rule

Keep the receiver idempotent and persist the delivery id from the headers.
