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

# Account hierarchy

> Understand Anchorage Digital's hierarchical model for organizations, accounts, vaults, wallets, and balances.

export const ApiPlayground = ({endpoint = "", method = "GET", mode = "curl", title = "API playground", description, params = [], bodyTemplate = ""}) => {
  const API_KEY_STORAGE = "anchorage-api-key-v1";
  const METHOD = method.toUpperCase();
  const MODE = mode === "live" ? "live" : "curl";
  const isBodyMethod = METHOD === "POST" || METHOD === "PUT" || METHOD === "PATCH";
  const [apiKey, setApiKey] = useState("");
  const [hydrated, setHydrated] = useState(false);
  const [copied, setCopied] = useState(false);
  const [paramValues, setParamValues] = useState({});
  const [body, setBody] = useState(bodyTemplate);
  const [sending, setSending] = useState(false);
  const [response, setResponse] = useState(null);
  useEffect(() => {
    try {
      const saved = window.sessionStorage.getItem(API_KEY_STORAGE);
      if (saved) setApiKey(saved);
    } catch {}
    setHydrated(true);
  }, []);
  useEffect(() => {
    if (!hydrated) return;
    try {
      window.sessionStorage.setItem(API_KEY_STORAGE, apiKey);
    } catch {}
  }, [hydrated, apiKey]);
  const setParam = (name, value) => setParamValues(prev => ({
    ...prev,
    [name]: value
  }));
  const buildUrl = () => {
    if (!endpoint) return "";
    const qp = new URLSearchParams();
    for (const p of params) {
      const v = (paramValues[p.name] || "").trim();
      if (v) qp.set(p.name, v);
    }
    const qs = qp.toString();
    return qs ? `${endpoint}?${qs}` : endpoint;
  };
  const buildCurl = () => {
    const url = buildUrl();
    if (!url) return "";
    const key = apiKey || "YOUR_API_KEY";
    const parts = [`curl -X ${METHOD} "${url}"`, `  -H "Api-Access-Key: ${key}"`];
    if (isBodyMethod && body.trim()) {
      parts.push(`  -H "Content-Type: application/json"`);
      parts.push(`  -d '${body.trim()}'`);
    }
    return parts.join(" \\\n");
  };
  const sendRequest = async () => {
    const url = buildUrl();
    if (!url || sending) return;
    setSending(true);
    setResponse(null);
    const started = performance.now();
    try {
      const headers = {
        "Api-Access-Key": apiKey || ""
      };
      const init = {
        method: METHOD,
        headers
      };
      if (isBodyMethod && body.trim()) {
        headers["Content-Type"] = "application/json";
        init.body = body.trim();
      }
      const res = await fetch(url, init);
      const text = await res.text();
      let pretty = text;
      try {
        pretty = JSON.stringify(JSON.parse(text), null, 2);
      } catch {}
      setResponse({
        ok: res.ok,
        status: res.status,
        statusText: res.statusText,
        body: pretty,
        ms: Math.round(performance.now() - started)
      });
    } catch (err) {
      setResponse({
        ok: false,
        status: 0,
        statusText: "Request failed",
        body: (err && err.message ? err.message : String(err)) + "\n\nThis is often a CORS block: the Anchorage API rejects cross-origin " + "browser requests. Use curl builder mode and run the command from your terminal.",
        ms: Math.round(performance.now() - started)
      });
    } finally {
      setSending(false);
    }
  };
  const handleCopy = async () => {
    const cmd = buildCurl();
    if (!cmd) return;
    try {
      await navigator.clipboard.writeText(cmd);
      setCopied(true);
      setTimeout(() => setCopied(false), 1400);
    } catch {}
  };
  const curlCommand = buildCurl();
  const displayUrl = buildUrl();
  const methodBadgeColor = ({
    GET: "#10b981",
    POST: "#5580F6",
    PUT: "#f59e0b",
    PATCH: "#f59e0b",
    DELETE: "#ef4444"
  })[METHOD] || "#5580F6";
  const INPUT_CLASS = "w-full rounded-md border border-zinc-950/15 dark:border-white/15 bg-white dark:bg-zinc-800 px-3 py-2 text-sm font-mono text-zinc-900 dark:text-zinc-100 placeholder:text-zinc-400 dark:placeholder:text-zinc-500 focus:outline-none focus:ring-2 focus:ring-[#5580F6]/40 focus:border-[#5580F6]/60";
  return <div className="not-prose my-6 rounded-2xl border border-zinc-950/10 dark:border-white/10 bg-white dark:bg-zinc-900 shadow-sm overflow-hidden">
      {}
      <div className="px-5 py-4 border-b border-zinc-950/10 dark:border-white/10 bg-zinc-50 dark:bg-zinc-950/40">
        <div className="flex items-center gap-2">
          <span className="inline-flex items-center rounded px-1.5 py-0.5 text-[11px] font-bold font-mono text-white" style={{
    backgroundColor: methodBadgeColor
  }}>
            {METHOD}
          </span>
          <span className="text-xs font-bold tracking-wider uppercase text-[#5580F6]">
            {MODE === "live" ? "live call" : "curl builder"}
          </span>
        </div>
        <h3 className="mt-2 text-base font-semibold text-zinc-950 dark:text-white">
          {title}
        </h3>
        {description && <p className="mt-1 text-sm text-zinc-600 dark:text-zinc-400">{description}</p>}
      </div>

      <div className="px-5 py-4 space-y-5">
        {}
        <label className="block">
          <div className="mb-1 text-xs font-semibold text-zinc-700 dark:text-zinc-300">
            API access key
          </div>
          <input type="text" autoComplete="off" spellCheck={false} value={apiKey} onChange={e => setApiKey(e.target.value.trim())} placeholder="Paste your Api-Access-Key" className={INPUT_CLASS} />
          <p className="mt-1.5 text-[11px] text-zinc-500 dark:text-zinc-500">
            Stored in this tab's{" "}
            <code className="text-[10px]">sessionStorage</code> — clears when you close the tab.
          </p>
        </label>

        {}
        {params.length > 0 && <details className="group rounded-lg border border-zinc-950/10 dark:border-white/10 bg-zinc-50/60 dark:bg-zinc-950/30">
            <summary className="cursor-pointer list-none px-3 py-2 text-xs font-semibold text-zinc-700 dark:text-zinc-300 flex items-center justify-between">
              <span>
                Query parameters{" "}
                <span className="font-normal text-zinc-400 dark:text-zinc-500">
                  (optional)
                </span>
              </span>
              <svg className="h-3.5 w-3.5 transition-transform group-open:rotate-180 text-zinc-500" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
                <polyline points="6 9 12 15 18 9" />
              </svg>
            </summary>
            <div className="px-3 pb-3 pt-2 grid grid-cols-2 gap-3">
              {params.map(p => <label key={p.name} className="block">
                  <div className="mb-0.5 text-[11px] font-semibold font-mono text-zinc-600 dark:text-zinc-400">
                    {p.name}
                  </div>
                  {p.description && <div className="mb-1 text-[11px] text-zinc-500 dark:text-zinc-500 leading-relaxed">
                      {p.description}
                    </div>}
                  <input type="text" spellCheck={false} value={paramValues[p.name] || ""} onChange={e => setParam(p.name, e.target.value.trim())} placeholder={p.placeholder || ""} className={INPUT_CLASS} />
                </label>)}
            </div>
          </details>}

        {}
        {isBodyMethod && <label className="block">
            <div className="mb-1 text-xs font-semibold text-zinc-700 dark:text-zinc-300">
              Request body
            </div>
            <textarea spellCheck={false} value={body} onChange={e => setBody(e.target.value)} placeholder="{&quot;key&quot;: &quot;value&quot;}" rows={6} className={"resize-y " + INPUT_CLASS} />
          </label>}

        {}
        {MODE === "curl" && <div>
            <div className="flex items-center justify-between mb-2">
              <div className="text-xs font-semibold text-zinc-700 dark:text-zinc-300">
                Generated command
              </div>
              <button type="button" onClick={handleCopy} disabled={!curlCommand} className={"rounded-md border px-2.5 py-1 text-[11px] font-medium transition " + (copied ? "border-emerald-500/40 bg-emerald-500/10 text-emerald-700 dark:text-emerald-400" : curlCommand ? "border-zinc-950/15 dark:border-white/15 text-zinc-700 dark:text-zinc-300 hover:bg-zinc-50 dark:hover:bg-white/5" : "border-zinc-950/10 dark:border-white/10 text-zinc-400 dark:text-zinc-600 cursor-not-allowed")}>
                {copied ? "Copied" : "Copy"}
              </button>
            </div>
            <div className="rounded-lg border border-zinc-200 dark:border-zinc-800 bg-zinc-100 dark:bg-zinc-950 overflow-auto">
              <pre className="px-4 py-3 text-[12px] font-mono text-zinc-800 dark:text-zinc-100 whitespace-pre">
                {curlCommand || <span className="text-zinc-400 dark:text-zinc-600 italic">
                    Configure the endpoint above to generate a command.
                  </span>}
              </pre>
            </div>
            <p className="mt-2 text-[11px] text-zinc-500 dark:text-zinc-500">
              Run this in your terminal. The{" "}
              <code className="text-[10px]">Api-Access-Key</code> header updates live as you type.
            </p>
          </div>}

        {}
        {MODE === "live" && <div>
            <div className="flex items-center justify-between mb-2">
              <div className="text-xs font-semibold text-zinc-700 dark:text-zinc-300">
                Response
              </div>
              <button type="button" onClick={sendRequest} disabled={!displayUrl || sending} className="rounded-md px-3 py-1 text-[11px] font-semibold text-white transition disabled:cursor-not-allowed" style={{
    backgroundColor: !displayUrl || sending ? "#9ca3af" : "#5580F6"
  }}>
                {sending ? "Sending…" : "Send request"}
              </button>
            </div>
            <div className="rounded-lg border border-zinc-200 dark:border-zinc-800 bg-zinc-100 dark:bg-zinc-950 overflow-auto">
              {response ? <div>
                  <div className="flex items-center gap-2 border-b border-zinc-200 dark:border-zinc-800 px-4 py-2 text-[11px] font-mono">
                    <span className={"font-bold " + (response.ok ? "text-emerald-600 dark:text-emerald-400" : "text-red-600 dark:text-red-400")}>
                      {response.status || "ERR"} {response.statusText}
                    </span>
                    <span className="text-zinc-400 dark:text-zinc-600">{response.ms} ms</span>
                  </div>
                  <pre className="px-4 py-3 text-[12px] font-mono text-zinc-800 dark:text-zinc-100 whitespace-pre-wrap break-words">
                    {response.body}
                  </pre>
                </div> : <pre className="px-4 py-3 text-[12px] font-mono whitespace-pre">
                  <span className="text-zinc-400 dark:text-zinc-600 italic">
                    Send the request to see the response here.
                  </span>
                </pre>}
            </div>
            <p className="mt-2 text-[11px] text-amber-600 dark:text-amber-500">
              The Anchorage API rejects cross-origin browser requests (CORS) and requires
              signed requests. Live call typically fails against production — use curl builder
              mode and run the command from your terminal.
            </p>
          </div>}
      </div>
    </div>;
};

