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

# Deposits

> Let users fund your app with any crypto, ideal for gaming deposits, embedded wallets & trading apps.

<Info>
  Before going live, you're required to complete [<u>KYB verification</u>](https://docs.hel.io/docs/verification) via the dashboard. Alternatively, get a link from your MP Account Manager.

  **Note:** KYB is not required to start the integration process.
</Info>

## 1. Create your Deposit

Create a deposit via the [<u>Create Deposit endpoint</u>](https://docs.hel.io/reference/deposits/create) or the [<u>dashboard</u>](https://moonpay.hel.io/). Upon creation, a `depositId` will be returned. Configure the following options:

* **Deposit Name:** Assign a unique name to the deposit. Within this section, you can:
  * **Recipient Currency:** Specify the blockchain/currency in which you wish to receive fund
  * **[Payment Options](https://docs.hel.io/docs/deposits#payment-options):** Enable **Transfer Manually, Connect Wallet**, **Connect Exchange**, **Bank Transfer** and **Add Money**.
    * **Customisation:** Update badges and CTA (Call to Action) copy
  * **Notifications:** Enable email notifications to receive updates when a deposit is successfully completed.

### Payment Options

When creating a deposit, you can enable any combination of the following payment options:

* **Transfer Manually** — Displays a QR code and wallet address for the user to send funds to directly.
* **Connect Wallet** — Lets users connect their crypto wallet, reads their balance, and allows them to send funds without manually copying addresses or scanning QR codes.
* **Connect Exchange** — Lets users connect a supported centralized exchange and transfer funds directly from their exchange balance.
* **Add Money** — Enables fiat on-ramp via card, Apple Pay, or Google Pay. Requires API keys from either **MoonPay Ramps** or **Onramper** to be configured under **Settings → Integrations**.
  * For Onramper, first-time users can sign up via their unique affiliate link to have the subscription fee waived.
* **Bank Transfer** — Creates a Virtual Account on behalf of the user which allows users to fund via bank transfer (SEPA, ACH, etc.) where supported. Availability depends on the user's region.

## 2. Create a Deposit Customer

Generate a [<u>Deposit Customer</u>](https://docs.hel.io/reference/deposit-customers/create) via the API and their associated deposit addresses across SVM, EVM, and BTC networks.

* **Required Parameters:** To create a customer, you must specify a unique `customerId`, a `recipientWallet`, and any optional metadata via the `additionalJson` payload.
* **Save the token:** Store the returned Deposit Customer token. This token allows you to reuse the same deposit address for subsequent transactions from the same customer.
* **Related endpoints:** use the [<u>Update Deposit Customer</u>](https://docs.hel.io/reference/deposit-customers/update) and [<u>Get Deposit Customer</u>](https://docs.hel.io/reference/deposit-customers/retrieve) endpoints as needed.
* **Test Customer Deposit Session:** In this step you can simulate a deposit widget. You must define a `customerId` and a `recipientWallet` to generate the test environment.

## 3. Build Your Own or Serve our Deposit UI in Your App

### Headless support

* Serve deposit addresses in your own UI. Create and store the `depositCustomerToken` -> use the [<u>Get Deposit Customer</u>](https://docs.hel.io/reference/deposit-customers/retrieve) endpoint to get the `depositWallets` array
* Use [<u>Record Deposit Wallet Activity (By Token)</u>](https://docs.hel.io/reference/deposit-wallet/record-activity) when you have the customer deposit token and want all of that customer’s wallets marked active, or [<u>Record Deposit Wallet Activity (By Public Keys)</u>](https://docs.hel.io/reference/deposit-wallet/record-activity-wallets) when you display specific wallet addresses. Both increase balance polling so incoming payments are detected more quickly
* Use [<u>Get Deposit Currencies</u>](https://docs.hel.io/reference/currency/list-deposit) to check available currencies
* The [<u>Get Deposit Customer</u>](https://docs.hel.io/reference/deposit-customers/retrieve) response includes a `swapRoutes` array with all swap paths into the deposit's payout currency. Each route provides `available` (whether the swap path is currently usable) and `minAmountUsd` (the minimum deposit amount in USD for that route). **Filter out entries where `available` is `false`** so your checkout or picker only surfaces currencies with an active swap path, and use `minAmountUsd` to enforce or display minimum deposit thresholds per currency.

### Deposit Widget Setup

Embed the deposit widget in your app using the following [<u>NPM package</u>](https://www.npmjs.com/package/@heliofi/deposit-react) . The below configuration options are available for customising your deposit widget via config:

<Info>
  Use our [demo environment](https://demo.hel.io/) to test display and other configurations. Simply toggle to the Deposit view and paste the Deposit Customer token.
</Info>

`display`

Controls how the deposit flow is rendered on your page.

* **Type**: `'inline' | 'button' | 'new-tab'`
* **Default**: `'inline'`
* **Required**: No

**Values**:

* `'inline'` - Embeds the deposit flow directly in the container element
* `'button'` - Renders a button that opens the deposit flow in a modal
* `'new-tab'` - Renders a button that opens the deposit flow in a new browser tab

<Info>
  If you enable **Add Money** and use the deposit widget in **inline** or **button** mode, your domain(s) must be whitelisted by MoonPay Ramps. In some cases, this may require additional KYB. You can always use **new-tab** mode without domain whitelisting, or disable the Pay with Cash option.
</Info>

***

`network`

Specifies the environment for the deposit flow.

* **Type**: `'test' | 'main'`
* **Default**: `'main'`
* **Required**: No

**Values**:

* `'test'` - Use the test/sandbox environment for development and testing
* `'main'` - Use the production environment for live transactions

***

`themeMode`

Specifies the default light/dark mode. Alternatively you can also set a fixed Company Theme (Settings -> Merchant settings) that overrides this config.

* **Type**: `'dark' | 'light'`
* **Default**: `'undefined'`
* **Required**: No

**Values**:

* `'dark'` - The widget uses dark mode
* `'light'` -The widget uses light mode

<Info>
  If `themeMode` is **undefined** and **no Company Theme is set**, the deposit flow will automatically match the user’s system light/dark mode.
</Info>

***

`variant`

Minimal removes padding and background for inline embeds

* **Type:** `'default' | 'minimal'`
* **Default**: `default`
* Required: no

**Values:**

* `'default'` – Standard embed with padding and background
* `'minimal'` – Removes padding and background for inline embeds

***

`openWalletConnectInNewTab`

Controls whether the WalletConnect flow opens in a new browser tab.

* **Type:** boolean
* **Default:** false
* **Required:** No

**Values:**

* `true` – WalletConnect opens in a new browser tab
* `false` – WalletConnect opens in the current tab or modal

<Info>
  **Note:** For better UX, consider setting this conditionally (e.g. `openWalletConnectInNewTab={wallet.isConnected}`) so a new tab is only opened when needed.
</Info>

***

`forcedStep`

Forces the deposit flow to begin at a specific step, skipping any preceding steps in the default deposit journey.

* **Type:** 'connect-wallet' | 'wallet-display' | 'moonpay-onramp'
* **Default:** undefined
* **Required:** No

**Values:**

`'connect-wallet'` — Forces the flow to start at the **Connect Wallet** step.

`'wallet-display'` — Forces the flow to start at the **Wallet Display** step.

`'moonpay-onramp'` — Forces the flow to start directly at the **MoonPay Onramp** step.

***

`currentlyConnectedWallet`

Allows the host application to pass an already connected user wallet into the deposit flow, surfacing it as an additional selectable option.

* **Type:** ConnectWalletSelection
* **Default:** undefined
* **Required:** No

**Fields:**

* `wallet` — The connected wallet provider.
* `blockchain` — The chain the wallet address belongs to.
* `address` — The connected wallet address.

`wallet` values (DepositConnectWallet)

* `'METAMASK'`, `'PHANTOM'`, `'TRUST_WALLET'`, `'WALLET_CONNECT'`

`blockchain` values

* `'SOL'`, `'ETH'`, `'BASE'`, `'POLYGON'`, `'ARBITRUM'`, `'BSC'`, `'ABSTRACT'`, `'HYPERLIQUID'`

```javascript theme={null}
// Optional: Pre-provides a wallet that is already connected in the host application.
  currentlyConnectedWallet?: {
    wallet: string;
    blockchain: string;
    address: string;
  };
```

### Embedding the widget inside a React app

Embed the deposit widget in your React application using the [Deposit Widget on npm](https://www.npmjs.com/package/@heliofi/deposit-react).

```typescript theme={null}
import { MoonpayCommerceDeposit } from '@heliofi/deposit-react';

interface MoonpayCommerceDepositConfig {
  // Required: Your unique deposit customer token
  // Create it from https://commerce.moonpay.com
  depositCustomerToken: string;

  // Optional: Network to use
  // 'main' = Mainnet
  // 'test' = Testnet
  network?: 'test' | 'main';

  // Optional: Controls how the deposit flow is rendered on your page.
  // 'inline' = Embeds the deposit flow directly in the container element
  // 'button' = Renders a button that opens the deposit flow in a modal
  // 'new-tab' = Renders a button that opens the deposit flow in a new browser tab
  display?: 'inline' | 'button' | 'new-tab'
  
	// Optional: Theme to use
  // 'dark' = Dark mode
  // 'light' = Light mode
  themeMode?: 'dark' | 'light';
  
  // Optional: Opens WalletConnect in a new browser tab when enabled	
  // Tip: Best used conditionally (e.g. openWalletConnectInNewTab={wallet.isConnected})
	openWalletConnectInNewTab?: boolean;
  
	// Optional: Forces the deposit flow to start at a specific step
	// 'connect-wallet' = start at wallet connection
	// 'wallet-display' = start at wallet display/selection
	// 'moonpay-onramp' = start directly at MoonPay onramp
  forcedStep?: 'connect-wallet' | 'wallet-display' | 'moonpay-onramp';

  // Optional: Called when deposit completes successfully
  // Note: this might not be working in the current beta version
  onSuccess?: (data: {
    transaction?: string;
    depositCustomer?: unknown;
  }) => void;

  // Optional: Called if an error occurs
  // Note: this might not be working in the current beta version
  onError?: (error: { errorMessage?: string; transaction?: string }) => void;
}

function App() {
  return (
    <MoonpayCommerceDeposit
        config={{
    			depositCustomerToken: 'your-deposit-customer-token',
        	onSuccess: (data) => {
          	console.log('Deposit completed:', data);
        	},
        	onError: (error) => {
          	console.error('Deposit failed:', error);
        	},
      }}
    />
  );
}
```

### Optional: Preload Assets with the Provider

To improve load performance, you can optionally wrap your application with the `MoonpayCommerceDepositProvider`.

The provider preloads the required JavaScript assets ahead of time, so when `<MoonpayCommerceDeposit />` renders, it does not need to wait for the scripts to load.

**Import**

```text theme={null}
import { MoonpayCommerceDepositProvider } from "@heliofi/deposit-react";
```

**Usage (Next.js example)**

The provider takes no props and should be placed near the root of your application (e.g. `layout.tsx` or `_app.tsx`):

```text theme={null}
// layout.tsx or _app.tsx
export default function RootLayout({ children }) {
  return (
    <YourOtherProviders>
      <MoonpayCommerceDepositProvider>
        {children}
      </MoonpayCommerceDepositProvider>
    </YourOtherProviders>
  );
}
```

**Notes:**

* `children` should include the rest of your application, including any usage of `<MoonpayCommerceDeposit />`.
* This setup is optional. If you do not use the provider, assets will still load automatically when `<MoonpayCommerceDeposit />` is rendered.

**Vanilla JS**

If you are not using React.js, you can alternatively embed using the pure JS approach like below:

```html theme={null}
<script type="module" src="https://embed.deposits.hel.io/assets/index-v1.js" id="deposit-script"></script>

<div id="deposit-container"></div>

<script>
  document.getElementById('deposit-script').addEventListener('load', () => {
    window.moonpayCommerceDeposit(
      document.getElementById('deposit-container'),
      {
        depositCustomerToken: 'your-token-here',
        network: 'test',
        display: 'inline',
        onSuccess: () => {
          console.log('Deposit completed!');
        },
        onError: (error) => {
          console.error('Deposit error:', error.message);
        },
      }
    );
  });
</script>
```

**Iframe**

Alternatively you can embed an iframe using the HTML snippet below. It lets users deposit crypto or pay by card directly on your site without leaving your app.

```html theme={null}
<iframe
  allow="clipboard-write"
  style="width:420px; height:260px;"
  src="https://moonpay.hel.io/embed/deposit/acac3ec9-f8f6-4128-8159-a91e418e2581"
/>
```

Replace the token at the end of the `src` URL with your own `token` returned when creating the customer deposit via the API (e.g. `acac3ec9-f8f6-4128-8159-a91e418e2581`) to render the correct deposit widget.

**Iframe Post Message Events**

Our deposit widget emits structured postMessage events that let your application react instantly to lifecycle changes such as completion, errors, or height updates, keeping your interface responsive and in sync without requiring a page reload.

| **Event**       | **Payload**                   | **When it fires**                                                   |
| --------------- | ----------------------------- | ------------------------------------------------------------------- |
| onSuccess       | `{}` (empty object)           | Deposit flow completed and the merchant has been successfully paid. |
| onError         | `{ message: string }`         | Something went wrong                                                |
| onHeightChanged | `{ height: number } `(pixels) | The widget needs a new height (e.g. after a step change)            |
| onReady         | `{}` (empty object)           | Widget has fully initialised and is ready                           |

The snippet below illustrates how to integrate and respond to our postMessage events within a React component.

```typescript theme={null}
import { useEffect, useState } from "react";

export const Deposit = () => {
  // Dynamic height set by the deposit widget via postMessage
  const [iframeHeight, setIframeHeight] = useState(0);

  useEffect(() => {
    // Handle events sent from the deposit widget iframe
    const handleMessage = (event: MessageEvent) => {
      // Only process messages coming from the Helio/MoonPay widget
      if (event.origin !== "https://moonpay.hel.io") return;

      const data = event.data;

      switch (data.type) {
        // Widget requests the parent to resize the iframe
        case "onHeightChanged":
          setIframeHeight(data.height || 0);
          break;

        // Deposit flow completed successfully
        case "onSuccess":
          alert("Deposit completed");
          break;

        // An error occurred inside the widget
        case "onError":
          alert(`Deposit error: ${data.message}`);
          break;

        default:
          break;
      }
    };

    // Subscribe to postMessage events
    window.addEventListener("message", handleMessage);

    // Clean up on unmount
    return () => window.removeEventListener("message", handleMessage);
  }, []);

  return (
    <iframe
      allow="clipboard-write"
      className="rounded-3xl shadow-2xl"
      // Apply dynamic height returned by the widget
      style={{ width: 420, minHeight: 260, height: iframeHeight }}
      src="https://moonpay.hel.io/embed/deposit/ad1ecf2d-f535-41f8-96df-fd6a45a27cdd"
    />
  );
};
```

<Info>
  Always validate the `event.origin` before handling messages from the widget. This ensures you only process events coming from our domain and ignore anything unexpected.
</Info>

## 4. Use Webhooks to Confirm Deposits on Your Backend

Create a webhook to listen for customer deposit events either in the dashboard under Developer Settings (see [<u>here</u>](https://docs.hel.io/docs/for-developers#getting-started) for more information) or via the [<u>Create a Deposit Webhook endpoint</u>](https://docs.hel.io/reference/webhook/deposit/create). Use `DEPOSIT_TX_*` events to confirm settled deposits, and `DEPOSIT_BELOW_MINIMUM` to notify users when they have sent funds below the sweep minimum so you can prompt a top-up. Payload examples are in the [webhook overview](https://docs.hel.io/reference/webhook/overview).

## Supported Chains and Currencies

Use [**Get Deposit Currencies**](https://docs.hel.io/reference/currency/list-deposit) to check all available currencies and chains. Users can choose their preferred network and currency when making a deposit. Deposited funds are then bridged and swapped into your specified recipient currency.

You can request support for additional currencies and blockchains by contacting [commerce@moonpay.com](mailto:commerce@moonpay.com).

### Demo

<iframe src="https://www.youtube.com/embed/9w5EA0JbcBE" title="YouTube video player" frameborder="0" className="w-full aspect-video rounded-xl" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen />
