Set INDIANA_API_KEY, INDIANA_PROJECT_ID and INDIANA_API_URL (https://api.tinker.cash in production). The event and Feature must already be configured in that App/environment.
An entitlement check only observes access; usage is a separate write. HTTP success does not mean a debit was accepted: inspect each receipt's accepted and reason.
Asynchronous client
holdings.pyPython
1import os23from indiana importAsyncIndiana456asyncdefread_customer_holdings(external_user_id: str):7asyncwithAsyncIndiana(8 api_key=os.environ["INDIANA_API_KEY"],9 project_id=os.environ["INDIANA_PROJECT_ID"],10 environment="sandbox",11 base_url=os.environ["INDIANA_API_URL"],12 ) as client:13 result = await client.get_or_create_customer(external_user_id=external_user_id)14returnawait client.read_holdings(customer_id=result["customer"]["id"])
Reuse one client in a long-running service and close it on shutdown with close() (sync) or await aclose() (async). Both accept timeout in seconds (default 10, maximum 120) and an HTTPX transport= for tests or custom networking. Ambient proxies and cookies are not used and redirects are not followed.
Methods
All arguments are keyword-only; returned TypedDicts keep wire keys such as `customerId`.
Method
Inputs and behavior
Scope
get_or_create_customer
external_user_id or email; optional name, attributes, fingerprint. Existing records are not patched.
customers:write
get_customer
Exactly one of customer_id or external_user_id.
customers:read
list_customers
Filters with explicit offset/limit; returns customers, hasMore, total.
customers:read
update_customer
A retained request_id, one lookup and a partial patch: name, email, attributes, remove_attributes, add_tags, remove_tags.
customer_id, a retained idempotency_key, exactly one of event_name or internal_feature_id; decimal-string quantity, optional properties/entity_id.
Scope
credits:consume
Omitted fields stay omitted; None is not an alias for omission. Quantities are decimal strings, never floats. Import the generated TypedDicts from indiana.models.
IndianaError exposes code, status, request_id, retryable, recovery, and optional reason and retry_after_seconds; it never retains the Key or payload. There are no automatic retries: persist the idempotency_key or request_id before sending and replay the same value and input after an uncertain result. TIMEOUT, NETWORK_ERROR and cancellation do not mean rollback.
Other operations
The Python SDK covers seven operations: Customers, holdings, entitlement checks and usage. Call other server operations, such as sessions, payments, offers, invoices, balance management and Funnel decisions, directly over HTTP with the same Server Key, X-Indiana-Protocol: 0.6 and a JSON body, and handle failures by the error object's code and recovery.
sessions.pyPython
1import os23import httpx45# An operation outside the SDK: issue a Customer Token (sessions:create).6response = httpx.post(7 f"{os.environ['INDIANA_API_URL']}/api/v1/customer-sessions",8 headers={9"Authorization": f"Bearer {os.environ['INDIANA_API_KEY']}",10"X-Indiana-Protocol": "0.6",11 },12 json={"customerId": "<CUSTOMER_UUID>"},13 timeout=10,14)15body = response.json()16if response.is_error:17raiseRuntimeError(body["error"]["code"])18customer_token = body["customerToken"]