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

# Webhook events

> Payload reference for RaaS Widgets Partner webhook events

## Event types

| Event                     | Description                                                |
| ------------------------- | ---------------------------------------------------------- |
| `link.created`            | A magic link was created                                   |
| `link.opened`             | User opened a magic link                                   |
| `user.created`            | End-user record first created for a `referenceId`          |
| `user.role_added`         | First time the user participated as `sender` or `receiver` |
| `user.data_request`       | Platform needs additional user data for CIP                |
| `user.cip_verified`       | CIP identity check approved                                |
| `user.cip_failed`         | CIP identity check rejected                                |
| `user.cip_manual_review`  | CIP identity check needs manual review                     |
| `operation.created`       | A money transfer operation was created                     |
| `operation.completed`     | An operation settled successfully                          |
| `operation.failed`        | An operation failed permanently                            |
| `operation.cancelled`     | An operation was cancelled                                 |
| `request_money.created`   | Request API created a money request + fund-request link    |
| `request_money.failed`    | Request API call failed                                    |
| `deferred_payout.created` | Deferred payout origination created / first binding        |
| `deferred_payout.updated` | Deferred payout binding or operation linkage changed       |
| `deferred_payout.failed`  | Deferred payout API call failed                            |

<Note>
  Delivery headers: `X-RAAS-Event`, `X-RAAS-Timestamp`, and `X-RAAS-Signature`. See [Webhook security](/raas-widgets/webhooks/security).
</Note>

<Tip>
  New event types may appear. Always acknowledge with HTTP `2xx` and ignore unknowns safely. For operation status meanings, see [Operation lifecycle](/raas-widgets/ops/operation-lifecycle).
</Tip>

Sandbox API base: `https://raas-widgets-backend-sandbox.up.railway.app`

***

## link.created

```json theme={null}
{
  "event": "link.created",
  "timestamp": "2026-07-23T14:30:00.000Z",
  "data": {
    "linkId": "link_acme_a1b2c3d4e5f6",
    "referenceId": "user_12345",
    "url": "https://<flow-host>/link_acme_a1b2c3d4e5f6",
    "status": "created",
    "expiresAt": "2026-07-24T14:30:00.000Z",
    "createdAt": "2026-07-23T14:30:00.000Z"
  }
}
```

Use this to persist the link and deliver `url` to your user asynchronously.

***

## link.opened

```json theme={null}
{
  "event": "link.opened",
  "timestamp": "2026-07-23T14:30:00.000Z",
  "data": {
    "linkId": "link_acme_a1b2c3d4e5f6",
    "referenceId": "user_12345",
    "openedAt": "2026-07-23T14:30:00.000Z",
    "deviceInfo": {
      "userAgent": "Mozilla/5.0 …",
      "platform": "iOS",
      "language": "en-US"
    }
  }
}
```

***

## user.created

```json theme={null}
{
  "event": "user.created",
  "timestamp": "2026-07-30T14:30:00.000Z",
  "data": {
    "userId": "usr_a1b2c3d4e5f6g7h8",
    "referenceId": "user_12345",
    "cipStatus": "pending",
    "rolesParticipated": [],
    "source": "claim",
    "createdAt": "2026-07-30T14:30:00.000Z"
  }
}
```

Fired the first time RaaS Widgets creates a User for your `referenceId` (typically on magic-link claim). `source` is one of `claim`, `request_money`, `deferred_payout_bind`, `terms_accept`, `debug`, or `system`.

Correlate later events with `userId` / `referenceId`. Money movement still uses `operation.*`.

***

## user.role\_added

```json theme={null}
{
  "event": "user.role_added",
  "timestamp": "2026-07-30T14:35:00.000Z",
  "data": {
    "userId": "usr_a1b2c3d4e5f6g7h8",
    "referenceId": "user_12345",
    "role": "sender",
    "rolesParticipated": ["sender"],
    "rolesParticipatedAt": {
      "sender": "2026-07-30T14:35:00.000Z"
    },
    "operationId": "op_acme_x1y2z3",
    "linkId": "link_acme_a1b2c3d4e5f6"
  }
}
```

Emitted once per role the first time the user participates as `sender` (funded / created an operation or deferred origination) or `receiver` (minted a money request or claimed a deferred payout). Optional correlation fields: `operationId`, `requestId`, `originationId`, `linkId`.

Roles are additive history, not entitlements — they do not skip CIP.

***

## user.data\_request

```json theme={null}
{
  "event": "user.data_request",
  "timestamp": "2026-07-23T14:30:00.000Z",
  "data": {
    "dataRequestId": "dr_acme_x9y8z7w6v5u4",
    "referenceId": "user_12345",
    "linkId": "link_acme_a1b2c3d4e5f6",
    "requiredFields": [
      "name.secondName",
      "idNumber",
      "idType",
      "dob"
    ],
    "replyEndpoint": "https://raas-widgets-backend-sandbox.up.railway.app/partner/data-requests/dr_acme_x9y8z7w6v5u4",
    "expiresAt": "2026-07-23T15:30:00.000Z"
  }
}
```

