Counterparties and economic context
Who is on the other side of an operation and why it happened: counterparties and address auto-matching, categories, metadata, and operation relations.
The ledger records amounts, while counterparties and metadata record meaning: who is on the other side and why the operation happened. This layer turns raw movements of funds into business events you can build reports on.
Three layers of context
Economic context is made up of three layers, which are easy to confuse:
| Layer | Answers | Mechanism |
|---|---|---|
| Counterparties | who is on the other side | a set of addresses + auto-match |
| Categories and metadata | why the operation happened | a category catalog + flat fields |
| Operation relations | how operations are related | explicit refund/reversal/… links |
A counterparty is a set of addresses
A counterparty is a named entity with linked addresses. The name is unique within a Vault, and each address belongs to at most one counterparty; otherwise, matching would be ambiguous. Address networks are validated against the Networks registry.
POST /api/v1/vaults/{code}/counterpartiescreates a counterparty (optionally with addresses right away).POST /api/v1/vaults/{code}/counterparties/{id}/addressesadds an address.GET /api/v1/vaults/{code}/counterpartiesreturns a list with thesearch(substring in the name) andkind(for example,exchange) filters.
curl -X POST "[BASE_URL]/api/v1/vaults/acme-otc/counterparties" \
-H "Authorization: Bearer $V3_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "ACME Exchange",
"kind": "exchange",
"addresses": [{ "network": "tron", "address": "TQ2m...p4rX" }]
}'
await fetch("[BASE_URL]/api/v1/vaults/acme-otc/counterparties", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.V3_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
name: "ACME Exchange",
kind: "exchange",
addresses: [{ network: "tron", address: "TQ2m...p4rX" }],
}),
});
requests.post(
"[BASE_URL]/api/v1/vaults/acme-otc/counterparties",
headers={"Authorization": f"Bearer {os.environ['V3_TOKEN']}"},
json={
"name": "ACME Exchange",
"kind": "exchange",
"addresses": [{"network": "tron", "address": "TQ2m...p4rX"}],
},
)
The body fields shown here are for illustration only. Check the exact schema in the API Reference.
Auto-matching and retroactive matching
When an operation goes to or from a known address, it's automatically linked to the counterparty, so there's no need to tag it manually. And if an address is added later, a retroactive match kicks in: existing operations involving that address are matched to the counterparty after the fact, and the classification history is preserved.
The point of retroactive matching is that classification is never lost and doesn't require manual cleanup after the fact: just add the address to the counterparty.
Counterparty groups
Counterparties can be grouped, for example, by type or jurisdiction:
POST /api/v1/vaults/{code}/counterparty-groupscreates a group (members are added separately). This mutation is gated by thecounterparty_group_createpolicy: if approval is required, an approval request is returned.
Archiving: history is never lost
Counterparties aren't deleted; they're archived:
POST /api/v1/vaults/{code}/counterparties/{id}/archivewitharchived=true: the counterparty stops matching new operations and can't be used for new transfers, but its history is preserved;falserestores it. Gated by thecounterparty_archivepolicy.
Operation categories
Categories are a configurable, versioned catalog used to build reports and filters:
GET /api/v1/vaults/{code}/operation-categoriesreturns the Vault's category list. The schema is visible to every member (it's used to buildcategoryKey,groupByField, andmetricFieldfor the report builder);viewScoperestricts access to the values on operations, not to the schema itself.
A category can have its own approvers (POST / DELETE /api/v1/vaults/{code}/operation-categories/{id}/approvers), so operations in a certain category can require approval from designated people (see Approvals).
Operation metadata
Metadata attaches business context to an operation. GET / PATCH /api/v1/vaults/{code}/operations/{type}/{id}/metadata upserts flat fields; each change increments version.
| Field | What it is |
|---|---|
paymentPurpose | payment purpose |
category | a code from the category catalog |
tags | arbitrary tags |
description | description |
dealId / invoiceId / orderId / settlementId / obligationId | external references and business links |
curl -X PATCH "[BASE_URL]/api/v1/vaults/acme-otc/operations/transfer/OPERATION_ID/metadata" \
-H "Authorization: Bearer $V3_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "paymentPurpose": "Invoice payment", "category": "settlement", "invoiceId": "INV-2026-0042" }'
await fetch("[BASE_URL]/api/v1/vaults/acme-otc/operations/transfer/OPERATION_ID/metadata", {
method: "PATCH",
headers: {
Authorization: `Bearer ${process.env.V3_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
paymentPurpose: "Invoice payment",
category: "settlement",
invoiceId: "INV-2026-0042",
}),
});
requests.patch(
"[BASE_URL]/api/v1/vaults/acme-otc/operations/transfer/OPERATION_ID/metadata",
headers={"Authorization": f"Bearer {os.environ['V3_TOKEN']}"},
json={
"paymentPurpose": "Invoice payment",
"category": "settlement",
"invoiceId": "INV-2026-0042",
},
)
Don't confuse the two: the flat category field in a specific operation's metadata is a reference to a code from the versioned category catalog, not the category itself.
Operation relations
Operations can be explicitly linked to each other to reflect an economic relationship:
| Relation type | Meaning |
|---|---|
refund | a return of funds (partial refunds use relatedAmountRaw) |
reversal | a reversal or cancellation of the original operation |
correction | an error correction |
replacement | replacement of the operation with a new one |
POST /api/v1/vaults/{code}/operation-relationscreates a relation. An opposite payment is not automatically treated as a refund; the link must be set explicitly.
For how these relations work with the ledger's immutability, see Ledger (double-entry).