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

# Create Omnibus Structure

In an omnibus setup, three vault types work together:

* **Intermediate vault accounts**: Assigned per end-client for deposits. Use the Fireblocks API to generate as many as needed.
* **Omnibus deposits**: The central vault where end-client funds are swept and stored.
* **Withdrawal pool**: Vault accounts containing funds allocated for end-client withdrawals. More than one may be required due to blockchain limitations.

Follow the right structure for your use case in the [Create Direct Custody Wallets](/docs/create-direct-custody-wallets) article.

## Understanding Asset Types

Handling your omnibus account correctly requires a clear understanding of the differences between UTXO and account-based assets.

Due to the nature of UTXO-based blockchains, a transaction includes the source address for each end client, unlike account-based transactions which require an intermediary vault account per client.

## UTXO Based

### Structure

* In the Omnibus Deposits vault account, you can assign each end client a deposit address (derived from the permanent wallet address of the UTXO asset).
* When adding an address for an end client in the Omnibus Deposits vault account, use the [Create a New Deposit Address of an Asset in a Vault Account](/reference/createvaultaccountassetaddress) endpoint and use the `description` field in `createAddressRequest` to associate the end client's ID.

  The `customerRefId` parameter is the ID for AML providers to associate the owner of funds with transactions. Both the name of the vault account and the AML `customerRefId` fields are propagated to every transaction.

### Deposit

Funds are deposited using the following process:

* The retail platform shares the deposit address with the end client.
* The end client makes a deposit.
* The incoming deposit triggers a webhook notification.
* Your client-facing software automatically notifies the end client that the deposit was received.
* The deposit appears on the Transaction History page.

### Example

