> ## 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.

# Create a deposit account

> Create a crypto deposit account from React, React Native, Node.js, or REST.

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>.
  </>;

A crypto deposit account gives a wallet persistent deposit addresses.

By default, deposit addresses belong to dedicated source wallets owned by the depositing user. Destination address reuse requires an explicit strategy.

The REST request body is a flat object discriminated by `type`:

<ParamField body="type" type="'inline_route' | 'deposit_config'" required>
  Which create payload to send. `inline_route` takes `source` and `destination`. `deposit_config`
  reuses an existing deposit configuration via `deposit_config_id`.
</ParamField>

<ParamField body="deposit_address_strategy" type="'dedicated' | 'prefer_destination' | 'require_destination'">
  Optional for both `inline_route` and `deposit_config`. Omission always selects `dedicated`,
  including for existing routes.

  * `dedicated`: Reuse or create eligible dedicated source wallets, never the destination wallet.
  * `prefer_destination`: Use the eligible destination for its matching source chain family; use dedicated wallets otherwise.
  * `require_destination`: Require the destination to serve its own chain family when that family is requested, and fail without fallback if it cannot. Other requested families still use dedicated source wallets.
</ParamField>

<ParamField body="source" type="object">
  Required when `type` is `inline_route`. Assets the deposit address accepts. Chains must be EVM or
  Solana.

  <Expandable title="properties" defaultOpen>
    <ParamField body="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="source.values" type="object[]">
      Asset specs for `include` and `exclude`. Omit when `mode` is `all`.

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

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

<ParamField body="destination" type="object">
  Required when `type` is `inline_route`. Asset delivered to the destination wallet. Identifies
  exactly one asset on exactly one chain.

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

    <ParamField body="destination.chain" type="string" required>
      <ChainIdentifier /> Must be in the same chain family as the destination wallet's `chain_type`.
      An EVM chain such as `tempo` matches an `ethereum` wallet.
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="deposit_config_id" type="string">
  Required when `type` is `deposit_config`. ID of an existing deposit configuration to attach.
</ParamField>

## Deposit address behavior

The destination must be a Privy wallet owned 1-of-1 by a single user, with no authorization keys and no nested quorums. A user token must belong to that user. Source chain families are EVM and Solana. `require_destination` uses the destination only for its own family when that family is requested; other families still use dedicated source wallets.

Exported wallets cannot act as deposit sources, including when reusing a destination address. An exported destination can still receive converted funds from dedicated source wallets.

When reusing the destination wallet, both `prefer_destination` and `require_destination` remove **all** existing automation attachments, including matching and disabled attachments, then attach the requested automation. The shared automation configurations and attachments on other wallets are unchanged. `dedicated` does not modify the destination wallet's attachments.

Repeated calls for the same route and strategy reuse eligible source wallets.

<Warning>
  Switching to `dedicated`, including by omitting the option, can change the returned deposit
  address without detaching previous routes. Explicit destination reuse can change which route the
  destination address serves by replacing all of its automation attachments. Use the latest returned
  `deposit_address` when displaying deposit instructions.
</Warning>

## Examples

<View title="REST API" icon="terminal">
  The body uses the optional `deposit_address_strategy` field for either request type, with the same strategy values and dedicated default described above. Include it in the signed body when provided. Do not add its default after signing a request that omits it.

  The field for an existing configuration is `deposit_config_id`.

  To create a crypto deposit account for a wallet, make a `POST` request to:

  ```bash theme={"system"}
  https://api.privy.io/v1/wallets/{wallet_id}/deposit_accounts/crypto
  ```

  Below is a sample cURL command for this request:

  ```bash theme={"system"}
  curl --request POST https://api.privy.io/v1/wallets/{wallet_id}/deposit_accounts/crypto \
    -u "<your-privy-app-id>:<your-privy-app-secret>" \
    -H "privy-app-id: <your-privy-app-id>" \
    -H "privy-authorization-signature: <dest-owner-signature>" \
    -H "Content-Type: application/json" \
    -d '{
      "type": "inline_route",
      "deposit_address_strategy": "prefer_destination",
      "source": {
        "mode": "include",
        "values": [{"asset": "usdc", "chain": "base"}]
      },
      "destination": {
        "asset": "pathusd",
        "chain": "tempo"
      }
    }'
  ```

  ```json theme={"system"}
  {
    "type": "deposit_config",
    "deposit_config_id": "<deposit-config-id>",
    "deposit_address_strategy": "prefer_destination"
  }
  ```
</View>