Anchorage Digital's security model uses a hierarchical structure for organizational entities and crypto assets. Each level has unique properties, allowing for flexible configurations to meet your organization's needs. While all use cases are unique, each maintains consistent structural rules. The following diagram provides an overview of each:

<img src="https://mintcdn.com/deployment-4/acPNZHOVq46gMy_P/knowledge-base/images/diagrams/account-hierarchy.png?fit=max&auto=format&n=acPNZHOVq46gMy_P&q=85&s=6bb013357a0e2aa41f3d3e58e487ab11" alt="Diagram of the Anchorage Digital account hierarchy, showing an organization branching into accounts, each account branching into vaults, and each vault holding wallets." width="710" height="753" data-path="knowledge-base/images/diagrams/account-hierarchy.png" />

## Organizations

At Anchorage Digital, the **organization** is the highest hierarchical classification within the product, where a client or partner of Anchorage Digital is onboarded. Clients may have one or many accounts under each organization.

## Accounts

Each organization can have multiple **accounts**. Each account can be its own legal entity under the parent organization, or a part of the legal parent organization. This enables parent organizations to onboard separate business entities while maintaining separate ownership of assets at the account level.

Accounts can also be used to onboard end customers (program customers) under the control of the middle-B partner (partner platform) for business-to-business-to-business (B2B2B) or business-to-business-to-consumer (B2B2C) use cases. For more information, contact our client experience team at [accountexecutive@anchorage.com](mailto:accountexecutive@anchorage.com).