<CodeGroup>
  ```typescript TypeScript theme={"system"}
  const createUTXOWithdrawalVaultAccounts = async (
    assetId: string,
    name: string,
  ): Promise<Array<{}> | undefined> => {
    const result: Array<{}> = [];

    try {
      const vaultAccount = await fireblocks.vaults.createVaultAccount({
        createVaultAccountRequest: {
          name,
        },
      });

      if (vaultAccount.data) {
        const vaultWallet = await fireblocks.vaults.createVaultAccountAsset({
          vaultAccountId: vaultAccount.data.id as string,
          assetId,
        });

        result.push({
          "Vault Account Name": vaultAccount.data.name,
          "Vault Account ID": vaultAccount.data.id,
          "Asset ID": assetId,
          Address: vaultWallet.data.address,
        });

        console.log(JSON.stringify(result, null, 2));
      }

      return result;
    } catch (error) {
      console.error(error);
    }
  };

  // Create an omnibus vault account for UTXO based assets
  const createOmnibusUTXOAccount = async (
    numOfAddresses: number,
    assetId: string,
  ): Promise<{} | undefined> => {
    try {
      const myOmnibusVault = await fireblocks.vaults.createVaultAccount({
        createVaultAccountRequest: {
          name: "My Omnibus Vault",
        },
      });

      if (myOmnibusVault.data) {
        const vaultAccountId = myOmnibusVault.data.id as string;

        let result = {};

        await fireblocks.vaults.createVaultAccountAsset({
          vaultAccountId,
          assetId,
        });

        for (let i = 0; i < numOfAddresses; i++) {
          // Generating additional addresses is possible for UTXO based assets only
          await fireblocks.vaults.createVaultAccountAssetAddress({
            assetId,
            vaultAccountId,
            createAddressRequest: {
              description: `UserAddress${i + 1}`,
            },
          });
        }

        const addresses =
          await fireblocks.vaults.getVaultAccountAssetAddressesPaginated({
            vaultAccountId,
            assetId,
          });

        result = {
          "Vault Account Name": myOmnibusVault.data.name,
          "VaultAccount ID": myOmnibusVault.data.id,
          "Asset ID": assetId,
          Addresses: addresses?.data.addresses,
        };

        console.log(JSON.stringify(result, null, 2));

        return result;
      }
    } catch (error) {
      console.error(error);
    }
  };
  createUTXOWithdrawalVaultAccounts("BTC_TEST", "MyWithdrawalVault");
  createOmnibusUTXOAccount(3, "BTC_TEST");
  ```

  ```javascript JavaScript theme={"system"}
  // Obtain a list of user identifiers associated with the vault accounts and pass them as strings inside internalCustRefIds
  // each of the internalCustRefIds is concatenated to the vault's name

  const internalCustRefIds = ["a","b","c"];
  const assetId = "BTC_TEST";

  async function createUTXOWithdrawalVaultAccounts(assetId, name){
      vault = await fireblocks.createVaultAccount(name);
      vaultWallet = await fireblocks.createVaultAsset(Number(vault.id), assetId);
      const result = [{"Vault Name": vault.name, "Vault ID": vault.id, "Asset ID": assetId, "Wallet Address": vaultWallet.address}];
      console.log(JSON.stringify(result, null, 2));
      return(result);
  }

  async function createUTXOOmnibusAccount(amountOfVaultAccounts, assetId, internalCustRefIds){
      let vault;
      let vaultWallet;
      let address = [];

      vault = await fireblocks.createVaultAccount("Omnibus");
      vaultWallet = await fireblocks.createVaultAsset(Number(vault.id), assetId);
      for (let i = 0; i < amountOfVaultAccounts; i++){
          address[i] = await fireblocks.generateNewAddress(Number(vault.id), assetId, "CustomerID_"+internalCustRefIds[i]+"_vault");
      }
      console.log("Created vault account:"+JSON.stringify(vault, null, 2)+" with wallet addresses:"+JSON.stringify(address, null, 2));
      return("Omnibus:", vault, "Addresses:", address);
   }

  createUTXOWithdrawalVaultAccounts(assetId, "Withdrawal");
  createUTXOOmnibusAccount(2, assetId, internalCustRefIds);
  ```

  ```python Python theme={"system"}
  # Obtain a list of user identifiers associated with the vault accounts and pass them as strings inside internalCustRefIds
  # each of the internalCustRefIds is concatenated to the vault's name

  ASSET = "BTC_TEST"
  CUSTOMER_IDS = ["a", "b", "c"]

  def create_utxo_withdrawal_vault(asset: str, name: str):
      vault_id = fireblocks.create_vault_account(name=name)["id"]
      address = fireblocks.create_vault_asset(vault_account_id=vault_id, asset_id=asset)["address"]

      return {name: vault_id}, address

  def create_utxo_omnibus_vault(amount: int, asset: str, customer_ids: list, hidden_on_ui: bool = True):
      deposit_address = {}

      vault_id = fireblocks.create_vault_account(name="Omnibus")["id"]
      fireblocks.create_vault_asset(vault_account_id=vault_id, asset_id=asset)
      for i in range(amount):
          address = fireblocks.generate_new_address(vault_account_id=vault_id, asset_id=asset, description=customer_ids[i], hidden_on_ui=hidden_on_ui)["address"]
          deposit_address[customer_ids[i]] = address

      return {"Omnibus": vault_id, "Addresses": deposit_address}

  print(create_utxo_withdrawal_vault(ASSET, "Withdrawal"))
  print(create_utxo_omnibus_vault(3, ASSET, CUSTOMER_IDS))
  ```
</CodeGroup>

This creates an omnibus vault and a withdrawal vault, then generates a deposit address per end user using a unique customer ID. The function returns a dictionary of the newly created vaults and generated deposit addresses.

## Account Based