Fulfill with:

```bash theme={null}
curl -X PUT https://raas-widgets-backend-sandbox.up.railway.app/partner/data-requests/dr_acme_x9y8z7w6v5u4 \
  -H "X-API-Key: raas_sandbox_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "referenceId": "user_12345",
    "userData": {
      "idNumber": "GALO900515HDFRPN09",
      "idType": "CURP",
      "dob": "1990-05-15"
    }
  }'
```

Details: [Data requests](/raas-widgets/guides/data-requests).

***

## user.cip\_verified

```json theme={null}
{
  "event": "user.cip_verified",
  "timestamp": "2026-07-30T14:40:00.000Z",
  "data": {
    "userId": "usr_a1b2c3d4e5f6g7h8",
    "referenceId": "user_12345",
    "cipStatus": "verified",
    "linkId": "link_acme_a1b2c3d4e5f6",
    "ticketId": "tkt_abc123",
    "kentuckyStatus": "approved"
  }
}
```

CIP approved. No document or biometric PII is included — use [GET /partner/users/:userId](/raas-widgets/ops/users-and-cip) if you need CIP outcome detail.

Also emitted: `user.cip_failed` (`cipStatus: "failed"`) and `user.cip_manual_review` (`cipStatus: "manual_review"`) with the same shape.

***

## operation.created

```json theme={null}
{
  "event": "operation.created",
  "timestamp": "2026-07-23T14:30:00.000Z",
  "data": {
    "operationId": "op_a1b2c3d4e5f6",
    "linkId": "link_acme_a1b2c3d4e5f6",
    "referenceId": "user_12345",
    "userId": "usr_x9y8z7w6v5u4",
    "requestId": "req_abc123",
    "status": "created",
    "funding": {
      "method": "card",
      "last4": "4242",
      "bankName": "visa"
    },
    "payout": {
      "method": "bank_account"
    },
    "amount": {
      "send": 100.0,
      "receive": 1850.5,
      "rate": 18.505,
      "fee": 3.99,
      "currency": {
        "send": "USD",
        "receive": "MXN"
      }
    },
    "createdAt": "2026-07-23T14:30:00.000Z"
  }
}
```

<Note>
  `requestId` is included only when the operation fulfills a money request (fund-request / Request API). Direct send operations omit it. Deferred payout claims include `originationId` instead.
</Note>

After create, the operation moves through `created` → `processing` → a terminal status. See [Operation lifecycle](/raas-widgets/ops/operation-lifecycle).

***

## operation.completed

```json theme={null}
{
  "event": "operation.completed",
  "timestamp": "2026-07-28T12:00:00.000Z",
  "data": {
    "operationId": "op_a1b2c3d4e5f6",
    "linkId": "link_acme_a1b2c3d4e5f6",
    "userId": "usr_x9y8z7w6v5u4",
    "requestId": "req_abc123",
    "status": "completed",
    "funding": {
      "method": "card"
    },
    "payout": {
      "method": "bank_account"
    },
    "amount": {
      "send": 100.0,
      "receive": 1850.5
    },
    "completedAt": "2026-07-28T12:00:00.000Z"
  }
}
```

Treat this as final success for fulfillment and reconciliation.

***

## operation.failed

```json theme={null}
{
  "event": "operation.failed",
  "timestamp": "2026-07-28T12:05:00.000Z",
  "data": {
    "operationId": "op_a1b2c3d4e5f6",
    "linkId": "link_acme_a1b2c3d4e5f6",
    "userId": "usr_x9y8z7w6v5u4",
    "requestId": "req_abc123",
    "status": "failed",
    "funding": {
      "method": "card"
    },
    "payout": {
      "method": "bank_account"
    },
    "amount": {
      "send": 100.0,
      "receive": 1850.5
    },
    "failedAt": "2026-07-28T12:05:00.000Z"
  }
}
```

<Warning>
  If you held balances or locks on `operation.created`, reverse them when you receive `operation.failed`.
</Warning>

***

## operation.cancelled

```json theme={null}
{
  "event": "operation.cancelled",
  "timestamp": "2026-07-23T14:35:00.000Z",
  "data": {
    "operationId": "op_a1b2c3d4e5f6",
    "linkId": "link_acme_a1b2c3d4e5f6",
    "referenceId": "user_12345",
    "userId": "usr_x9y8z7w6v5u4",
    "status": "cancelled",
    "cancellationReason": "user_requested",
    "cancelledAt": "2026-07-23T14:35:00.000Z"
  }
}
```

Widget-initiated cancels may include `referenceId` and `cancellationReason`. Corridor-driven cancels include funding/payout/amount and may include `requestId` when the op fulfilled a money request. There is no separate `operation.expired` event — funding expiry maps to `cancelled`.

