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

# Deposit modal

> Use the useDepositFunds hook from @privy-io/react-auth to let users fund wallets with fiat or crypto

export const ChainIdentifier = () => <>
    Chain alias or CAIP-2 identifier, such as <code>base</code> or <code>eip155:8453</code>.
  </>;

export const AssetIdentifier = () => <>
    Asset alias or token contract address, such as <code>usdc</code> or{' '}
    <code>0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913</code>.
  </>;

Privy provides a `useDepositFunds` hook in `@privy-io/react-auth` that opens a funding modal.

Your app can use this hook to let authenticated users fund a destination wallet with fiat, crypto, or both. A crypto-only call opens the crypto deposit flow directly. A call that includes fiat shows a method picker first.

## Prerequisites

For fiat, enable card and bank funding methods on the [Account Funding](https://dashboard.privy.io/apps?page=funding) page. See the [deposit configuration guide](/financial-flows/deposits/configuration).

For crypto, enable swaps and app-pays gas sponsorship as described in [crypto deposit setup](/wallets/funding/crypto-deposits/setup). Crypto deposits require a Privy wallet. The hook builds the [create-deposit-account](/wallets/funding/crypto-deposits/create-deposit-account) request and signs it with the user's signer.

## Access the hook

Import and initialize `useDepositFunds`:

```tsx {skip-check} theme={"system"}
import {useDepositFunds} from '@privy-io/react-auth';

const {depositFunds} = useDepositFunds();
```

## Start a deposit flow

Call `depositFunds` with a destination and at least one funding method.

```tsx {skip-check} theme={"system"}
await depositFunds({
  destination: {
    asset: 'pathusd',
    chain: 'tempo'
  },
  crypto: {
    source: {
      mode: 'all'
    }
  }
});
```

The crypto-only call opens the crypto deposit modal. The user picks a source token and network. Privy then creates a [deposit account](/wallets/funding/crypto-deposits/create-deposit-account) and shows the address with an indicative quote.

<Note>
  `destination.chain` and `destination.asset` accept aliases or raw identifiers. Omit
  `destination.wallet` to use the user's first embedded wallet on that chain.
</Note>

Pass both `fiat` and `crypto` to show a method picker:

```tsx {skip-check} theme={"system"}
await depositFunds({
  destination: {
    asset: 'usdc',
    chain: 'tempo'
  },
  fiat: {
    source: {
      assets: ['usd', 'eur'],
      defaultAsset: 'usd'
    },
    environment: 'production',
    defaultAmount: '50'
  },
  crypto: {
    source: {
      mode: 'all'
    }
  }
});
```

## Parameters

`depositFunds` accepts an object with the following fields:

<ParamField body="destination" type="object" required>
  Wallet and asset that receive the funds.

  <Expandable title="properties" defaultOpen>
    <ParamField body="destination.asset" type="string" required>
      <AssetIdentifier />
    </ParamField>

    <ParamField body="destination.chain" type="string" required>
      <ChainIdentifier /> Must match the destination wallet's `chain_type` for crypto deposits.
    </ParamField>

    <ParamField body="destination.wallet" type="string">
      Privy wallet ID or linked wallet address. When omitted, Privy uses the user's first embedded
      wallet on `destination.chain`. Crypto deposits require a Privy wallet. Fiat needs a resolvable
      address.
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="crypto" type="object">
  Enables the crypto deposit flow. Required unless `fiat` is provided. Pass `{source: {mode:
      'all'}}` to accept every supported source.

  <Expandable title="properties" defaultOpen>
    <ParamField body="crypto.source" type="object">
      Assets the modal lets the user send. Defaults to `{mode: 'all'}`.

      <Expandable title="properties" defaultOpen>
        <ParamField body="crypto.source.mode" type="'all' | 'include' | 'exclude'" required>
          `include` accepts only the listed assets. `exclude` accepts all except the listed assets.
          `all` accepts every supported source.
        </ParamField>

        <ParamField body="crypto.source.values" type="object[]">
          Asset specs for `include` and `exclude`. Omit when `mode` is `all`.

          <Expandable title="properties" defaultOpen>
            <ParamField body="crypto.source.values.asset" type="string">
              <AssetIdentifier />
            </ParamField>

            <ParamField body="crypto.source.values.chain" type="string">
              <ChainIdentifier /> Omit to match every supported chain for that asset.
            </ParamField>
          </Expandable>
        </ParamField>
      </Expandable>
    </ParamField>

    <ParamField body="crypto.slippageBps" type="number">
      Maximum slippage tolerance for the deposit route, in basis points. If omitted, Privy uses the
      default for the route.
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="fiat" type="object">
  Enables fiat funding with the card and bank onramp flow. Required unless `crypto` is provided.

  <Expandable title="properties" defaultOpen>
    <ParamField body="fiat.source.assets" type="SupportedFiatCurrency[]">
      Fiat source currencies your app allows. Defaults to all supported currencies. When provided,
      must be non-empty.
    </ParamField>

    <ParamField body="fiat.source.defaultAsset" type="SupportedFiatCurrency">
      Source currency selected when the flow opens. Falls back to the locale currency, then to the
      first item in `fiat.source.assets`.
    </ParamField>

    <ParamField body="fiat.environment" type="'sandbox' | 'production'">
      Onramp environment for provider APIs.
    </ParamField>

    <ParamField body="fiat.defaultAmount" type="string">
      Initial fiat amount displayed in the amount step.
    </ParamField>
  </Expandable>
</ParamField>

At least one of `fiat` or `crypto` must be provided.

## Return value

`depositFunds` returns a Promise with one of the following results:

| Result                                        | Meaning                                                                               |
| --------------------------------------------- | ------------------------------------------------------------------------------------- |
| `{method: 'fiat', status: 'submitted'}`       | The user completed the provider flow, then exited before Privy finished confirmation. |
| `{method: 'fiat', status: 'confirmed'}`       | The fiat flow reached provider confirmation, and the user completed the success step. |
| `{method: 'crypto', status: 'address_shown'}` | The user viewed the crypto deposit address and closed the modal.                      |
| `{method: 'crypto', status: 'completed'}`     | Privy detected the crypto deposit and finished the flow.                              |

## Error handling

`depositFunds` rejects on invalid configuration or incomplete flows. Common error cases include:

* the call omits `destination.chain` or `destination.asset`
* the call omits both `fiat` and `crypto`
* the call sends an empty `fiat.source.assets` list
* the user has no authenticated session
* `destination.wallet` is not a Privy wallet on a crypto call
* another funding flow is already in progress
* the user cancels the flow
* swaps or app-pays gas sponsorship are not enabled
* no source tokens match `crypto.source`
* provider session, quote, or deposit account requests fail

Your app should wrap calls in `try/catch` and show clear UI feedback.

## Complete example

```tsx {skip-check} theme={"system"}
import {useState} from 'react';
import {useDepositFunds} from '@privy-io/react-auth';

export const DepositFundsButton = ({walletId}: {walletId: string}) => {
  const {depositFunds} = useDepositFunds();
  const [isLoading, setIsLoading] = useState(false);

  const onDepositFunds = async () => {
    setIsLoading(true);

    try {
      const result = await depositFunds({
        destination: {
          wallet: walletId,
          asset: 'usdc',
          chain: 'tempo'
        },
        fiat: {
          source: {
            assets: ['usd', 'eur', 'gbp'],
            defaultAsset: 'usd'
          },
          environment: 'production',
          defaultAmount: '50'
        },
        crypto: {
          source: {
            mode: 'all'
          }
        }
      });

      if (result.method === 'fiat') {
        // Handle submitted or confirmed fiat purchases.
      }

      if (result.method === 'crypto') {
        // Handle address_shown or completed crypto deposits.
      }
    } catch (error) {
      // Show retry UI or an error banner.
      console.error(error);
    } finally {
      setIsLoading(false);
    }
  };

  return (
    <button type="button" onClick={onDepositFunds} disabled={isLoading}>
      {isLoading ? 'Starting funding…' : 'Add funds'}
    </button>
  );
};
```

## Related

<CardGroup cols={2}>
  <Card title="Card onramps" icon="credit-card" href="/wallets/funding/fiat-onramp">
    Fund wallets with fiat via card, Apple Pay, or Google Pay.
  </Card>

  <Card title="Crypto deposits" icon="arrow-right-to-bracket" href="/wallets/funding/crypto-deposits/overview">
    Persistent deposit addresses, setup, and headless React or React Native.
  </Card>
</CardGroup>