This section covers account-based assets without a tag or memo. For tag/memo-based assets, see [Tag / Memo Based](#tag--memo-based).

### Structure

* The workspace should contain one or more intermediate vault accounts per end client, plus a single Omnibus Deposits vault account.

* When adding a vault account, use the [Create a New Vault Account](/reference/createvaultaccount) endpoint and use the `name` parameter to associate the end client's ID as a prefix or suffix.

  The `customerRefId` parameter is the ID for AML providers to associate the owner of funds with transactions. Both the name of the vault account and the AML `customerRefId` fields are propagated to every transaction.

* Due to the nature of account-based blockchains, transactions can only be transferred from one account-based address to another sequentially, unlike UTXO where multiple addresses are included in a single transaction.

### Deposit

Funds are deposited using the following process:

* The end client receives a deposit address.
* The end client makes a deposit.
* The incoming deposit triggers a webhook notification.
* Your client-facing software automatically notifies the end client that the deposit was received.
* The deposit is swept to the Omnibus Deposits vault account. See [Sweeping within an Omnibus Vault structure](/docs/sweep-funds) for the sweeping logic.

### Example

<Tip>
  **Recommended: Set `hiddenOnUI: true` for end-user vaults**

  When creating end-user vault accounts, set `hiddenOnUI: true` in the `createVaultAccount` request. By default it is `false`, which means all vaults will appear in the Console — not recommended at scale.

  Transfers to hidden vaults are only visible programmatically, not in the Console UI.
</Tip>

The example below creates:

1. 5 intermediate vault accounts for 5 end users.
2. 1 treasury vault.
3. 3 withdrawal vaults to distribute settlement load.

<CodeGroup>
  ```typescript TypeScript theme={"system"}
  const createAccountBasedVaultAccounts = async (
    vaultAccountNamePrefix: string,
    numOfVaultAccounts: number,
    assetId: string,
    hiddenOnUI: boolean,
    endUserReferences?: string[],
  ): Promise<Array<{}> | undefined> => {
    try {
      let vaultAccount: FireblocksResponse<VaultAccount>;
      let results: Array<{}> = [];

      for (let i = 0; i < numOfVaultAccounts; i++) {
        if (
          endUserReferences &&
          endUserReferences.length !== numOfVaultAccounts
        ) {
          throw new Error(
            "Number of Vault Accounts does not equal to the number of end user references",
          );
        }

        vaultAccount = await fireblocks.vaults.createVaultAccount({
          createVaultAccountRequest: {
            name: endUserReferences
              ? vaultAccountNamePrefix + "_" + endUserReferences[i]
              : vaultAccountNamePrefix + "_Vault" + String(i + 1),
            hiddenOnUI,
          },
        });

        const vaultAccountId = vaultAccount.data?.id as string;

        const vaultWallet = await fireblocks.vaults.createVaultAccountAsset({
          assetId,
          vaultAccountId,
        });

        const singleVaultResult = {
          "Vault Account": vaultAccount.data?.name,
          "Vault Account ID": vaultAccountId,
          "Asset ID": assetId,
          Address: vaultWallet.data?.address,
        };

        results.push(singleVaultResult);
        console.log(
          `Created Vault Account:\n ${JSON.stringify(singleVaultResult, null, 2)}`,
        );
      }

      return results;
    } catch (error) {
      console.error(error);
    }
  };

  createAccountBasedVaultAccounts("Deposits", 5, "ETH_TEST5", true, [
    "UserA",
    "UserB",
    "UserC",
    "UserD",
    "UserE",
  ]);
  createAccountBasedVaultAccounts("Treasury", 1, "ETH_TEST5", false);
  createAccountBasedVaultAccounts("Withdrawal_Pool", 3, "ETH_TEST5", false);
  ```

  ```javascript JavaScript theme={"system"}
  // Obtain a list of user identifiers associated with the vault accounts and pass them as strings inside internalCustRefIds
  // each of the internalCustRefIds is concatenated to the vault's name

  const internalCustRefIds = ["a","b","c","d","e"];
  const assetId = "ETH_TEST3";

  async function createAccountBasedVaultAccounts(vaultAccountNamePrefix, amountOfVaultAccounts, assetId, hiddenOnUI, internalCustRefIds){
      let createVaultRes;
      let vault;
      let vaultWallet;

      for (let i = 0; i < amountOfVaultAccounts; i++){
          if (internalCustRefIds){
              createVaultRes = await fireblocks.createVaultAccount(vaultAccountNamePrefix.toString()+"_"+internalCustRefIds[i]+"_vault", hiddenOnUI);
          }
          else {
              createVaultRes = await fireblocks.createVaultAccount(vaultAccountNamePrefix.toString()+"_"+i.toString()+"_vault", hiddenOnUI);
          }
          vault = {
              vaultName: createVaultRes.name,
              vaultID: createVaultRes.id
          }
          vaultWallet = await fireblocks.createVaultAsset(Number(vault.vaultID), assetId);
          console.log("Created vault account", vault.vaultName,":", "with wallet address:", vaultWallet.address);
      }
   }

  createAccountBasedVaultAccounts("Deposits_End_User", 5, assetId, false, internalCustRefIds);
  createAccountBasedVaultAccounts("Treasury", 1, assetId, false, undefined);
  createAccountBasedVaultAccounts("Withdrawal_pool", 3, assetId, false, undefined);
  ```

  ```python Python theme={"system"}
  # Obtain a list of user identifiers associated with the vault accounts and pass them as strings inside internalCustRefIds
  # each of the internalCustRefIds is concatenated to the vault's name

  CUSTOMER_IDS = ["a", "b", "c", "d", "e"]
  ASSET = "ETH_TEST3"

  def create_account_vault_accounts(prefix: str, amount: int, asset_id: str, customer_ids: list, is_hidden: bool = False) -> dict:
    vault_dict = {}

    for index in range(amount):
      if customer_ids:
  	    vault_name = f"{prefix}_{customer_ids[index]}_vault"
      else:
        vault_name = f"{prefix}_vault"
      vault_id = fireblocks.create_vault_account(name=vault_name, hidden_on_ui=is_hidden)["id"]
      fireblocks.create_vault_asset(vault_id, )
      vault_dict[vault_name] = vault_id

    return vault_dict

  print(create_account_vault_accounts("End-User", 5, ASSET, CUSTOMER_IDS, True))
  print(create_account_vault_accounts("Treasury", 1, ASSET))
  print(create_account_vault_accounts("Withdrawal", 3, ASSET))
  ```
</CodeGroup>

The function accepts a name prefix, account count, and optionally `internalCustRefIds` and `hiddenOnUI`. It runs three times: once for end-user vaults, once for the treasury vault, and once for withdrawal vaults.

## Tag / Memo Based

Tag and memo-based assets share a single wallet address per omnibus vault, with a unique tag or memo identifying each end client. The tag/memo name varies by blockchain.

### Structure

* In the Omnibus Deposits vault account, you can assign each end client a tag or memo.
* When adding an address for an end client in the Omnibus Deposits vault account, use the [Create a New Deposit Address of an Asset in a Vault Account](/reference/createvaultaccountassetaddress) endpoint and use the `description` field in `createAddressRequest` to associate the end client's ID.

  The `customerRefId` parameter is the ID for AML providers to associate the owner of funds with transactions. Both the name of the vault account and the AML `customerRefId` fields are propagated to every transaction.

### Deposit

Funds are deposited using the following process:

* The end client receives a deposit address and a tag or memo.
* The end client makes a deposit using both the address and the tag.
* The incoming deposit triggers a webhook notification.
* Your client-facing software automatically notifies the end client that the deposit was received, provided they included the tag or memo.
* All funds are held in the same vault account; different customer balances are tracked in your internal ledger.

### Example

<CodeGroup>
  ```typescript TypeScript theme={"system"}
  const createTagWithdrawalVaultAccounts = async (
    assetId: string,
    name: string,
  ): Promise<Array<{}> | undefined> => {
    const result: Array<{}> = [];

    try {
      const vaultAccount = await fireblocks.vaults.createVaultAccount({
        createVaultAccountRequest: {
          name,
        },
      });

      if (vaultAccount.data) {
        const vaultWallet = await fireblocks.vaults.createVaultAccountAsset({
          vaultAccountId: vaultAccount.data.id as string,
          assetId,
        });

        result.push({
          "Vault Account Name": vaultAccount.data.name,
          "Vault Account ID": vaultAccount.data.id,
          "Asset ID": assetId,
          Address: vaultWallet.data.address,
        });

        console.log(JSON.stringify(result, null, 2));
      }

      return result;
    } catch (error) {
      console.error(error);
    }
  };

  // Create an omnibus vault account for Tag/Memo based assets
  const createTagOmnibusAccount = async (
    numOfAddresses: number,
    assetId: string,
  ): Promise<{} | undefined> => {
    try {
      const myOmnibusVault = await fireblocks.vaults.createVaultAccount({
        createVaultAccountRequest: {
          name: "My Omnibus Vault",
        },
      });

      if (myOmnibusVault.data) {
        const vaultAccountId = myOmnibusVault.data.id as string;

        let result = {};

        await fireblocks.vaults.createVaultAccountAsset({
          vaultAccountId,
          assetId,
        });

        for (let i = 0; i < numOfAddresses; i++) {
          // For Tag/Memo based assets, the address of the wallet is always the same but a new Memo/Tag is generated upon each user
          await fireblocks.vaults.createVaultAccountAssetAddress({
            assetId,
            vaultAccountId,
            createAddressRequest: {
              description: `UserAddress${i + 1}`,
            },
          });
        }

        const addresses =
          await fireblocks.vaults.getVaultAccountAssetAddressesPaginated({
            vaultAccountId,
            assetId,
          });

        result = {
          "Vault Account Name": myOmnibusVault.data.name,
          "VaultAccount ID": myOmnibusVault.data.id,
          "Asset ID": assetId,
          Addresses: addresses?.data.addresses,
        };

        console.log(JSON.stringify(result, null, 2));

        return result;
      }
    } catch (error) {
      console.error(error);
    }
  };

  createTagWithdrawalVaultAccounts("XLM_TEST", "Withdrawal");
  createTagOmnibusAccount(2, "XLM_TEST");
  ```

  ```javascript JavaScript theme={"system"}
  // Obtain a list of user identifiers associated with the vault accounts and pass them as strings inside internalCustRefIds
  // each of the internalCustRefIds is concatenated to the vault's name

  const internalCustRefIds = ["a","b","c"];
  const assetId = "XLM_TEST";

  async function createTagWithdrawalVaultAccounts(assetId, name){
      vault = await fireblocks.createVaultAccount(name);
      vaultWallet = await fireblocks.createVaultAsset(Number(vault.id), assetId);
      const result = [{"Vault Name": vault.name, "Vault ID": vault.id, "Asset ID": assetId, "Wallet Address": vaultWallet.address}];
      console.log(JSON.stringify(result, null, 2));
      return(result);
  }

  async function createTagOmnibusAccount(amountOfVaultAccounts, assetId, internalCustRefIds){
      let vault;
      let vaultWallet;
      let tag = [];

      vault = await fireblocks.createVaultAccount("Omnibus");
      vaultWallet = await fireblocks.createVaultAsset(Number(vault.id), assetId);
      for (let i = 0; i < amountOfVaultAccounts; i++){
          tag[i] = await fireblocks.generateNewAddress(Number(vault.id), assetId, "CustomerID_"+internalCustRefIds[i]+"_vault");
      }
      console.log("Created vault account:"+JSON.stringify(vault, null, 2)+" with wallet tag:"+JSON.stringify(tag, null, 2));
      return("Omnibus:", vault, "Tags:", tag);
   }

  createTagWithdrawalVaultAccounts(assetId, "Withdrawal");
  createTagOmnibusAccount(2, assetId, internalCustRefIds);
  ```

  ```python Python theme={"system"}
  ASSET = "XLM_TEST"
  CUSTOMER_IDS = ["a", "b", "c"]

  def create_tag_withdrawal_vault(asset: str, name: str):
      vault_id = fireblocks.create_vault_account(name=name)["id"]
      address = fireblocks.create_vault_asset(vault_account_id=vault_id, asset_id=asset)["address"]

      return {name: vault_id}, address

  def create_tag_omnibus_vault(amount: int, asset: str, customer_ids: list, hidden_on_ui: bool = True):
      deposit_tags = {}

      vault_id = fireblocks.create_vault_account(name="Omnibus")
      address = fireblocks.create_vault_asset(vault_account_id=vault_id, asset_id=asset)["address"]
      for i in range(amount):
          tag = fireblocks.generate_new_address(vault_account_id=vault_id, asset_id=asset, description=customer_ids[i], hidden_on_ui=hidden_on_ui)["tag"]
          deposit_tags[customer_ids[i]] = address

      return {"Omnibus": vault_id, "Address": address, "Tags": deposit_tags}

  print(create_tag_withdrawal_vault(ASSET, "Withdrawal"))
  print(create_tag_omnibus_vault(3, ASSET, CUSTOMER_IDS))
  ```
</CodeGroup>

This creates an omnibus vault and a withdrawal vault, then generates a unique deposit identifier per end user. The function returns a dictionary of vault IDs and deposit address mappings.
