Handle an incoming deposit
How an incoming payment becomes a deposit: the Wallet Service webhook (TOPUP), crediting the ledger, and reading the deposit.
Incoming funds arrive on-chain, and Wallet Service monitors your addresses and notifies V3 Custody through a webhook. The platform credits the amount to the ledger and creates a deposit. This guide explains the webhook contract and how to read the result. For how crediting works, see Ledger.
The webhook is called by Wallet Service, not by you. On the integration side, you usually consume the result: deposits, the feed, and balances.
The path of a deposit, from an on-chain payment to an entry in the feed and balance:
Prerequisites
- A monitored address in the Vault. See Generate addresses.
- An access token for reading (see Authentication).
- The Vault's
codeor a deposit id to read the result.
Step 1. How a deposit arrives
POST /webhooks/wallet accepts incoming on-chain events; currently only TOPUP is processed. The token is resolved from the registry by its contract address, the amount is credited to the recipient address, and a deposit record is created.
Example event body:
{
"tx": {
"network": "TRON",
"asset": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
"amount": "500.00",
"toAddress": "TQ5kohbBSdorGoDBmCGUmDL7RUvNr75mBC",
"txHash": "9f2c...e41a"
}
}
asset is the token's contract address; the platform uses it to find the token in the registry.
In demo mode, the webhook has no authentication or signature (HMAC is planned for production), and no strict body schema is enforced (it's an external contract, validated inside the handler). The fields above are for illustration only. Check the exact contract in the API Reference.
Step 2. Read the deposit
Once the deposit is created, its details are available by id:
curl "[BASE_URL]/api/v1/vaults/acme-otc/deposits/DEPOSIT_ID" \
-H "Authorization: Bearer $V3_TOKEN"
const res = await fetch("[BASE_URL]/api/v1/vaults/acme-otc/deposits/DEPOSIT_ID", {
headers: { Authorization: `Bearer ${process.env.V3_TOKEN}` },
});
console.log(await res.json());
requests.get(
"[BASE_URL]/api/v1/vaults/acme-otc/deposits/DEPOSIT_ID",
headers={"Authorization": f"Bearer {os.environ['V3_TOKEN']}"},
).json()
{
"id": "cmr3f41z20001psp7phmyapw3",
"amountDecimal": "500.00",
"token": "usdt",
"toAddress": "TQ5kohbBSdorGoDBmCGUmDL7RUvNr75mBC",
"amlStatus": null
}
| Field | Meaning |
|---|---|
id | deposit id |
amountDecimal | amount in human-readable format |
token | token symbol |
toAddress | recipient address |
amlStatus / amlDetails | placeholders until the automation engine is available |
Step 3. Find deposits in the feed
Deposits show up in your activity feed and are reflected in your balance:
curl "[BASE_URL]/api/v1/vaults/acme-otc/history?direction=in" \
-H "Authorization: Bearer $V3_TOKEN"
const res = await fetch(
"[BASE_URL]/api/v1/vaults/acme-otc/history?direction=in",
{ headers: { Authorization: `Bearer ${process.env.V3_TOKEN}` } },
);
console.log(await res.json());
requests.get(
"[BASE_URL]/api/v1/vaults/acme-otc/history",
params={"direction": "in"},
headers={"Authorization": f"Bearer {os.environ['V3_TOKEN']}"},
).json()
Where to look after crediting:
| What you need | Request |
|---|---|
| deposit details | GET /api/v1/vaults/{code}/deposits/{id} |
| incoming in the feed | GET /api/v1/vaults/{code}/history?direction=in |
| updated balance | GET /api/v1/vaults/{code}/balances (available has increased) |
The deposit is also automatically matched to a counterparty if the sender address belongs to one.
Common mistakes
| Symptom | Cause |
|---|---|
| deposit didn't appear | Wallet Service didn't send TOPUP, or the address isn't monitored |
| token wasn't credited | the contract address isn't in the registry, so resolution failed |
| balance didn't increase | check available, and verify the network and recipient address |
| no counterparty link | the sender address doesn't belong to any counterparty |
| webhook rejected in production | the HMAC signature check failed (there's none in demo) |
You're done when
- the
TOPUPevent was processed and a deposit was created; GET .../deposits/{id}returnsamountDecimalandtoken;- the deposit is visible in
history?direction=in; availableinbalancesincreased by the deposit amount.