diff --git a/docs/digital-wallets.md b/docs/digital-wallets.md
index 6f946fc..a17520b 100644
--- a/docs/digital-wallets.md
+++ b/docs/digital-wallets.md
@@ -6,7 +6,7 @@ sidebar_position: 9
**Does Topper support Apple and Google Pay?**
-Yes.
+Yes, and currently only on `crypto_onramp` flow.
**What are the benefits of using Apple and Google Pay?**
diff --git a/docs/environments.md b/docs/environments.md
index c745e8d..3a00198 100644
--- a/docs/environments.md
+++ b/docs/environments.md
@@ -19,26 +19,37 @@ If you face issues initializing Topper and see a 'something went wrong' error pa
You can bypass email authentication and phone verification codes by typing `000000`.
-### Credit cards
-
-The following card details can be used to force specific outcomes:
-
-| Card number | Outcome |
-|------------------|-------------------------|
-| 4921817844445119 | `success` |
-| 4312810406702461 | `card_unauthorized` |
-| 4414745735532923 | `card_declined_by_bank` |
-| 4916426384864999 | `request_data_invalid` |
-| 4086439018748730 | `card_expired` |
-| 4532942248840268 | `card_unsupported` |
-| 4929216735379028 | `insufficient_funds` |
-| 4748972091871094 | `amount_invalid` |
-| 4916526184701927 | `velocity` |
+### Cards
+
+The following card details can be used to force specific outcomes when creating accounts:
+
+| Card number | Outcome | Type | Country | Brand |
+|------------------|-------------------------|--------|---------|------------|
+| 5318773012490080 | `success` | debit | US | MasterCard |
+| 4748972091871094 | `amount_invalid` | debit | US | Visa |
+| 4818924250131070 | `card_unauthorized` | debit | GB | Visa |
+| 4407108123937239 | `card_unauthorized` | credit | GB | Visa |
+| 4414745735532923 | `card_declined_by_bank` | credit | US | Visa |
+| 5148447461737269 | `card_declined_by_bank` | debit | US | MasterCard |
+| 4086439018748730 | `card_expired` | credit | US | Visa |
+| 4695070264707089 | `card_expired` | debit | US | Visa |
+| 4532942248840268 | `card_unsupported` | credit | AD | Visa |
+| 4472010538259482 | `card_unsupported` | debit | US | Visa |
+| 4916426384864999 | `request_data_invalid` | credit | US | Visa |
+| 4648778096000816 | `request_data_invalid` | debit | US | Visa |
+| 4929216735379028 | `insufficient_funds` | credit | MT | Visa |
+| 4247318851058116 | `insufficient_funds` | debit | US | Visa |
+| 4916526184701927 | `velocity` | credit | AE | Visa |
+| 4467625019643180 | `velocity` | debit | US | Visa |
:::tip
When using the above card numbers, Topper will accept any value for the expiry date and CVV.
:::
+:::caution
+In the `crypto_offramp` flow, only `debit` cards that match the user's country of residence will be accepted.
+:::
+
## Production
After successfully onboarding and testing your integration in our sandbox environment, you can start Topper sessions for your end users using the production environment.
diff --git a/docs/flows/crypto-offramp.mdx b/docs/flows/crypto-offramp.mdx
new file mode 100644
index 0000000..5fdbb3f
--- /dev/null
+++ b/docs/flows/crypto-offramp.mdx
@@ -0,0 +1,754 @@
+---
+sidebar_position: 2
+---
+
+import Tabs from "@theme/Tabs";
+import TabItem from "@theme/TabItem";
+
+# Crypto off-ramp
+
+The crypto off-ramp flow allows a user to sell cryptocurrency and convert it into fiat, which can then be transferred to their linked debit cards.
+
+## Bootstrap token payload
+
+
+
+
+- `partner` (_optional_): Partner object.
+ - `continueUrl` (_optional_): URL to redirect the user to after the order is placed and the funds were received.
+ - `continueUrlTarget` (_optional_): In which tab should the `continueUrl` be opened.
+ - `new-tab`: Open in a new tab.
+ - `same-tab`: Open in the same tab or iframe (default).
+ - `parent-tab`: Useful only in an iframe: open in the tab that contains the iframe.
+ - `displayName` (_optional_): Partner name to be displayed to the user.
+ - `fee` (_optional_): An object configuring the partner fee to be charged.
+ - `percentage`: Percentage of the total source amount (the maximum allowed value is "5").
+- `refund` (_optional_): An object configuring the refund details. The asset and network of the refund will be the same as the source asset and network.
+ - `address`: Address to which the refund will be sent.
+ - `tag` (_optional_): Tag of the crypto transaction, used to complement the `address`.
+ - `type`: Tag type (e.g.: `memo` or `destination-tag`).
+ - `value`: Tag value.
+ - `priority` (_optional_): Priority of the crypto transaction (e.g.: `fast` will enable instant send for `Dash` transactions). Defaults to `normal`.
+- `source` (_optional_): An object configuring the asset and amount to be sold.
+ - `allowedAssets` (_optional_): Set of cryptoassets that the user can set as source asset.
+ - `amount` (_optional_): Amount to be sold.
+ - `asset`: Cryptoasset the user will send.
+ - `editMode` (_optional_): Controls what values the user can change on the widget.
+ - `all-editable`: The user can change `amount`, `asset` and `network` on the widget. (default)
+ - `only-amount`: The user can only change the amount on the widget.
+ - `network` (_optional_): Network of the receiving asset.
+ - `walletSendUrl` (_optional_): URL to redirect the user to send the crypto from their wallet.
+ - `walletSendUrlTarget` (_optional_): In which tab should the `walletSendUrl` be opened.
+ - `new-tab`: Open in a new tab.
+ - `same-tab`: Open in the same tab or iframe (default).
+ - `parent-tab`: Useful only in an iframe: open in the tab that contains the iframe.
+- `target` (_optional_): An object configuring the amount and asset to be paid.
+ - `amount` (_optional_): Amount the user will receive.
+ - `asset`: Currency code in the [ISO 4217](https://www.iso.org/iso-4217-currency-codes.html) format used to receive the funds.
+
+:::note
+At least one of `source.amount` or `target.amount` _must_ be provided, but not both.
+
+The supported values for `target.asset`, `source.asset`, `source.network`, `source.tag` can be found using our [REST API](../rest-api.md), via the [assets endpoint](https://api.topperpay.com/assets/crypto-offramp).
+:::
+
+:::caution
+If `source.allowedAssets` is set, and you define `source.asset` with an asset that is not allowed, the bootstrap will fail.
+
+If `source.allowedAssets` is set and `source.asset` is not, the `source.asset` will default to the first asset on `source.allowedAssets`.
+:::
+
+:::caution
+In the `sandbox` environment, Topper has limited funds on testnets. If you make an order that needs to be refunded using an asset we have no funds for, the order will be stuck indefinitely trying to create the blockchain transaction.
+We recommend that you use `XRP` for testing purposes when integrating Topper since we have a larger quantity of them. If you prefer to test with another asset and network, please reach out to us beforehand so that we can guarantee funds on our pool and give you a smoother integration experience.
+:::
+
+
+
+
+```js
+{
+ "iat": 1679538023,
+ "jti": "4b552af1-1592-42f8-bbc9-dac28e2b4000",
+ "sub": "b9fe022b-f436-49e1-bb89-6f2e8eabf336",
+ // highlight-start
+ "partner": {
+ "continueUrl": "https://example.com",
+ "continueUrlTarget": "new-tab",
+ "displayName": "ACME",
+ "fee": {
+ "percentage": "1"
+ }
+ },
+ "refund": {
+ "address": "0xb794f5ea0ba39494ce839613fffba74279579268",
+ "priority": "normal"
+ },
+ "source": {
+ "allowedAssets": [
+ "BTC",
+ {
+ "asset": "ETH",
+ "networks": [ "ethereum", "arbitrum" ]
+ },
+ { "asset": "XRP" }
+ ]
+ "amount": "1",
+ "asset": "ETH",
+ "editMode": "all-editable",
+ "network": "ethereum",
+ "walletSendUrl": "https://example.com",
+ "walletSendUrlTarget": "new-tab"
+ },
+ "target": {
+ "asset": "USD",
+ }
+ // highlight-end
+}
+```
+
+
+
+
+## Events
+
+### `order:crypto-offramp:committed`
+
+Triggered when a user has placed an order.
+
+
+
+
+- `id`: UUID of the order.
+- `status`: Status of the order (`processing`).
+- `createdAt`: Timestamp at which the order was created.
+- `updatedAt`: Timestamp at which the order was last updated.
+- `origin`: Object containing information about what the user will send.
+ - `amount`: Amount the user will send.
+ - `rate`: Rate used to calculate the amount.
+ - `asset`: Cryptoasset the user will send.
+ - `network`: Network of the sending asset.
+ - `depositAddress`: Object containing information related to the deposit.
+ - `expiredAt`: Timestamp at which the deposit expires.
+ - `remindAt`: Timestamp at which the user is reminded.
+ - `tag`: Tag of the crypto transaction, used to complement the address.
+ - `type`: Tag type.
+ - `value`: Tag value.
+ - `value`: Address to which the user sends the funds.
+- `destination`: Object containing information about what the user will receive.
+ - `amount`: Amount the user will receive.
+ - `rate`: Rate used to calculate the amount.
+ - `asset`: Currency code in the [ISO 4217](https://www.iso.org/iso-4217-currency-codes.html) format used to receive the funds.
+ - `paymentMethod`: Object containing information about the payment method used.
+ - `type`: Type of payment method.
+- `fees`: Array containing fees associated with the order.
+ - `amount`: Amount user was charged for this fee.
+ - `asset`: Asset used to charge the fee.
+ - `normalized`: Amount in USD that the user was charged for this fee.
+ - `type`: Type of fee (`network`, `deposit` or `partner`).
+- `widget`: Widget associated with the session.
+ - `id` UUID of the widget.
+ - `name`: Name of the widget.
+ - `flow`: Flow associated with the widget.
+
+:::note
+The values for `destination.paymentMethod.type` can be found using our [REST API](../rest-api.md), via the [payment methods endpoint](https://api.topperpay.com/payment-methods/crypto-offramp).
+:::
+
+
+
+
+```js
+{
+ "name": "order:crypto-offramp:committed",
+ "id": "00a991cf-a870-43af-88b8-43c51532831d",
+ "bootstrapTokenId": "141bfa06-481e-4684-96eb-cec4ad529616",
+ "data": {
+ // highlight-start
+ "id": "966b8e24-6a65-442a-942e-577f16288789",
+ "status": "processing",
+ "createdAt": "2023-06-12T17:21:21.240Z",
+ "updatedAt": "2023-06-12T17:21:21.240Z",
+ "origin": {
+ "amount": "0.047116964221968237",
+ "rate": "0.00056488387749632223",
+ "asset": "ETH",
+ "network": "ethereum",
+ "depositAddress": {
+ "expiredAt": "2023-06-12T17:21:21.240Z",
+ "remindAt": "2023-06-12T17:21:21.240Z",
+ "value": "0xb794F5eA0ba39494cE839613fffBA74279579268"
+ }
+ },
+ "destination": {
+ "amount": "100.00",
+ "rate": "1770.27534301775263314892",
+ "asset": "USD",
+ "paymentMethod": {
+ "type": "credit-card"
+ }
+ },
+ "fees": [
+ {
+ "amount": "2.42",
+ "asset": "USD",
+ "normalized": "2.42",
+ "type": "deposit"
+ },
+ {
+ "amount": "1.00",
+ "asset": "USD",
+ "normalized": "1.00",
+ "type": "partner"
+ }
+ ],
+ "widget": {
+ "id": "998544f2-5b01-4062-9394-22827ff5db6c",
+ "name": "ACME",
+ "flow": "crypto_offramp"
+ }
+ // highlight-end
+ }
+}
+```
+
+
+
+
+### `order:crypto-offramp:funds-sent`
+
+Triggered when a user has sent funds for their order.
+
+
+
+
+- `id`: UUID of the order.
+- `status`: Status of the order (`processing`).
+- `createdAt`: Timestamp at which the order was created.
+- `updatedAt`: Timestamp at which the order was last updated.
+- `origin`: Object containing information about what the user sent.
+ - `amount`: Amount the user sent.
+ - `rate`: Rate used to calculate the amount.
+ - `asset`: Cryptoasset the user sent.
+ - `network`: Network of the sending asset.
+ - `depositAddress`: Object containing information related to the deposit.
+ - `expiredAt`: Timestamp at which the deposit expires.
+ - `remindAt`: Timestamp at which the user is reminded.
+ - `tag`: Tag of the crypto transaction, used to complement the address.
+ - `type`: Tag type.
+ - `value`: Tag value.
+ - `value`: Address to which the user sends the funds.
+- `destination`: Object containing information about what the user will receive.
+ - `amount`: Amount the user will receive.
+ - `rate`: Rate used to calculate the amount.
+ - `asset`: Currency code in the [ISO 4217](https://www.iso.org/iso-4217-currency-codes.html) format used to receive the funds.
+ - `paymentMethod`: Object containing information about the payment method used.
+ - `type`: Type of payment method.
+- `fees`: Array containing fees associated with the order.
+ - `amount`: Amount user was charged for this fee.
+ - `asset`: Asset used to charge the fee.
+ - `normalized`: Amount in USD that the user was charged for this fee.
+ - `type`: Type of fee (`network`, `deposit` or `partner`).
+- `widget`: Widget associated with the session.
+ - `id` UUID of the widget.
+ - `name`: Name of the widget.
+ - `flow`: Flow associated with the widget.
+
+:::note
+The values for `destination.paymentMethod.type` can be found using our [REST API](../rest-api.md), via the [payment methods endpoint](https://api.topperpay.com/payment-methods/crypto-offramp).
+:::
+
+
+
+
+```js
+{
+ "name": "order:crypto-offramp:funds-sent",
+ "id": "00a991cf-a870-43af-88b8-43c51532831d",
+ "bootstrapTokenId": "141bfa06-481e-4684-96eb-cec4ad529616",
+ "data": {
+ // highlight-start
+ "id": "966b8e24-6a65-442a-942e-577f16288789",
+ "status": "processing",
+ "createdAt": "2023-06-12T17:21:21.240Z",
+ "updatedAt": "2023-06-12T17:21:21.240Z",
+ "origin": {
+ "amount": "0.047116964221968237",
+ "rate": "0.00056488387749632223",
+ "asset": "ETH",
+ "network": "ethereum",
+ "depositAddress": {
+ "expiredAt": "2023-06-12T17:21:21.240Z",
+ "remindAt": "2023-06-12T17:21:21.240Z",
+ "value": "0xb794F5eA0ba39494cE839613fffBA74279579268"
+ }
+ },
+ "destination": {
+ "amount": "100.00",
+ "rate": "1770.27534301775263314892",
+ "asset": "USD",
+ "paymentMethod": {
+ "type": "credit-card"
+ }
+ },
+ "fees": [
+ {
+ "amount": "2.42",
+ "asset": "USD",
+ "normalized": "2.42",
+ "type": "deposit"
+ },
+ {
+ "amount": "1.00",
+ "asset": "USD",
+ "normalized": "1.00",
+ "type": "partner"
+ }
+ ],
+ "widget": {
+ "id": "998544f2-5b01-4062-9394-22827ff5db6c",
+ "name": "ACME",
+ "flow": "crypto_offramp"
+ }
+ // highlight-end
+ }
+}
+```
+
+
+
+
+### `order:crypto-offramp:funds-received`
+
+Triggered when a user has sent funds for their order and we have received them.
+
+
+
+
+- `id`: UUID of the order.
+- `status`: Status of the order (`processing`).
+- `createdAt`: Timestamp at which the order was created.
+- `updatedAt`: Timestamp at which the order was last updated.
+- `origin`: Object containing information about what the user sent.
+ - `amount`: Amount the user sent.
+ - `rate`: Rate used to calculate the amount.
+ - `asset`: Cryptoasset the user sent.
+ - `network`: Network of the sending asset.
+ - `depositAddress`: Object containing information related to the deposit.
+ - `expiredAt`: Timestamp at which the deposit expires.
+ - `remindAt`: Timestamp at which the user is reminded.
+ - `tag`: Tag of the crypto transaction, used to complement the address.
+ - `type`: Tag type.
+ - `value`: Tag value.
+ - `value`: Address to which the user sends the funds.
+- `destination`: Object containing information about what the user will receive.
+ - `amount`: Amount the user will receive.
+ - `rate`: Rate used to calculate the amount.
+ - `asset`: Currency code in the [ISO 4217](https://www.iso.org/iso-4217-currency-codes.html) format used to receive the funds.
+ - `paymentMethod`: Object containing information about the payment method used.
+ - `type`: Type of payment method.
+- `fees`: Array containing fees associated with the order.
+ - `amount`: Amount user was charged for this fee.
+ - `asset`: Asset used to charge the fee.
+ - `normalized`: Amount in USD that the user was charged for this fee.
+ - `type`: Type of fee (`network`, `deposit` or `partner`).
+- `widget`: Widget associated with the session.
+ - `id` UUID of the widget.
+ - `name`: Name of the widget.
+ - `flow`: Flow associated with the widget.
+
+:::note
+The values for `destination.paymentMethod.type` can be found using our [REST API](../rest-api.md), via the [payment methods endpoint](https://api.topperpay.com/payment-methods/crypto-offramp).
+:::
+
+
+
+
+```js
+{
+ "name": "order:crypto-offramp:funds-received",
+ "id": "00a991cf-a870-43af-88b8-43c51532831d",
+ "bootstrapTokenId": "141bfa06-481e-4684-96eb-cec4ad529616",
+ "data": {
+ // highlight-start
+ "id": "966b8e24-6a65-442a-942e-577f16288789",
+ "status": "processing",
+ "createdAt": "2023-06-12T17:21:21.240Z",
+ "updatedAt": "2023-06-12T17:21:21.240Z",
+ "origin": {
+ "amount": "0.047116964221968237",
+ "rate": "0.00056488387749632223",
+ "asset": "ETH",
+ "network": "ethereum",
+ "depositAddress": {
+ "expiredAt": "2023-06-12T17:21:21.240Z",
+ "remindAt": "2023-06-12T17:21:21.240Z",
+ "value": "0xb794F5eA0ba39494cE839613fffBA74279579268"
+ }
+ },
+ "destination": {
+ "amount": "100.00",
+ "rate": "1770.27534301775263314892",
+ "asset": "USD",
+ "paymentMethod": {
+ "type": "credit-card"
+ }
+ },
+ "fees": [
+ {
+ "amount": "2.42",
+ "asset": "USD",
+ "normalized": "2.42",
+ "type": "deposit"
+ },
+ {
+ "amount": "1.00",
+ "asset": "USD",
+ "normalized": "1.00",
+ "type": "partner"
+ }
+ ],
+ "widget": {
+ "id": "998544f2-5b01-4062-9394-22827ff5db6c",
+ "name": "ACME",
+ "flow": "crypto_offramp"
+ }
+ // highlight-end
+ }
+}
+```
+
+
+
+
+### `order:crypto-offramp:completed`
+
+Triggered when a user's order has completed.
+
+
+
+
+- `id`: UUID of the order.
+- `status`: Status of the order (`completed`).
+- `createdAt`: Timestamp at which the order was created.
+- `updatedAt`: Timestamp at which the order was last updated.
+- `origin`: Object containing information about what the user sent.
+ - `amount`: Amount the user sent.
+ - `rate`: Rate used to calculate the amount.
+ - `asset`: Cryptoasset the user sent.
+ - `network`: Network of the sending asset.
+ - `depositAddress`: Object containing information related to the deposit.
+ - `expiredAt`: Timestamp at which the deposit expires.
+ - `remindAt`: Timestamp at which the user is reminded.
+ - `tag`: Tag of the crypto transaction, used to complement the address.
+ - `type`: Tag type.
+ - `value`: Tag value.
+ - `value`: Address to which the user sends the funds.
+- `destination`: Object containing information about what the user received.
+ - `amount`: Amount the user received.
+ - `rate`: Rate used to calculate the amount.
+ - `asset`: Currency code in the [ISO 4217](https://www.iso.org/iso-4217-currency-codes.html) format used to receive the funds.
+ - `paymentMethod`: Object containing information about the payment method used.
+ - `type`: Type of payment method.
+- `fees`: Array containing fees associated with the order.
+ - `amount`: Amount user was charged for this fee.
+ - `asset`: Asset used to charge the fee.
+ - `normalized`: Amount in USD that the user was charged for this fee.
+ - `type`: Type of fee (`network`, `deposit` or `partner`).
+- `widget`: Widget associated with the session.
+ - `id` UUID of the widget.
+ - `name`: Name of the widget.
+ - `flow`: Flow associated with the widget.
+
+:::note
+The values for `destination.paymentMethod.type` can be found using our [REST API](../rest-api.md), via the [payment methods endpoint](https://api.topperpay.com/payment-methods/crypto-offramp).
+:::
+
+
+
+
+```js
+{
+ "name": "order:crypto-offramp:completed",
+ "id": "00a991cf-a870-43af-88b8-43c51532831d",
+ "bootstrapTokenId": "141bfa06-481e-4684-96eb-cec4ad529616",
+ "data": {
+ // highlight-start
+ "id": "966b8e24-6a65-442a-942e-577f16288789",
+ "status": "processing",
+ "createdAt": "2023-06-12T17:21:21.240Z",
+ "updatedAt": "2023-06-12T17:21:21.240Z",
+ "origin": {
+ "amount": "0.047116964221968237",
+ "rate": "0.00056488387749632223",
+ "asset": "ETH",
+ "network": "ethereum",
+ "depositAddress": {
+ "expiredAt": "2023-06-12T17:21:21.240Z",
+ "remindAt": "2023-06-12T17:21:21.240Z",
+ "value": "0xb794F5eA0ba39494cE839613fffBA74279579268"
+ }
+ },
+ "destination": {
+ "amount": "100.00",
+ "rate": "1770.27534301775263314892",
+ "asset": "USD",
+ "paymentMethod": {
+ "type": "credit-card"
+ }
+ },
+ "fees": [
+ {
+ "amount": "2.42",
+ "asset": "USD",
+ "normalized": "2.42",
+ "type": "deposit"
+ },
+ {
+ "amount": "1.00",
+ "asset": "USD",
+ "normalized": "1.00",
+ "type": "partner"
+ }
+ ],
+ "widget": {
+ "id": "998544f2-5b01-4062-9394-22827ff5db6c",
+ "name": "ACME",
+ "flow": "crypto_offramp"
+ }
+ // highlight-end
+ }
+}
+```
+
+
+
+
+### `order:crypto-offramp:failed`
+
+Triggered when a user's order has failed.
+
+
+
+
+- `id`: UUID of the order.
+- `status`: Status of the order (`failed`).
+- `createdAt`: Timestamp at which the order was created.
+- `updatedAt`: Timestamp at which the order was last updated.
+- `origin`: Object containing information about what the user sent.
+ - `amount`: Amount the user sent.
+ - `rate`: Rate used to calculate the amount.
+ - `asset`: Cryptoasset the user sent.
+ - `network`: Network of the sending asset.
+ - `depositAddress`: Object containing information related to the deposit.
+ - `expiredAt`: Timestamp at which the deposit expires.
+ - `remindAt`: Timestamp at which the user is reminded.
+ - `tag`: Tag of the crypto transaction, used to complement the address.
+ - `type`: Tag type.
+ - `value`: Tag value.
+ - `value`: Address to which the user sends the funds.
+- `destination`: Object containing information about what the user would have received.
+ - `amount`: Amount the user would have received.
+ - `rate`: Rate used to calculate the amount.
+ - `asset`: Currency code in the [ISO 4217](https://www.iso.org/iso-4217-currency-codes.html) format used to receive the funds.
+ - `paymentMethod`: Object containing information about the payment method used.
+ - `type`: Type of payment method.
+- `fees`: Array containing fees associated with the order.
+ - `amount`: Amount user was charged for this fee.
+ - `asset`: Asset used to charge the fee.
+ - `normalized`: Amount in USD that the user was charged for this fee.
+ - `type`: Type of fee (`network`, `deposit` or `partner`).
+- `widget`: Widget associated with the session.
+ - `id` UUID of the widget.
+ - `name`: Name of the widget.
+ - `flow`: Flow associated with the widget.
+- `error`: Indicates specific error information.
+ - `reason`: Indicates the reason for the error, possible values are `fraud`.
+
+:::note
+The values for `destination.paymentMethod.type` can be found using our [REST API](../rest-api.md), via the [payment methods endpoint](https://api.topperpay.com/payment-methods/crypto-offramp).
+:::
+
+
+
+
+```js
+{
+ "name": "order:crypto-offramp:failed",
+ "id": "00a991cf-a870-43af-88b8-43c51532831d",
+ "bootstrapTokenId": "141bfa06-481e-4684-96eb-cec4ad529616",
+ "data": {
+ // highlight-start
+ "id": "966b8e24-6a65-442a-942e-577f16288789",
+ "status": "failed",
+ "createdAt": "2023-06-12T17:21:21.240Z",
+ "updatedAt": "2023-06-12T17:21:21.240Z",
+ "origin": {
+ "amount": "0.047116964221968237",
+ "rate": "0.00056488387749632223",
+ "asset": "ETH",
+ "network": "ethereum",
+ "depositAddress": {
+ "expiredAt": "2023-06-12T17:21:21.240Z",
+ "remindAt": "2023-06-12T17:21:21.240Z",
+ "value": "0xb794F5eA0ba39494cE839613fffBA74279579268"
+ }
+ },
+ "destination": {
+ "amount": "100.00",
+ "rate": "1770.27534301775263314892",
+ "asset": "USD",
+ "paymentMethod": {
+ "type": "credit-card"
+ }
+ },
+ "fees": [
+ {
+ "amount": "2.42",
+ "asset": "USD",
+ "normalized": "2.42",
+ "type": "deposit"
+ },
+ {
+ "amount": "1.00",
+ "asset": "USD",
+ "normalized": "1.00",
+ "type": "partner"
+ }
+ ],
+ "widget": {
+ "id": "998544f2-5b01-4062-9394-22827ff5db6c",
+ "name": "ACME",
+ "flow": "crypto_offramp"
+ },
+ "error": {
+ "reason": "fraud"
+ }
+ // highlight-end
+ }
+}
+```
+
+
+
+
+### `order:crypto-offramp:refund:completed`
+
+Triggered when a user's order has been successfully refunded.
+
+
+
+
+- `id`: UUID of the order.
+- `status`: Status of the order (`failed`).
+- `createdAt`: Timestamp at which the order was created.
+- `updatedAt`: Timestamp at which the order was last updated.
+- `origin`: Object containing information about what the user sent.
+ - `amount`: Amount the user sent.
+ - `rate`: Rate used to calculate the amount.
+ - `asset`: Cryptoasset the user sent.
+ - `network`: Network of the sending asset.
+ - `depositAddress`: Object containing information related to the deposit.
+ - `expiredAt`: Timestamp at which the deposit expires.
+ - `remindAt`: Timestamp at which the user is reminded.
+ - `tag`: Tag of the crypto transaction, used to complement the address.
+ - `type`: Tag type.
+ - `value`: Tag value.
+ - `value`: Address to which the user sends the funds.
+- `destination`: Object containing information about what the user would have received.
+ - `amount`: Amount the user would have received.
+ - `rate`: Rate used to calculate the amount.
+ - `asset`: Currency code in the [ISO 4217](https://www.iso.org/iso-4217-currency-codes.html) format used to receive the funds.
+ - `paymentMethod`: Object containing information about the payment method used.
+ - `type`: Type of payment method.
+- `fees`: Array containing fees associated with the order.
+ - `amount`: Amount user was charged for this fee.
+ - `asset`: Asset used to charge the fee.
+ - `normalized`: Amount in USD that the user was charged for this fee.
+ - `type`: Type of fee (`network`, `deposit` or `partner`).
+- `refund`: Object containing information about how much was refunded to the user.
+ - `amount`: Amount the user received.
+ - `rate`: Rate used to calculate the amount.
+ - `asset`: Cryptoasset the user received.
+ - `network`: Network of the receiving asset.
+ - `address`: User's wallet address to receive funds.
+ - `priority`: Priority of the crypto transaction.
+ - `tag`: Tag of the crypto transaction, used to complement the address.
+ - `type`: Tag type (e.g.: `memo` or `destination-tag`).
+ - `value`: Tag value.
+- `widget`: Widget associated with the session.
+ - `id` UUID of the widget.
+ - `name`: Name of the widget.
+ - `flow`: Flow associated with the widget.
+
+:::note
+The values for `destination.paymentMethod.type` can be found using our [REST API](../rest-api.md), via the [payment methods endpoint](https://api.topperpay.com/payment-methods/crypto-offramp).
+:::
+
+
+
+
+```js
+{
+ "name": "order:crypto-offramp:refund:completed",
+ "id": "00a991cf-a870-43af-88b8-43c51532831d",
+ "bootstrapTokenId": "141bfa06-481e-4684-96eb-cec4ad529616",
+ "data": {
+ // highlight-start
+ "id": "966b8e24-6a65-442a-942e-577f16288789",
+ "status": "failed",
+ "createdAt": "2023-06-12T17:21:21.240Z",
+ "updatedAt": "2023-06-12T17:21:21.240Z",
+ "origin": {
+ "amount": "0.047116964221968237",
+ "rate": "0.00056488387749632223",
+ "asset": "ETH",
+ "network": "ethereum",
+ "depositAddress": {
+ "expiredAt": "2023-06-12T17:21:21.240Z",
+ "remindAt": "2023-06-12T17:21:21.240Z",
+ "value": "0xb794F5eA0ba39494cE839613fffBA74279579268"
+ }
+ },
+ "destination": {
+ "amount": "100.00",
+ "rate": "1770.27534301775263314892",
+ "asset": "USD",
+ "paymentMethod": {
+ "type": "credit-card"
+ }
+ },
+ "fees": [
+ {
+ "amount": "2.42",
+ "asset": "USD",
+ "normalized": "2.42",
+ "type": "deposit"
+ },
+ {
+ "amount": "1.00",
+ "asset": "USD",
+ "normalized": "1.00",
+ "type": "partner"
+ }
+ ],
+ "refund": {
+ "amount": "0.047116964221968237",
+ "rate": "0.00056488387749632223",
+ "asset": "ETH",
+ "network": "ethereum",
+ "address": "0xb794F5eA0ba39494cE839613fffBA74279579268",
+ "priority": "normal"
+ },
+ "widget": {
+ "id": "998544f2-5b01-4062-9394-22827ff5db6c",
+ "name": "ACME",
+ "flow": "crypto_offramp"
+ }
+ // highlight-end
+ }
+}
+```
+
+
+
diff --git a/docs/flows/crypto-onramp.mdx b/docs/flows/crypto-onramp.mdx
index 34b5b03..3c6f2f1 100644
--- a/docs/flows/crypto-onramp.mdx
+++ b/docs/flows/crypto-onramp.mdx
@@ -584,7 +584,7 @@ The values for `origin.paymentMethod.type` can be found using our [REST API](../
"id": "998544f2-5b01-4062-9394-22827ff5db6c",
"name": "ACME",
"flow": "crypto_onramp"
- }
+ },
"error": {
"reason": "fraud"
}
diff --git a/docs/webhooks.md b/docs/webhooks.md
index 6f1998d..7dba042 100644
--- a/docs/webhooks.md
+++ b/docs/webhooks.md
@@ -24,13 +24,26 @@ A webhook request will include the following data:
Full information about the available events and their associated payloads can be found on the associated **Flows** page.
-| Flow | Event | Trigger |
-| - | - | - |
-| [crypto_onramp](./flows/crypto-onramp.mdx) | [`order:crypto-onramp:committed`](./flows/crypto-onramp.mdx#ordercrypto-onrampcommitted) | User placed an order. |
-| [crypto_onramp](./flows/crypto-onramp.mdx) | [`order:crypto-onramp:charged`](./flows/crypto-onramp.mdx#ordercrypto-onrampcharged) | User has been charged for their order. |
-| [crypto_onramp](./flows/crypto-onramp.mdx) | [`order:crypto-onramp:completed`](./flows/crypto-onramp.mdx#ordercrypto-onrampcompleted) | User's order has completed. |
-| [crypto_onramp](./flows/crypto-onramp.mdx) | [`order:crypto-onramp:failed`](./flows/crypto-onramp.mdx#ordercrypto-onrampfailed) | User's order has failed. |
-| [crypto_onramp](./flows/crypto-onramp.mdx) | [`order:crypto-onramp:refund:completed`](./flows/crypto-onramp.mdx#ordercrypto-onramprefundcompleted) | User's order has been successfully refunded. |
+### Onramp flow
+
+| Event | Trigger |
+| - | - |
+| [`order:crypto-onramp:committed`](./flows/crypto-onramp.mdx#ordercrypto-onrampcommitted) | User placed an order. |
+| [`order:crypto-onramp:charged`](./flows/crypto-onramp.mdx#ordercrypto-onrampcharged) | User has been charged for their order. |
+| [`order:crypto-onramp:completed`](./flows/crypto-onramp.mdx#ordercrypto-onrampcompleted) | User's order has completed. |
+| [`order:crypto-onramp:failed`](./flows/crypto-onramp.mdx#ordercrypto-onrampfailed) | User's order has failed. |
+| [`order:crypto-onramp:refund:completed`](./flows/crypto-onramp.mdx#ordercrypto-onramprefundcompleted) | User's order has been successfully refunded. |
+
+### Offramp flow
+
+| Event | Trigger |
+| - | - |
+| [`order:crypto-offramp:committed`](./flows/crypto-offramp.mdx#ordercrypto-offrampcommitted) | User placed an order. |
+| [`order:crypto-offramp:funds-sent`](./flows/crypto-offramp.mdx#ordercrypto-offrampfunds-sent) | User has sent funds for their order. |
+| [`order:crypto-offramp:funds-received`](./flows/crypto-offramp.mdx#ordercrypto-offrampfunds-received) | User has sent funds for their order and we have received them. |
+| [`order:crypto-offramp:completed`](./flows/crypto-offramp.mdx#ordercrypto-offrampcompleted) | User's order has completed. |
+| [`order:crypto-offramp:failed`](./flows/crypto-offramp.mdx#ordercrypto-offrampfailed) | User's order has failed. |
+| [`order:crypto-offramp:refund:completed`](./flows/crypto-offramp.mdx#ordercrypto-offramprefundcompleted) | User's order has been successfully refunded. |
## Verifying a request
diff --git a/docs/widgets.md b/docs/widgets.md
index da6b4f0..415e29a 100644
--- a/docs/widgets.md
+++ b/docs/widgets.md
@@ -9,7 +9,7 @@ import TabItem from '@theme/TabItem';
## Creating a widget {#creating-widget}
-As a business customer, you may have one or more widgets which will allow your end users to interact with Topper. A widget is associated with one of the flows supported by Topper — currently [crypto on-ramp](./flows/crypto-onramp.mdx) is the only supported flow.
+As a business customer, you may have one or more widgets which will allow your end users to interact with Topper. A widget is associated with one of the flows supported by Topper — [crypto on-ramp](./flows/crypto-onramp.mdx) or [crypto off-ramp](./flows/crypto-offramp.mdx).
Each widget has its own:
@@ -502,6 +502,52 @@ topper.initialize({ bootstrapToken: });
In order to prevent social and replay attacks, a **bootstrap token** will only be valid for 3 minutes after its issue time (from the `iat` claim). A **bootstrap token** may only be used to create a session one time, any subsequent attempts to create a session with the same token will be rejected.
+## Initiating multiple sessions {#initiate-multiple-sessions}
+
+To allow both crypto onramp and crypto offramp flows to be available when Topper is initialized, you can initialize multiple sessions by providing multiple **bootstrap tokens**.
+
+
+
+
+```
+https://app.sandbox.topperpay.com/?bt=;
+```
+
+
+
+
+```
+https://app.topperpay.com/?bt=;
+```
+
+
+
+
+Using the [Web SDK](./web-sdk.md):
+
+
+
+
+```
+const topper = new TopperWebSdk({ environment: TOPPER_ENVIRONMENTS.SANDBOX });
+
+topper.initialize({ bootstrapTokens: [, ] });
+```
+
+
+
+
+```
+const topper = new TopperWebSdk();
+
+topper.initialize({ bootstrapTokens: [, ] });
+```
+
+
+
+
+By default, the widget will use the first **bootstrap token** passed in the URL as the **active** flow. However, an optional `active_flow` parameter in the URL or `activeFlow` configuration option in the [Web SDK](./web-sdk.md) can be used to explicitly set which flow is active on initialization. The available options are `crypto_onramp` and `crypto_offramp`.
+
## A note about security {#a-note-about-security}
For security reasons, the **widget id** and **key id** we provide for the sandbox and production [environments](./environments.md) will be different. Moreover, you should not use the same signing key for both environments.