## Vaults

Under each account, there may be one or many **vaults**. A vault is Anchorage Digital's way of organizing asset wallets and user and API key permissions. If the organization has multiple vaults, each one can be managed by the same or separate admins on the account.

Each vault has its own security and quorum approval policy. Admins elect who manages each vault and how many vault members constitute a quorum for sensitive transactions or activities within the vault. Vaults can hold single or multiple assets, depending on the use case. Each vault also has its own `vaultId`, used to request or filter API responses, including withdrawals, trades, and transfers.

<Note>
  The `vaultId` is uniquely identifiable across the Anchorage Digital platform and can be used to reference a vault using Anchorage Digital's APIs. You can find the `vaultId` field by hitting the list vaults endpoint. Only the vaults provisioned on the API key are returned.
</Note>

### View your account structure

Wallets hold balances for a specific asset within a vault, and each vault can contain multiple wallets—one per asset type. As you map your account structure, use `GET /v2/wallets` to list every wallet your API key can access across all permissioned vaults.

<ApiPlayground
  endpoint="https://api.anchorage-staging.com/v2/wallets"
  method="GET"
  title="List wallets"
  description="Fetch all wallets accessible to your API key."
  params={[
{ name: "limit", placeholder: "e.g. 10", description: "Maximum number of results to return." },
{ name: "afterId", placeholder: "walletId", description: "Cursor for the next page — use the last walletId from the previous response." },
{ name: "networkId", placeholder: "e.g. ethereum", description: "Filter by blockchain network." },
{ name: "assetType", placeholder: "e.g. ETH", description: "Filter by asset type." },
{ name: "filterByIsArchived", placeholder: "true or false", description: "Include archived wallets. Default excludes them." },
{ name: "searchByAddress", placeholder: "On-chain address", description: "Filter by a specific deposit address." },
]}
/>

