Sending money from a wallet is one API call. What happens between that call and a confirmed transaction is where custody is won or lost. This is the path every payout on Valtu takes.
1. The request
Your server asks for a payout: which wallet pays, which asset, how much, and where it goes. Every request is signed with your API key, and every payout carries your own externalId, so a retry can never send it twice.
await valtu.transfers.create({
walletId: payouts.id,
asset: "USDT-TRC20",
amount: await valtu.assets.toBaseUnits("USDT-TRC20", "250.00"),
to: "TQ…",
externalId: "payout_981",
});
Want to know what will happen first? POST /v1/transfers/preview takes the same body, creates nothing, and returns the network fee and what your policies would do.
2. Your policies decide
Before anything is signed, the payout is checked against your workspace's policies. A policy can look at the amount in USD, the destination, the wallet, how much has left that wallet recently, and who is asking. The outcome is one of three:
- Allow: it goes straight to signing (for example, small payouts made by your API key).
- Require approval: it waits for approvers from a named group.
- Deny: it's blocked, and the reason names the rule.
A common setup: small API payouts go through automatically, anything unusual needs two people, and treasury can only send to saved addresses.
3. Your team approves with passkeys
When approvals are needed, the payout waits as PENDING_APPROVAL. Approvers see it in the dashboard, with the amount, destination and any note, and confirm with a passkey on their own device. A rejection ends it.
Valtu runs the infrastructure but never approves or co-signs your transfers. With team signing turned on, the enclave verifies your approvers' passkey signatures itself, so even Valtu's own servers can't push through a payout your rules don't allow.
4. The enclave signs
Approved payouts move to QUEUED, then SIGNING. The key that signs exists only inside a hardware enclave, and the enclave signs only what passed your policy. If something is missing, such as gas for the fee, lastError says why it's waiting.
5. Broadcast and confirmed
The signed transaction is broadcast (BROADCAST). If it's slow, fees are bumped automatically. Once it's deep enough on its network it's CONFIRMED, with the network fee recorded on the transfer. Your server hears about every step by signed webhook.
If a payout can't be sent within 30 minutes, for example because the wallet is short of funds or gas, it's cancelled before signing rather than left hanging.
Where to go next
- Payouts and approvals on the product page
- The transfer lifecycle in the API guide
- Security: how the enclaves are verified