<View title="React" icon="react">
  Use `createCryptoDepositAccount` from `useHeadlessCryptoDeposit`. The hook uses the optional `depositAddressStrategy` field for either request type, with the same strategy values and dedicated default described above. The hook signs the dest-owner request with the authenticated user's signer.

  <Warning>
    `useHeadlessCryptoDeposit` is experimental. Import it from `@privy-io/react-auth`. The interface
    may change without a major SDK version bump.
  </Warning>

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

  const {createCryptoDepositAccount} = useHeadlessCryptoDeposit();

  const {deposit_accounts} = await createCryptoDepositAccount({
    walletId: '<wallet-id>',
    type: 'inline_route',
    depositAddressStrategy: 'prefer_destination',
    source: {
      mode: 'include',
      values: [{asset: 'usdc', chain: 'base'}]
    },
    destination: {asset: 'pathusd', chain: 'tempo'}
  });
  ```

  The hook param for an existing configuration is `depositConfigId`.

  ```tsx {skip-check} theme={"system"}
  const {deposit_accounts} = await createCryptoDepositAccount({
    walletId: '<wallet-id>',
    type: 'deposit_config',
    depositConfigId: '<deposit-config-id>',
    depositAddressStrategy: 'prefer_destination'
  });
  ```
</View>

<View title="React Native" icon="react">
  Use `createCryptoDepositAccount` from `useHeadlessCryptoDeposit`. The hook uses the optional `depositAddressStrategy` field for either request type, with the same strategy values and dedicated default described above. The hook signs the dest-owner request with the authenticated user's signer.

  <Warning>
    `useHeadlessCryptoDeposit` is experimental. Import it from `@privy-io/expo`. The interface may
    change without a major SDK version bump.
  </Warning>

  ```tsx {skip-check} theme={"system"}
  import {useHeadlessCryptoDeposit} from '@privy-io/expo';

  const {createCryptoDepositAccount} = useHeadlessCryptoDeposit();

  const {deposit_accounts} = await createCryptoDepositAccount({
    walletId: '<wallet-id>',
    type: 'inline_route',
    depositAddressStrategy: 'prefer_destination',
    source: {
      mode: 'include',
      values: [{asset: 'usdc', chain: 'base'}]
    },
    destination: {asset: 'pathusd', chain: 'tempo'}
  });
  ```

  The hook param for an existing configuration is `depositConfigId`.

  ```tsx {skip-check} theme={"system"}
  const {deposit_accounts} = await createCryptoDepositAccount({
    walletId: '<wallet-id>',
    type: 'deposit_config',
    depositConfigId: '<deposit-config-id>',
    depositAddressStrategy: 'prefer_destination'
  });
  ```
</View>

<View title="NodeJS" icon="node-js">
  The client uses the optional `deposit_address_strategy` field for either request type, with the same strategy values and dedicated default described above. Include it in the signed body when provided. Do not add its default after signing a request that omits it.

  The field for an existing configuration is `deposit_config_id`.

  ```ts {skip-check} theme={"system"}
  import {PrivyClient} from '@privy-io/node';

  const userJwt = 'insert-user-jwt';
  const walletId = 'insert-wallet-id';

  const privy = new PrivyClient({
    appId: 'insert-your-app-id',
    appSecret: 'insert-your-app-secret'
  });

  const {deposit_accounts} = await privy.wallets().depositAccounts.crypto.create(walletId, {
    type: 'inline_route',
    deposit_address_strategy: 'prefer_destination',
    source: {
      mode: 'include',
      values: [{asset: 'usdc', chain: 'base'}]
    },
    destination: {asset: 'pathusd', chain: 'tempo'},
    authorization_context: {user_jwts: [userJwt]}
  });
  ```

  ```ts {skip-check} theme={"system"}
  const {deposit_accounts} = await privy.wallets().depositAccounts.crypto.create(walletId, {
    type: 'deposit_config',
    deposit_config_id: '<deposit-config-id>',
    deposit_address_strategy: 'prefer_destination',
    authorization_context: {user_jwts: [userJwt]}
  });
  ```
</View>

## Response

A successful response includes the following fields:

<ResponseField name="deposit_accounts" type="object[]">
  One entry per source route created for the destination wallet.

  <Expandable title="properties" defaultOpen>
    <ResponseField name="deposit_address" type="string">
      Address to send funds to. The selected strategy determines whether this belongs to a dedicated
      source wallet or the destination wallet.
    </ResponseField>

    <ResponseField name="wallet_id" type="string">
      ID of the source wallet behind this deposit address.
    </ResponseField>

    <ResponseField name="source" type="object">
      Assets this address accepts, using aliases when known.

      <Expandable title="properties" defaultOpen>
        <ResponseField name="source.mode" type="'all' | 'include' | 'exclude'">
          Filter applied to this deposit address.
        </ResponseField>

        <ResponseField name="source.values" type="object[]">
          Accepted assets.

          <Expandable title="properties" defaultOpen>
            <ResponseField name="source.values.asset" type="string">
              <AssetIdentifier />
            </ResponseField>

            <ResponseField name="source.values.chain" type="string">
              <ChainIdentifier />
            </ResponseField>
          </Expandable>
        </ResponseField>
      </Expandable>
    </ResponseField>

    <ResponseField name="destination" type="object">
      Asset and chain delivered to the destination wallet, using aliases when known.

      <Expandable title="properties" defaultOpen>
        <ResponseField name="destination.asset" type="string">
          <AssetIdentifier />
        </ResponseField>

        <ResponseField name="destination.chain" type="string">
          <ChainIdentifier />
        </ResponseField>
      </Expandable>
    </ResponseField>
  </Expandable>
</ResponseField>

```json theme={"system"}
{
  "deposit_accounts": [
    {
      "wallet_id": "insert-source-wallet-id",
      "deposit_address": "0x1234...abcd",
      "source": {
        "mode": "include",
        "values": [{"asset": "usdc", "chain": "base"}]
      },
      "destination": {"asset": "pathusd", "chain": "tempo"}
    }
  ]
}
```

## Error handling

Create rejects on invalid configuration or failed requests. Common error cases include:

* the user is not authenticated
* the dest-owner request expires before it is sent
* swaps or app-pays gas sponsorship are not enabled for the source chain
* the route is unsupported
* `require_destination` is set and the destination cannot serve its own chain family when that family is requested

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

<View title="React" icon="react">
  ## Complete example

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

  export const CryptoDepositPanel = ({walletId}: {walletId: string}) => {
    const {createCryptoDepositAccount} = useHeadlessCryptoDeposit();
    const [depositAddress, setDepositAddress] = useState<string | null>(null);
    const [isLoading, setIsLoading] = useState(false);

    const onCreate = async () => {
      setIsLoading(true);
      try {
        const {deposit_accounts} = await createCryptoDepositAccount({
          walletId,
          type: 'inline_route',
          source: {
            mode: 'include',
            values: [{asset: 'usdc', chain: 'base'}]
          },
          destination: {asset: 'pathusd', chain: 'tempo'}
        });

        setDepositAddress(deposit_accounts[0]?.deposit_address ?? null);
      } catch (error) {
        console.error(error);
      } finally {
        setIsLoading(false);
      }
    };

    return (
      <div>
        <button type="button" onClick={onCreate} disabled={isLoading}>
          {isLoading ? 'Creating...' : 'Get deposit address'}
        </button>
        {depositAddress && (
          <p>
            Send USDC on Base to <code>{depositAddress}</code>
          </p>
        )}
      </div>
    );
  };
  ```
