Sub-wallets
How balances are scoped per partner — and why a user's portfolio can look smaller through your API than it does in their app.
An end user has one combined OroPocket balance. They see all of it in the OroPocket app. You do not. Each partner sees and moves only its own sub-wallet: the slice of that combined balance which was transacted through your integration.
Everything else in the user's holdings — assets they bought directly in the OroPocket app, or through a different partner — is invisible to you. It never appears in a portfolio read, and it cannot be sold, gifted, delivered or withdrawn through your API.
What lands in your sub-wallet
| Source | Credited to you |
|---|---|
| API buys | Server-to-server buys you made on the user's behalf. |
| Embed buys | Buys the user made inside your hosted embed session, however they paid. |
| Embed SIPs | Recurring plans created through your integration, and every installment they execute. |
| BTC cashback | Bitcoin cashback earned on those buys — it follows the buy that produced it. |
| Sell proceeds | INR from sells you executed, credited to your INR sub-wallet. |
| Top-ups | INR the user added through your integration. |
1. Reads are scoped
The portfolio endpoint and the activity feed return your sub-wallet only. Same response shape as always — the numbers are simply your share.
/partner/users/:user_code/portfoliobalance/partner/transactions/alltransactionsSo if a user holds 5g of gold in total but bought 1.2g of it through you, your portfolio read reports 1.2g. That is not a bug and not a stale cache — it is the number you are allowed to act on.
2. Writes are validated against your claim
Sells, gifts, deliveries and withdrawals are all checked against your sub-wallet, not the combined balance. Ask for more than you hold a claim on and the call fails with an INSUFFICIENT_* error that carries the scoped availability figure — so the error itself tells you your real ceiling.
{
"success": false,
"request_id": "req_9f2c…",
"mode": "live",
"error": {
"code": "INSUFFICIENT_USER_BALANCE",
"message": "The user holds 1.2000g gold via your integration; this needs 5.0000g.",
"details": {
"required_grams": 5,
"available_grams": 1.2
}
}
}Read available_grams rather than assuming the user is short of funds overall — they may be holding plenty, just not through you.
3. User-side activity can reduce your balance
This is the rule that surprises people. Your sub-wallet can shrink with no API call from you. In the OroPocket app the user sells against their combined balance — they have no concept of which partner an asset came through, and we do not stop them.
When that happens the sale is drained in a defined order:
| Order | Consumed |
|---|---|
| First | The user's own OroPocket-side portion — anything not claimed by a partner. |
| Then | Partner sub-wallets, largest-first: the biggest remaining claim is consumed before smaller ones. |
You are told about it: those sales fire sell.completed webhooks to your endpoint exactly like an API sell would, so the drain is observable in real time rather than something you discover at reconciliation.
INSUFFICIENT_* on a previously-valid amount as expected, not exceptional.4. KYC and bank accounts are global
Identity is not per-partner. A user verified anywhere is verified everywhere: if they completed KYC in the OroPocket app or through another partner, they arrive at your integration already verified, and you do not need to re-collect anything. The same holds for bank accounts — one verified account is usable across every channel.
Practically: check KYC status before you assume a user needs onboarding, and expect a brand-new user of yours to occasionally already be fully verified.
5. Failed withdrawals restore claims
A withdrawal consumes your sub-wallet claim when it is initiated. If the payout is later rejected or fails, the money comes back to the user and the consumed claim is restored to your sub-wallet in the same motion. You do not need to reconcile it yourself or ask support to re-credit anything.
No integration changes required
Nothing about your code has to change for any of this. Request and response shapes are identical — every endpoint in the Raw API guide keeps the same fields and the same errors. Only the values are scoped to you. The work, if any, is in your assumptions: stop treating a portfolio read as the user's whole net worth, and stop treating your last-known balance as authoritative.