Python SDK (server)
invonetwork is the official first-party server-side SDK for integrating Invo from a Python backend (Django, Flask, FastAPI, or plain Python). It's the Python counterpart to the Web / TypeScript SDK — same endpoints, field names, and webhook signing scheme, so both stay in lockstep.
Server-side only — holds your game secret
This SDK authenticates with your game secret and is meant for your backend. For the browser half (passkey enroll/approve, self-claim, balances/destinations for a logged-in player), pair it with the Web SDK — the game secret never reaches the browser.
Currency & Item Purchase
Hosted checkout, direct rail, and spend-currency item purchases
Sends & Transfers
Initiate on the server; the browser approves by passkey
Balances & Reads
Player balances, inbound-pending, linked identities, order details
Webhook Verification
Constant-time HMAC verification with typed events
Install
Requires Python 3.9+. The exact command differs slightly by OS — use the one for your platform:
macOS / Linux
python3 -m pip install invonetworkWindows
py -m pip install invonetworkRecommended: inside a virtual environment
python3 -m venv .venv
source .venv/bin/activate
pip install invonetworkpy -m venv .venv
.venv\Scripts\Activate.ps1
pip install invonetworkFull stack? Install the server SDK here and the browser SDK on your web front-end:
# Python backend (this package)
pip install invonetwork
# Web / browser front-end (Node ≥ 18)
npm install @invonetwork/web-sdkQuickstart
Construct one InvoServer with your game secret and reuse it. Get your secret and base URLs from the Invo console (https://console.invo.network for production, https://dev.console.invo.network for testing).
from invonetwork import InvoServer
invo = InvoServer(
game_secret="sk_live_...", # server-side ONLY
base_url="https://sandbox.invo.network/sandbox", # prod: https://invo.network
)
# Mint a short-lived, game-scoped token for the browser SDK to use
token = invo.mint_player_token(player_email="player@example.com")
# Spend game currency on an in-game item (balance debit; grant off the item.purchased webhook)
order = invo.purchase_item(
client_request_id="req-123", # idempotency key
player_email="player@example.com",
player_name="Ada",
item_id="sword_001",
item_name="Flaming Sword",
item_quantity=1,
unit_price="150.00",
total_price="150.00",
)
# Read a player's balances
balance = invo.get_player_balance(player_email="player@example.com")Verify webhooks
Pass the raw request bytes (never a re-serialized object) and your signing secret. verify_webhook checks the HMAC in constant time, rejects stale timestamps, supports secret rotation, and returns a typed event.
from flask import Flask, request
from invonetwork import verify_webhook, InvoError
app = Flask(__name__)
@app.post("/invo/webhooks")
def invo_webhook():
try:
event = verify_webhook(
request.get_data(), # RAW bytes
request.headers.get("X-Invo-Signature"),
"whsec_...", # your signing secret (or a list during rotation)
)
except InvoError:
return "", 400 # bad signature / stale / malformed
if event.event_type == "purchase.completed":
grant_currency(event.data) # idempotent on event.idempotency_key
return "", 200from fastapi import FastAPI, Request, Response
from invonetwork import verify_webhook, InvoError
app = FastAPI()
@app.post("/invo/webhooks")
async def invo_webhook(request: Request):
raw = await request.body()
try:
event = verify_webhook(raw, request.headers.get("X-Invo-Signature"), "whsec_...")
except InvoError:
return Response(status_code=400)
# handle event.event_type ...
return Response(status_code=200)Errors
Every failure raises InvoError with .code, .status,.message, .body, and .request_id, plus classifier helpers so you don't string-match:
from invonetwork import InvoError
try:
invo.purchase_item(...)
except InvoError as e:
if e.is_insufficient_balance:
... # not enough currency
elif e.is_duplicate_request:
... # replayed client_request_id
elif e.retry_after is not None:
... # throttled; back off e.retry_after seconds
else:
raiseWhat's included
- Tokens & flows:
mint_player_token,initiate_send,initiate_transfer,create_checkout,purchase_currency,confirm_payment,purchase_item - Reads:
get_order_details,get_item_purchase_history(+iterate_item_purchase_history),get_item_order_details,get_player_balance,get_inbound_pending,get_linked_identities - Webhooks:
verify_webhookwith a typedWebhookEvent - Resilience: automatic retries (network / 429 / 5xx, idempotent-only, honoring
retry_after), timeouts, and observability hooks - Types: full type hints, ships
py.typed(mypy --strictclean)