UseThatApp Logo
    Python

    Python Documentation

    Sell your web app from your own website with UseThatApp as the merchant of record, sign buyers in with their UseThatApp account over standard OAuth 2.0 / OpenID Connect, and gate features on their live entitlement — a buyer who completes checkout lands back in your app already signed in, entitlement live. The usethatapp Python SDK is framework-agnostic — it takes and returns plain strings and one JSON-able flow_state dict, so it works with Flask, Django, FastAPI, Dash, Streamlit, plain WSGI, or a CLI. Each framework guide below is copied from a tested example in the SDK.

    This guide covers the Hosted sign-in path

    It has UseThatApp run login, so buyers return signed in and the same session answers what they bought — the Hosted sign-in add-on. If your app already has its own accounts, you do not need any of the sign-in wiring below: keep your login and verify purchases with a license key your server validates in one call, included in the per-sale fee.

    What the SDK does

    A single OIDC login gives you identity and entitlement at once, and the purchase helpers close the loop:

    • Identity. complete_login() returns a UtaSession carrying the user's sub — a pairwise pseudonymous id that is stable for a user within your app, different in every other app, and carries no PII. Use it as your local user key.
    • Entitlement. get_entitlement(access_token) returns the user's current, live plan so you can gate features. A canceled license stops being entitled immediately.
    • Purchasing. purchase_url(price_id) and manage_url() are pure URL builders — no network call — for hosted checkout and the buyer's subscription-management page. UseThatApp is the merchant of record (payment, tax, refunds), and the license is created synchronously at checkout, so no webhooks. get_prices() / get_prices_async() return a live AppPrices with a tuple of Price entries, each carrying a ready-made buy_url and the product_id that matches the entitlement’s product_public_id; get_app_info() / get_app_info_async() return your public AppInfo listing. See Sell from your own website and the Pricing API.

    The SDK is a confidential, server-side client: it holds your client secret and validates ID tokens. Keep it on your server, never in the browser. For the conceptual deep-dive, see OpenID Connect.

    Install

    terminal
    pip install usethatapp

    Python 3.9+. Runtime dependencies are httpx and joserfc — no web framework required. These docs describe 2.2.0 or newer; if you are upgrading from an earlier release, run pip install --upgrade usethatapp first — the License Key API, product_id, and UtaServiceNotEnabledError do not exist before it.

    Configure

    The SDK reads its config from django.conf.settings when Django is installed and configured, otherwise from environment variables — or set anything in code with configure(...), which wins over both. Only the client id and secret are required; the rest default to production.

    environment
    UTA_CLIENT_ID=...            # required
    UTA_CLIENT_SECRET=...        # required (server-side only)
    # or read the secret from a mounted file (Render / k8s / Fly):
    # UTA_CLIENT_SECRET_PATH=/run/secrets/uta_client_secret
    UTA_REDIRECT_URI=https://yourapp.com/callback   # required
    # optional — default to production:
    UTA_ISSUER=https://www.usethatapp.com/o
    UTA_API_URL=https://www.usethatapp.com
    UTA_SCOPES="openid entitlements"

    In code — same names, snake_case keywords (the JavaScript SDK's configure({...}) works the same way):

    Python
    import usethatapp
    
    # e.g. point a dev machine at a local platform instance:
    usethatapp.configure(
        api_url="http://localhost:8000",
        issuer="http://localhost:8000/o",
    )
    usethatapp.load_config()    # the resolved UtaConfig (cached)
    usethatapp.reset_config()   # drop overrides; back to settings/env
    usethatapp.DEFAULT_API_URL  # "https://www.usethatapp.com"

    The shape of an integration

    Every framework follows the same three routes plus a gated view. The SDK does the crypto; you wire the framework-specific bits (read callback query params, store flow_state in your session, issue redirects).

    any framework
    from usethatapp import begin_login, complete_login, get_entitlement
    
    # /login — start the auth-code flow:
    auth_url, flow_state = begin_login()
    save_to_session("uta_flow", flow_state)        # JSON-able dict
    return redirect(auth_url)
    
    # /callback — reads ?code=&state=, or ?error= on cancel:
    if read_query("error"):
        return redirect("/")                        # login canceled
    session = complete_login(
        code=read_query("code"),
        state=read_query("state"),
        flow_state=load_from_session("uta_flow"),
    )
    save_to_session("uta_sub", session.sub)
    save_to_session("uta_access_token", session.access_token)
    
    # anywhere you gate features:
    ent = get_entitlement(load_from_session("uta_access_token"))
    if ent.entitled and ent.product_public_id == "prod_<your-pro-id>":
        unlock_pro_features()

    Framework guides

    • Flask — confidential server app, /login · /callback · /logout.
    • Django — views and URL patterns; config read from settings.
    • FastAPI — async hot path with get_entitlement_async and Starlette sessions.
    • Dash — routes on the underlying Flask server, entitlement in a callback.
    • Streamlit — a small BFF companion server handles OIDC; Streamlit reads the result.

    Next steps

    Read OpenID Connect for the full model, then Error Handling and Gotchas.

    AI agents: this site is fully pre-rendered — fetch /llms.txt for an indexed summary of every page, or /llms-full.txt for the whole documentation as one Markdown file.