</View>

<View title="React Native" icon="react">
  ## Complete example

  ```tsx {skip-check} theme={"system"}
  import {useState} from 'react';
  import {View, Text, Pressable} from 'react-native';
  import {useHeadlessCryptoDeposit} from '@privy-io/expo';

  export const CryptoDepositPanel = ({walletId}: {walletId: string}) => {
    const {createCryptoDepositAccount} = useHeadlessCryptoDeposit();
    const [depositAddress, setDepositAddress] = useState<string | null>(null);
    const [isLoading, setIsLoading] = useState(false);

    const onCreate = async () => {
      setIsLoading(true);
      try {
        const {deposit_accounts} = await createCryptoDepositAccount({
          walletId,
          type: 'inline_route',
          source: {
            mode: 'include',
            values: [{asset: 'usdc', chain: 'base'}]
          },
          destination: {asset: 'pathusd', chain: 'tempo'}
        });

        setDepositAddress(deposit_accounts[0]?.deposit_address ?? null);
      } catch (error) {
        console.error(error);
      } finally {
        setIsLoading(false);
      }
    };

    return (
      <View>
        <Pressable onPress={onCreate} disabled={isLoading}>
          <Text>{isLoading ? 'Creating...' : 'Get deposit address'}</Text>
        </Pressable>
        {depositAddress && <Text>Send USDC on Base to {depositAddress}</Text>}
      </View>
    );
  };
  ```
</View>

## Next steps

<CardGroup cols={2}>
  <Card title="Deposit modal" icon="window-restore" href="/wallets/funding/use-deposit-funds">
    `useDepositFunds` for the prebuilt deposit UI
  </Card>

  <Card title="Setup" icon="gear" href="/wallets/funding/crypto-deposits/setup">
    Enable swaps and app-pays gas sponsorship
  </Card>

  <Card title="Quotes" icon="calculator" href="/wallets/funding/crypto-deposits/quotes">
    Indicative route quotes before creating an address
  </Card>

  <Card title="Orders" icon="arrows-rotate" href="/wallets/funding/crypto-deposits/orders">
    Poll sweep status after a deposit is sent
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.