Wallets
Every ISV is provisioned as either SHARED or INDIVIDUAL. That single setting decides how funds are tracked, what GET /private/v1/wallets returns, and a few smaller details elsewhere. Confirm which one you've been provisioned as before designing your wallet flows — they're not interchangeable at runtime.
This doc covers two endpoints: reading the current wallet, and reading the transaction history that produced it.
Auth: see Authentication. Both endpoints accept requests with or without sub, and behave differently depending on which.
1. The two fund models
| Fund type | Wallet rows | Source of truth |
|---|---|---|
INDIVIDUAL | One wallet per user. Each user's balance is segregated. | The user's own wallet row. |
SHARED | One ISV-level pot wallet (userId IS NULL) plus a per-user tally row for each user. | The pot. Per-user tallies are bookkeeping and may go negative. |
A few practical consequences:
- Atomic balance updates target the pot for SHARED ISVs and the user wallet for INDIVIDUAL. For SHARED ISVs, the
balance_before/balance_afterandwallet_versionfields on the transaction log refer to the pot, not the per-user tally. - User deletion semantics differ — see User Onboarding (users, KYC, terms).
- Reading
/walletswithoutsubonly makes sense for SHARED ISVs (it returns the pot). INDIVIDUAL ISVs get a 404 in that case, because there's no pot row to return.
2. GET /private/v1/wallets
GET /private/v1/walletsReturns the caller's wallet row. What "the caller's wallet" means depends on which headers the gateway derives from the JWT:
| Headers present | Result |
|---|---|
X-ProphetX-ISV + X-ProphetX-User (JWT has sub) | That user's wallet row. |
X-ProphetX-ISV only (no sub) | The ISV pot row. SHARED only — INDIVIDUAL ISVs get 404. |
You don't set those headers directly; they come from the JWT claims (iss and sub). See Authentication.
Response shape
{
"id": 42,
"userId": "00000000-0000-0000-0000-000000000000",
"isvId": "00000000-0000-0000-0000-000000000000",
"fundType": "SHARED",
"balance": "100.00",
"version": 17,
"createdAt": "2026-05-01T12:00:00Z",
"updatedAt": "2026-05-12T09:14:22Z"
}A few things worth calling out:
userIdisnullfor the ISV pot row.balanceis a string, not a number. The underlying column isnumeric(16,2), and the string preserves precision and is always rendered with two decimal places. Parse it with a decimal library, not a float, or you'll eventually have an off-by-one-cent bug to chase.versionis an optimistic-concurrency counter that increments on every write. Use it to detect concurrent updates — if you cache the wallet locally, key the cache onversion.updatedAtisnulluntil the row has been updated at least once.
3. GET /private/v1/wallets/transactions
GET /private/v1/wallets/transactionsReturns the caller's transaction history, newest first, paginated by cursor.
| Headers present | Result |
|---|---|
X-ProphetX-ISV + X-ProphetX-User | That user's transactions. |
X-ProphetX-ISV only | ISV-level transactions (user_id IS NULL) — e.g. ISV deposits and withdrawals on the pot. |
An empty result is a 200 with data: [], not a 404.
Query parameters
| Name | Type | Default | Notes |
|---|---|---|---|
limit | integer | 50 | Page size. 1 ≤ limit ≤ 200. |
before | integer | unset | Cursor — return rows with id strictly less than this value. Pass the nextCursor from the previous response. |
Response shape (TransactionsPage)
TransactionsPage){
"data": [
{
"id": 5128,
"txId": "00000000-0000-0000-0000-000000000000",
"userId": "00000000-0000-0000-0000-000000000000",
"isvId": "00000000-0000-0000-0000-000000000000",
"refId": "11111111-1111-1111-1111-111111111111",
"contractId": "8315d4bc44d06eef736959e0b214c170",
"txType": "ORDER",
"amount": "-25.00",
"balanceBefore": "100.00",
"balanceAfter": "75.00",
"walletVersion": 18,
"createdAt": "2026-05-12T09:14:22Z"
}
],
"nextCursor": 5128,
"hasMore": true
}Field meanings:
id— internal row id, also used as the pagination cursor.txId— UUID idempotency / dedupe key for the transaction.userId—nullfor ISV-level rows.refId— UUID of the originating market order or parlay.nullwhen no order is associated (e.g. ISV deposits).contractId— empty string when no contract is associated.txType— one of the values in the next section.amount— signed decimal, two decimal places, string-encoded for the same precision reason asbalance. Debits are negative (e.g.ORDERquantity =-25.00), credits are positive (e.g.PAYpayout =+45.45).balanceBefore/balanceAfter— wallet balance immediately before and after this transaction. For SHARED ISVs, these refer to the pot, not the per-user tally.walletVersion— the optimistic-concurrency version recorded against this transaction (matches theversionfield on the wallet at the time).nextCursor— pass asbeforeto fetch the next page.nullwhen there are no more rows.hasMore— true whennextCursoris set and more rows may follow.
TransactionType enum
TransactionType enum| Value | What it represents |
|---|---|
ORDER | Quantity debited when an order is submitted. |
CANCEL | Quantity returned on order cancellation. |
PAY | Payout on a winning order. |
PUSH | Refund on a push outcome. |
VOID | Refund on a voided contract. |
ADJUSTMENT_INCREASE / ADJUSTMENT_REDUCE | Manual balance adjustments. |
DEPOSIT / WITHDRAW | Money in/out via the funds system. |
APPROVE_WITHDRAW / REJECT_WITHDRAW | Withdrawal decision postings. |
COMMISSION | Commission charge. |
REFUND | Generic refund. |
ORDER_FEE | ISV fee deducted from an order. |
Pagination pattern
# First page
GET /private/v1/wallets/transactions?limit=50
# → { data: [...], nextCursor: 5128, hasMore: true }
# Next page
GET /private/v1/wallets/transactions?limit=50&before=5128
# → { data: [...], nextCursor: 5078, hasMore: true }
# Last page
GET /private/v1/wallets/transactions?limit=50&before=12
# → { data: [...], nextCursor: null, hasMore: false }4. Deposits and withdrawals
GET /private/v1/wallets and /wallets/transactions are read-only. Money movement happens elsewhere:
- Deposits and withdrawals flow through the
/embed/v1/payment/*surface used by the embedded UI, which proxies to ProphetX's funds system. They show up here later asDEPOSIT,WITHDRAW,APPROVE_WITHDRAW, orREJECT_WITHDRAWtransactions. See Embedded UI (tokens + /embed/v1). - Order debits and payouts are side effects of
POST /market-ordersandPOST /parlays/{id}/confirm. They show up here asORDER,CANCEL,PAY,PUSH,VOID,ORDER_FEE, etc.
The private ISV API doesn't expose direct deposit or withdraw endpoints.
5. Failure modes
| HTTP | When |
|---|---|
400 | Bad request — invalid limit (outside 1..200), malformed before, etc. |
401 | JWT missing or invalid. |
404 | INDIVIDUAL ISV calling /wallets without sub. No pot exists. (/wallets/transactions returns 200 with data: [] for empty results, not 404.) |
500 | Server error. |
6. Curl
BASE="https://isv-staging-api.betprophet.co/private/v1"
# A user's wallet (works for both SHARED and INDIVIDUAL ISVs)
curl "$BASE/wallets" -H "Authorization: Bearer $JWT_USER"
# The ISV pot (SHARED ISVs only; INDIVIDUAL returns 404)
curl "$BASE/wallets" -H "Authorization: Bearer $JWT_ISV"
# A user's most recent 50 transactions
curl "$BASE/wallets/transactions?limit=50" -H "Authorization: Bearer $JWT_USER"
# ISV-level transactions (deposits/withdrawals on the pot)
curl "$BASE/wallets/transactions?limit=100" -H "Authorization: Bearer $JWT_ISV"
# Next page
curl "$BASE/wallets/transactions?limit=50&before=5128" -H "Authorization: Bearer $JWT_USER"Updated about 6 hours ago
