Create a Vault with a derivation schema
Design your address axes and create a Vault in a single request: the network, static and dynamic segments, their order, and verification.
A Vault is created in a single request, together with its entire derivation structure. The most important work happens before any code: designing the axes along which your addresses will differ. In this guide, we'll design a schema, create a Vault, and verify the result. For the overall model, see Vaults and derivation.
Prerequisites
- Your instance address, shown as
[BASE_URL]in the examples. - An access token for the
Authorizationheader (see Authentication). - Any HTTP client:
curl, JavaScript, or Python.
Step 1. Design the axes
Decide which axes your addresses will differ by. Each axis is a path segment:
network: a required segment: the blockchain and its BIP-44coinType(TRON is 195, Ethereum is 60).- Static segments: closed lists, such as
purpose(invoices/settlement) andasset(usdt/usdc). - Dynamic segments: an integer index per entity, such as
client(a new branch per client).
The segment order is fixed and defines the shape of the path. As an example, let's use this schema:
network → purpose → asset → client
TRON invoices usdt (dynamic)
settlement usdc
Choose your axes based on how you keep your books and write policies: the same segments become Policy Engine selectors and report dimensions. For more on schema design, see Vaults and derivation.
Step 2. Create the Vault
Send POST /api/v1/vaults with a vault object (code and name) and a routeMap of segments. The network key is required, and 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.
curl -X POST "[BASE_URL]/api/v1/vaults" \
-H "Authorization: Bearer $V3_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"vault": { "code": "acme-otc", "name": "ACME OTC" },
"routeMap": {
"network": [{ "label": "TRON", "coinType": 195 }],
"purpose": [{ "label": "invoices" }, { "label": "settlement" }],
"asset": [{ "label": "usdt" }, { "label": "usdc" }],
"client": { "kind": "dynamic" }
}
}'
await fetch("[BASE_URL]/api/v1/vaults", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.V3_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
vault: { code: "acme-otc", name: "ACME OTC" },
routeMap: {
network: [{ label: "TRON", coinType: 195 }],
purpose: [{ label: "invoices" }, { label: "settlement" }],
asset: [{ label: "usdt" }, { label: "usdc" }],
client: { kind: "dynamic" },
},
}),
});
requests.post(
"[BASE_URL]/api/v1/vaults",
headers={"Authorization": f"Bearer {os.environ['V3_TOKEN']}"},
json={
"vault": {"code": "acme-otc", "name": "ACME OTC"},
"routeMap": {
"network": [{"label": "TRON", "coinType": 195}],
"purpose": [{"label": "invoices"}, {"label": "settlement"}],
"asset": [{"label": "usdt"}, {"label": "usdc"}],
"client": {"kind": "dynamic"},
},
},
)
The routeMap structure is shown for illustration, to convey the idea (a network with a coinType, static options, a dynamic segment). Check the exact request body schema on the create Vault page in the API Reference, which is the source of truth.
The response contains the created Vault with all its relations (simplified):
{
"id": "cmr3f41z20001psp7phmyapw3",
"code": "acme-otc",
"name": "ACME OTC",
"networks": [{ "coinType": 195, "slug": "tron" }],
"routes": [
{ "code": "purpose", "order": 0 },
{ "code": "asset", "order": 1 },
{ "code": "client", "order": 2 }
]
}
Note the code: it goes into every subsequent request.
Step 3. Verify the structure
Make sure the networks and segments were set up as intended:
curl "[BASE_URL]/api/v1/vaults/acme-otc" \
-H "Authorization: Bearer $V3_TOKEN"
const res = await fetch("[BASE_URL]/api/v1/vaults/acme-otc", {
headers: { Authorization: `Bearer ${process.env.V3_TOKEN}` },
});
console.log(await res.json());
requests.get(
"[BASE_URL]/api/v1/vaults/acme-otc",
headers={"Authorization": f"Bearer {os.environ['V3_TOKEN']}"},
).json()
GET /api/v1/vaults/{code} returns the connected networks (by coinType) and Routes (by order) with all their options. This is your derivation structure.
Step 4. Build a test path
Before creating addresses, verify the schema by building a canonical path from segment values:
curl -X POST "[BASE_URL]/api/v1/vaults/acme-otc/derivation-path/build" \
-H "Authorization: Bearer $V3_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "network": "TRON", "purpose": "invoices", "asset": "usdt", "client": 42 }'
await fetch("[BASE_URL]/api/v1/vaults/acme-otc/derivation-path/build", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.V3_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ network: "TRON", purpose: "invoices", asset: "usdt", client: 42 }),
});
requests.post(
"[BASE_URL]/api/v1/vaults/acme-otc/derivation-path/build",
headers={"Authorization": f"Bearer {os.environ['V3_TOKEN']}"},
json={"network": "TRON", "purpose": "invoices", "asset": "usdt", "client": 42},
)
build returns a path like m/44/195/0/0/42 and validates the schema along the way: the network is connected, all Routes are present, the static options exist and are enabled, and the dynamic values are within the allowed range. The reverse operation is derivation-path/parse.
The field names in the build body (the segment values) depend on your Route codes. Check them in the API Reference.
Common mistakes
| Symptom | Cause |
|---|---|
| creation rejected | the Vault's code or name is already taken |
routeMap not accepted | the required network key is missing |
| network not recognized | wrong coinType (check against BIP-44/SLIP-0044) |
build: network not connected | the coinType isn't part of the Vault's structure |
build: option not found | the static option doesn't exist or is disabled |
build: value out of range | the dynamic value isn't within [0, 2^31−1] |
You're done when
GET /api/v1/vaults/acme-otcreturns your networks and Routes;derivation-path/buildreturns a path likem/44/195/...;- you've saved the Vault's
codefor subsequent requests.