Developer documentation

Build your first
wallet flow.

Install the Python SDK, connect a sandbox key, and work with balances, transactions, sessions, and payout reservations through domain-native methods.

Quickstart

MojoWallet’s Python SDK supports Python 3.10 and later. Install the package, configure an API key, and retrieve a wallet.

1. Install

pip install mojowallet

2. Configure

import mojowallet

mojowallet.configure(
    "mvs-your-sandbox-key",
    base_url="https://api.mojowallet.com",
)

3. Make the first request

wallet = mojowallet.Wallet.get(42)
print(wallet.id, wallet.uuid, wallet.name)
print(wallet.balance("SC_REAL"))
Response objects work both ways.Read fields with attribute syntax (result.id) or dictionary syntax (result["id"]).

Core concepts

Wallets and holdings

A wallet belongs to a customer. Its balance is the sum of holdings: balance buckets scoped by currency, category, spend priority, and cashability. This makes deposited, promotional, reserved, and other value independently auditable.

Currencies and families

Use exact currency codes such as SC_REAL for a single balance, or a root code such as SC to operate across an ordered currency family. Family spending walks configured priority and debits as many holdings as needed.

Integer amounts

All amounts use the smallest currency unit. For USD, 1050 represents $10.50. Loyalty or virtual units may already be whole units.

Reference IDs

Send a stable reference_id for financial operations. Safe retries return the original transaction instead of moving value twice. Reusing a reference with different data raises an explicit replay error.

Wallet operations

Operations are methods on a wallet instance. They map to the wallet action endpoint and return transaction or result objects.

MethodPurpose
add_funds()Credit value from an external source into a specific currency and holding category.
purchase()Debit a currency for a merchant purchase after balance and spending-limit checks.
spend()Debit across a root currency family in priority order with an idempotent reference.
cashout()Debit cashable holdings only. The external payout is handled upstream.
transfer()Move value to another wallet in the same tenant.
refund()Fully or partially reverse a completed transaction in the same wallet.
redeem_promo()Apply a promotional code exactly once per wallet and reference.
lock() / unlock()Control wallet availability with an auditable reason.
txn = wallet.add_funds(
    5000,
    "SC_REAL",
    source="CREDIT_CARD",
    category="deposited",
    can_cashout=True,
    reference_id="deposit-1042",
)

wallet.spend(
    750,
    root_code="SC",
    reference_id="purchase-1042",
    merchant="Partner Store",
)

Balance reads

Choose the read that matches the question: exact currency, root family, per-holding detail, or a complete snapshot.

exact = wallet.balance("SC_REAL")
family = wallet.get_root_balance("SC")
holdings = wallet.get_holdings(root_code="SC")
summary = wallet.balance_summary()

summary.balances.SC.available
summary.balances.SC.by_code.SC_REAL
summary.total_by_currency.SC_REAL
SDK 2.3 balance shapebalance_summary().balances is keyed by root code. Per-currency totals remain under total_by_currency.

Sessions

Withdrawal sessions provide concurrency control. Only one active withdrawal session may exist per wallet, preventing two flows from racing the same balance.

with wallet.session(
    "game-round-2026",
    expires_in_seconds=3600,
) as session:
    session.withdraw(
        500, "SC_REAL",
        reference_id="bet-001",
    )
    session.extend(1800)
# The session closes even if an exception occurs.

Reserve flow

External payouts are asynchronous. Reserve wallet value first, then confirm only when the processor succeeds—or release if it fails.

wallet.reserve(
    2500,
    "SC_REAL",
    "SC_HOLD",
    reference_id="payout-001",
)

# Processor succeeded
wallet.confirm_reservation("payout-001")

# Or return value when it failed
wallet.release_reservation("payout-001")

If a hold expires before either terminal call, MojoWallet releases it automatically and emits a reservation-expired event.

REST API

Use the API directly from any server stack. Authenticate with a production mvp- or sandbox mvs- API key.

Authorization: apikey mvs-XXXXXXXXXXXXXXXX
Content-Type: application/json
EndpointPurpose
GET /api/wallet/walletList and filter wallets.
POST /api/wallet/walletCreate a wallet for an existing customer.
POST /api/wallet/wallet/action/<pk>Run financial and session actions.
POST /api/wallet/wallet/query/<pk>Read balances, spending power, historical state, and metrics.
POST /api/wallet/wallet/batchRead balances for multiple wallets.
GET /api/wallet/bonus_grantRead wagering and promotional grant lifecycle.

Read permission allows queries and listings. Manage permission adds wallet mutations. Admin grants full access.

Error handling

The SDK raises domain-specific exceptions for wallet failures. The numeric 5000-block code is authoritative even if an upstream HTTP status differs.

CodeExceptionMeaning
5001WalletInvariantErrorA safety cross-check failed. Show a generic retry message.
5002InsufficientBalanceErrorAvailable balance is lower than required.
5003WalletLockedErrorThe wallet is locked.
5004WalletSuspendedErrorThe wallet is suspended, optionally until a known time.
5005WalletInactiveErrorThe wallet is inactive.
5006InvalidReferenceErrorThe reference is empty or malformed.
5007IdempotentReplayErrorThe same reference was replayed with different input.
from mojowallet.exceptions import (
    InsufficientBalanceError,
    SessionConflictError,
)

try:
    wallet.cashout(
        10000, "SC_REAL",
        reference_id="cashout-002",
    )
except InsufficientBalanceError as error:
    print(error.available, error.required)
except SessionConflictError:
    print("Another session is active")

Need a human? Visit the Help center.