## Wallets

Under each vault, there may be multiple **wallets**. A wallet at Anchorage Digital is similar to a traditional crypto wallet, with slight nuances to match the structure of Anchorage Digital's platform capabilities and services.

Anchorage Digital wallets are tied to a particular blockchain and serve as a flexible way to aggregate and manage assets. This removes the complexity and need for users to manage multiple addresses, while maintaining the ability to trace assets and view separate on-chain interactions. There may also be multiple wallets on the same blockchain within the same vault, if needed to support the use case.

### Wallet creation

All active members of a vault can create a wallet via the create wallet API, which doesn't require quorum approval. Wallet addresses can be reused, although they can't be deleted once generated in a vault, as they remain live on the blockchain.

<Warning>
  If a vault is ever deleted, ensure individuals—including counterparties—with access to wallet addresses refrain from sending additional assets to the deleted vault. If a deposit is made to an address under a deleted vault, Anchorage Digital can reactivate it to retrieve the assets.
</Warning>

### Default wallet

If there are multiple wallets for the same blockchain within a single vault, the first wallet created for each specific blockchain is designated as the **default wallet**. The following operations require the default wallet, as these are specified at the vault level and the default wallet is the source of funds:

* External withdrawals
* Settlement of funds from Anchorage Digital trading into client vaults
* Execution of a hold via API

### UTXO vs. account-based wallets

Anchorage Digital uses various asset wallet models: account-based and unspent transaction output (UTXO) wallets. The conceptual difference is that the account model updates user balances globally.

The UTXO model only records transaction receipts. In the UTXO model, account balances are calculated on the client side by adding up the available unspent transaction outputs (UTXOs).

When a transaction uses more funds than needed from a source address, the remainder (or "change") is sent to a new change address within the wallet. These change addresses are automatically managed and are part of the wallet's balance.

| Type             | Account-based wallets                                                                                                                                                                                                                              | UTXO wallets                                                                                                                                                                                                                                            |
| :--------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Definition       | Contain one address for multiple assets on the same blockchain. The transaction model is similar to spending on an ATM card, where the balance is reduced by the exact amount spent. This keeps track of each account's balance as a global state. | Take into account the unspent transaction output, where a single input results in a new unspent balance and a net-new address created within the wallet each time this occurs. This is similar to using a one dollar bill and getting change in return. |
| Example          | An Ethereum-based wallet with a single address for ETH and ERC-20s (e.g. USDC).                                                                                                                                                                    | A Bitcoin wallet with multiple addresses for the same BTC wallet, each with individual on-chain balances, but pooled together for transactions and transfers.                                                                                           |
| Additional notes | The address is the only deposit address across all tokens within the wallet (e.g. ETH and USDC). Asset-specific balances, transfers, and transactions are accessible in the iOS app, web dashboard, and on-chain using blockchain explorers.       | During a transfer or transaction, funds are automatically pulled from multiple source addresses—you don't need to designate addresses. All addresses created can be used as deposit addresses at Anchorage Digital.                                     |

## Balances

Each asset in an Anchorage Digital vault contains an `availableBalance` and a `totalBalance`:

* `availableBalance` is the balance of funds available to be withdrawn or transferred. Use this value when reading balances for client balance monitoring or evaluating sufficient client funds. This balance excludes any funds that are held, in progress, or locked.
* `totalBalance` is the total amount of assets under custody within the vault. This balance may contain funds that are in progress or locked for activities like voting. It's always greater than or equal to the `availableBalance`.