<Warning>
  If you held balances or locks on `operation.created`, reverse them when you receive `operation.cancelled`.
</Warning>

***

## request\_money.created

Emitted after a successful legacy `POST /v1/request-money`. The platform creates a money request and a **fund-request** link for the sender.

```json theme={null}
{
  "event": "request_money.created",
  "timestamp": "2026-07-23T14:30:00.000Z",
  "data": {
    "legacyOperationReferenceId": "OpBnK001",
    "linkId": "link_acme_fund_req_01",
    "fundRequestLink": "https://<fund-request-host>/link_acme_fund_req_01",
    "landingLink": "https://app.example.com/pay?ref=OpBnK001",
    "waLink": "https://wa.me/…",
    "referenceId": "OpBnK001",
    "requestId": "req_abc123",
    "userReferenceId": "user-8842",
    "amount": 150.5,
    "currency": "GTQ",
    "status": "pending",
    "statusDetails": null
  }
}
```

Persist `requestId` and deliver `fundRequestLink` to the sender. Later `operation.*` events for the same ask include the same `requestId`.

Full journey: [Request money lifecycle](/raas-widgets/request-api/lifecycle).

***

## request\_money.failed

Emitted when a legacy Request API `POST` or `GET` under `/v1/request-money` fails (for example identity / watchlist rejection at create).

```json theme={null}
{
  "event": "request_money.failed",
  "timestamp": "2026-06-29T12:00:00.000Z",
  "data": {
    "path": "/v1/request-money",
    "method": "POST",
    "referenceId": "OpBnK001",
    "errorCode": "OFAC_HIT",
    "httpStatus": 403,
    "message": "Identity check rejected: global.watch.list.ofac",
    "details": {
      "restrictionKey": "global.watch.list.ofac"
    }
  }
}
```

<Info>
  `request_money.updated` is **deprecated and not emitted**. For payer fulfillment and settlement, use `operation.created`, `operation.completed`, `operation.failed`, and `operation.cancelled`.
</Info>

***

## deferred\_payout.created

Emitted when a deferred payout origination is created (legacy deferred-payout API or first persistence in an awaiting-claim / payment-bound state).

```json theme={null}
{
  "event": "deferred_payout.created",
  "timestamp": "2026-07-23T14:30:00.000Z",
  "data": {
    "originationId": "dpr_abc123",
    "legacyReferenceId": null,
    "referenceId": "user-12345",
    "userReferenceId": "user-12345",
    "bindingState": "awaiting_claim",
    "payoutClaimLink": "https://<payout-claim-host>/link_…",
    "payoutClaimLinkId": "link_acme_claim_01",
    "operationId": null,
    "sendAmount": 100,
    "totalDebit": 103.5,
    "sendCurrency": "USD",
    "destinationCurrency": "MXN",
    "recipientHint": {
      "firstName": "Maria",
      "lastName": "Lopez"
    },
    "sourceCountry": "US",
    "destinationCountry": "MX"
  }
}
```

See [Deferred payout](/raas-widgets/flows/deferred-payout).

***

## deferred\_payout.updated

Same payload shape as `deferred_payout.created`. Fired when binding state or `operationId` changes (claim, cancel, expire, or operation sync) after the initial create notification.

***

## deferred\_payout.failed

Structured error payload when a deferred payout API call fails (path, method, error code, HTTP status, message) — same pattern as `request_money.failed`.

***

## Handler sketch

```javascript theme={null}
app.post('/webhooks/raas-widgets', async (req, res) => {
  // verify X-RAAS-Signature first, then:
  const { event, data } = JSON.parse(req.body.toString());
  res.status(200).send('OK');

  switch (event) {
    case 'link.created':
    case 'link.opened':
    case 'user.created':
    case 'user.role_added':
    case 'user.data_request':
    case 'user.cip_verified':
    case 'user.cip_failed':
    case 'user.cip_manual_review':
    case 'operation.created':
    case 'operation.completed':
    case 'operation.failed':
    case 'operation.cancelled':
    case 'request_money.created':
    case 'request_money.failed':
    case 'deferred_payout.created':
    case 'deferred_payout.updated':
    case 'deferred_payout.failed':
      await handle(event, data);
      break;
    default:
      console.log('Unknown event', event);
  }
});
```

## Next steps

<CardGroup cols={2}>
  <Card title="Security" icon="shield" href="/raas-widgets/webhooks/security">
    Verify HMAC signatures.
  </Card>

  <Card title="Operation lifecycle" icon="diagram-project" href="/raas-widgets/ops/operation-lifecycle">
    Statuses and which webhooks fire.
  </Card>

  <Card title="Request money lifecycle" icon="arrows-split-up-and-left" href="/raas-widgets/request-api/lifecycle">
    Request → fund-request → operation.
  </Card>

  <Card title="Data requests" icon="database" href="/raas-widgets/guides/data-requests">
    Fulfill `user.data_request`.
  </Card>
</CardGroup>
