Core ConceptsVaults and derivation

Vaults and derivation

A Vault is an address tree you design yourself. Derivation segments become deterministic paths, and an address's path becomes your accounting model.

A Vault is your organization's dedicated space in V3 Custody: it has a code (code, a slug), a name, and, most importantly, a derivation structure that you define yourself. Almost every API route starts with the Vault's code, and all addresses, balances, policies, and reports live inside it.

The Introduction already described Vaults in a nutshell. Here we'll look at what a Vault is made of and how your segments turn into deterministic addresses.

You design the address schema

A typical wallet hands out addresses however it happens to. A Vault works the other way around: you describe which axes your addresses differ by, and the platform turns that into a tree of derivation paths.

Each address is a leaf of the tree. The route from the root to a leaf consists of segments, and each segment is responsible for one axis: network, purpose, asset, client, stage. You choose the set. The segment order is fixed, and it defines the shape of the path.

Here's what the tree looks like in an example. Each level below network branches by its options, and a leaf is a specific address:

The network is the required first segment

The structure has one special segment: network. It defines the blockchain and its coinType per the BIP‑44 standard (for example, TRON is 195, Ethereum is 60). Network values are added to the global Network registry, and a path always starts with m/44/{coinType}/....

A single Vault can hold multiple networks: you connect the coinType values you need, and each gets its own branch.

Segments: static and dynamic

The remaining segments are Routes, ordered by the order field (normalized starting from 0). A Route comes in two kinds:

  • Static: a closed list of options that you define upfront. For example, purpose = invoices | settlement, asset = usdt | usdc. Each option stores its own index in the path; options you no longer need can be disabled (disabled) without breaking addresses that were already issued.
  • Dynamic: not a list but an integer index in the range [0, 2^31−1]. It creates a new branch for each entity: per client, per request, per deposit. This is how each client gets their own subtree, with as many addresses in it as you need.
StaticDynamic
What it isa closed list of optionsan integer index [0, 2^31−1]
Examplespurpose, asset, stageclient, invoice, deposit
Number of valuesfew, known in advanceunlimited, appear on the fly
Rolecategoryinstance
Changesan option can be disabledeach new index is a new branch

The idea behind the split is simple: static segments are your categories (few, known in advance), and dynamic segments are your instances (many, appearing on the fly).

How segments become an address

An address is created by choosing a value for each segment. The platform then builds the canonical path and creates the address:

Segment values are chosen

The network (networkCode) and the static segment values (staticSegments). For dynamic segments, the index is assigned automatically.

The next index is calculated

The next free pathIndex is taken for this combination of segments (with a retry on a concurrency conflict), so two parallel requests can't claim the same path.

The canonical path is built

The values are turned into a path of the form m/44/{coinType}/{seg0}/{seg1}/..., one number per segment, in a fixed order.

Policy check

Address creation goes through the Policy Engine (action=create_address), which can allow it, reject it, or send it for approval.

Example of creating an address:

curl -X POST "[BASE_URL]/api/v1/vaults/demo_vault/addresses" \
  -H "Authorization: Bearer $V3_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "networkCode": "tron_network",
    "staticSegments": { "purpose": "invoices", "asset": "usdt" }
  }'

A path reads both ways

Because the path is deterministic, you can build it from segments and parse it back:

  • POST /api/v1/vaults/{code}/derivation-path/build builds the canonical path from segment values. It checks that the network is connected to the Vault, all Routes are present, the static options exist and are enabled, and the dynamic values are integers within the allowed range.
  • POST /api/v1/vaults/{code}/derivation-path/parse parses a path back into the network and each segment's value. It fails if the prefix isn't m/44/, the coinType isn't connected to the Vault, or the number of segments doesn't match the structure.

Let's parse an example path:

m / 44 / 195 / 0 / 0 / 42
  • 44: the BIP‑44 standard.
  • 195: network: TRON (this is the coinType).
  • 0: purpose: invoices (a static option).
  • 0: asset: usdt (a static option).
  • 42: client: index 42 (a dynamic segment).

One schema, many addresses

The same schema produces any number of addresses; only the segment values change:

purposeassetclientPathWhat it is
invoicesusdt42m/44/195/0/0/42Client 42's invoices, USDT
invoicesusdt43m/44/195/0/0/43Client 43's invoices, USDT
settlementusdc42m/44/195/1/1/42Client 42's settlement, USDC

(purpose: invoices = 0, settlement = 1; asset: usdt = 0, usdc = 1; client is the index.)

How to design a schema

Design your axes upfront, since their order and composition are hard to change later:

  • Start from accounting and policies. Segments become report dimensions and Policy Engine selectors, so choose the ones you'll actually use to roll up volumes and write rules.
  • The order is fixed. It defines the shape of the path, and once addresses have been issued, you can't change it. Think it through from the start.
  • Static for categories, dynamic for instances. A few values known in advance → a static segment; many entities appearing on the fly → a dynamic one.
  • Don't over-segment. Every axis multiplies the tree. Add only what you'll filter, gate, or report by.
  • Disable, don't delete. Mark a static option you no longer need as disabled, and addresses already issued stay valid.
  • One network, one coinType. Connect the networks you need; each gets its own branch.

The order and set of Routes are your Vault's "database schema." Mistakes in them are hard to fix after the fact, so design your axes before creating the Vault.

Common patterns

  • A subtree per client. A dynamic client segment: each client gets their own branch, with as many addresses as needed.
  • An address per invoice or order. A dynamic invoice / order segment: each invoice gets its own address, so incoming payments reconcile automatically.
  • Separation by purpose or stage. A static purpose (invoices / settlement) or stage (hot / cold) segment, so you can write different policies and roll up reports by meaning.

Why the tree is your accounting model

The shape of the path isn't a technical detail; it's a way of keeping your books:

  • An address reveals its purpose. purpose=invoices, asset=usdt, client=42: it's immediately clear that this is an invoicing address for a specific client, not an anonymous string.
  • Policies are written against the same segments. The Policy Engine selects rules by network, asset, and purpose, the same axes as the tree. There's no need to list addresses by hand.
  • Reports roll up along the axes. Balances and volumes are aggregated by network, asset, purpose, and client, because that's already built into the structure.

Creating a Vault

A Vault with its entire derivation structure is created with a single POST /api/v1/vaults request. The body contains a RouteMap, a map of segments that must include the special network key (its options are added to the Network registry by coinType). The other keys become Routes, and their order is normalized starting from 0 in the order they appear.

GET /api/v1/vaults/{code} returns the full configuration of the created Vault: the connected networks (by coinType) and the Routes (by order) with all their options.

The exact schema of the RouteMap body and all its fields is on the create Vault page in the API Reference. This page describes what the structure means, not the request format.

Terms

Next steps