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 typeWallet rowsSource of truth
INDIVIDUALOne wallet per user. Each user's balance is segregated.The user's own wallet row.
SHAREDOne 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_after and wallet_version fields on the transaction log refer to the pot, not the per-user tally.
  • User deletion semantics differ — see User Onboarding (users, KYC, terms).
  • Reading /wallets without sub only 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

Returns the caller's wallet row. What "the caller's wallet" means depends on which headers the gateway derives from the JWT:

Headers presentResult
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:

  • userId is null for the ISV pot row.
  • balance is a string, not a number. The underlying column is numeric(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.
  • version is an optimistic-concurrency counter that increments on every write. Use it to detect concurrent updates — if you cache the wallet locally, key the cache on version.
  • updatedAt is null until the row has been updated at least once.

3. GET /private/v1/wallets/transactions

Returns the caller's transaction history, newest first, paginated by cursor.

Headers presentResult
X-ProphetX-ISV + X-ProphetX-UserThat user's transactions.
X-ProphetX-ISV onlyISV-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

NameTypeDefaultNotes
limitinteger50Page size. 1 ≤ limit ≤ 200.
beforeintegerunsetCursor — return rows with id strictly less than this value. Pass the nextCursor from the previous response.

Response shape (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.
  • userIdnull for ISV-level rows.
  • refId — UUID of the originating market order or parlay. null when 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 as balance. Debits are negative (e.g. ORDER quantity = -25.00), credits are positive (e.g. PAY payout = +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 the version field on the wallet at the time).
  • nextCursor — pass as before to fetch the next page. null when there are no more rows.
  • hasMore — true when nextCursor is set and more rows may follow.

TransactionType enum

ValueWhat it represents
ORDERQuantity debited when an order is submitted.
CANCELQuantity returned on order cancellation.
PAYPayout on a winning order.
PUSHRefund on a push outcome.
VOIDRefund on a voided contract.
ADJUSTMENT_INCREASE / ADJUSTMENT_REDUCEManual balance adjustments.
DEPOSIT / WITHDRAWMoney in/out via the funds system.
APPROVE_WITHDRAW / REJECT_WITHDRAWWithdrawal decision postings.
COMMISSIONCommission charge.
REFUNDGeneric refund.
ORDER_FEEISV 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 as DEPOSIT, WITHDRAW, APPROVE_WITHDRAW, or REJECT_WITHDRAW transactions. See Embedded UI (tokens + /embed/v1).
  • Order debits and payouts are side effects of POST /market-orders and POST /parlays/{id}/confirm. They show up here as ORDER, CANCEL, PAY, PUSH, VOID, ORDER_FEE, etc.

The private ISV API doesn't expose direct deposit or withdraw endpoints.


5. Failure modes

HTTPWhen
400Bad request — invalid limit (outside 1..200), malformed before, etc.
401JWT missing or invalid.
404INDIVIDUAL ISV calling /wallets without sub. No pot exists. (/wallets/transactions returns 200 with data: [] for empty results, not 404.)
500Server 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"