# UseThatApp Documentation > Documentation for selling and integrating a web app through UseThatApp, across Python and JavaScript frameworks. UseThatApp is the MERCHANT OF RECORD for web apps: hosted buy links and a live pricing API, processing payment, remitting tax, handling refunds/chargebacks, and paying sellers via Stripe, so developers sell from their own websites. An app verifies what a buyer purchased in one of two ways: LICENSE KEYS (included in the per-sale fee) let the developer keep their own authentication and validate a key server-to-server; HOSTED SIGN-IN (an optional paid add-on) has UseThatApp run login via OpenID Connect, so buyers return from checkout already signed in and the same session answers their live entitlement. ## Important notes for AI agents - How to read this site: every route serves complete pre-rendered HTML (no JavaScript required), so any page can be fetched directly. This llms.txt is the index; https://docs.usethatapp.com/llms-full.txt contains every page as one Markdown file — prefer it over crawling. Canonical page URLs are extensionless (e.g. https://docs.usethatapp.com/license-keys) and sitemap.xml lists them all. - Selling from your own website is the core offering: UseThatApp is the merchant of record (payment, tax, refunds/chargebacks; sellers get Stripe payouts). Buy buttons link to hosted checkout at https://www.usethatapp.com/buy/{price_id}/ — get price ids AND ready-made buy_url values from the public, CORS-enabled pricing API (GET /api/v1/public/apps/{client_id}/prices/); render prices from that API, never hardcode them. Purchases are currently US-only and buy links are enabled per app during the beta (404 until enabled). The license is created synchronously at checkout — build NO payment webhooks and NO polling. How the app then verifies the purchase depends on its mode: with license keys the return redirect carries a uta_order ref to exchange for the key; with the Hosted sign-in add-on the buyer returns already signed in with a live entitlement. See /purchase/sell-from-your-website. - Two verification modes, and an app picks ONE: (1) LICENSE KEYS — included in the per-sale fee, the developer keeps their own auth; validate_license_key/validateLicenseKey, get_order/getOrder, regenerate_license_key/regenerateLicenseKey, authenticated server-to-server with UTA_CLIENT_ID + UTA_CLIENT_SECRET (HTTP Basic), see /license-keys. (2) HOSTED SIGN-IN — an optional paid add-on where UseThatApp runs login; begin_login/complete_login then get_entitlement, see /licensing. Sign-in itself is free and unmetered; the entitlement call is what the add-on gates (403 service_not_enabled when it is off). Never tell a developer they must use our login to sell. - SDK (PyPI/npm `usethatapp`) also covers the purchase surface — purchase_url/purchaseUrl and manage_url/manageUrl (pure URL builders, no network; manage needs only UTA_CLIENT_ID), get_prices/getPrices and get_app_info/getAppInfo (anonymous public reads; 404 → UtaError when external sales isn't enabled, 429/5xx → UtaServerError). The optional `next` on buy/manage links must be HTTPS on the app's registered domain. - Sign-in is OpenID Connect (OAuth 2.0): 'Sign in with UseThatApp'. The usethatapp SDK is a confidential, SERVER-SIDE client — it holds the client secret and validates ID tokens, so it must never run in the browser (single-page apps such as React/Vue use a backend-for-frontend). - Identity is a pairwise pseudonymous `sub` — stable for a user WITHIN your app, uncorrelatable across apps, and never PII (no email/name). Key your user records off `sub`, never an email. The entitlement response does NOT include `sub`; identity comes from the login (session.sub). - Entitlement gating: branch on the stable `product_public_id` (an opaque prod_… id that survives plan renames — the same id the pricing API returns per price), not the mutable `version` display name. get_entitlement returns 401 (UtaTokenError — re-authenticate/refresh) for an invalid/expired/revoked token and 403 (UtaPermissionError) for a missing scope. - Sign-out is RP-initiated. Both 'logged out' and 'Stay signed in' return to the same post-logout URL, so reconcile via the token rather than clearing your session eagerly: a confirmed logout revokes the token and the next get_entitlement returns 401. - UseThatApp also ships a remote MCP server at https://www.usethatapp.com/mcp (Streamable HTTP + OAuth) so AI agents can manage a developer's own apps: integration settings (integrations.read/write scopes) and listing content + product descriptions incl. listing_mode (listing.read/write scopes). The fee-changing Hosted sign-in add-on toggle is deliberately NOT exposed via MCP — its state is readable via get_integration_settings, which also returns the dashboard URL where the developer flips it. See /mcp for setup and the tool reference. ## Getting Started - [Introduction](https://docs.usethatapp.com/): Sell your web app from your own website with UseThatApp as merchant of record: hosted buy links and a live pricing API, live entitlements the moment checkout completes, and "Sign in with UseThatApp" (OIDC) bringing buyers back into your app signed in. - [Quick Start](https://docs.usethatapp.com/quickstart): The whole selling loop end to end: register your app, add /login and /callback, gate on the entitlement, create products and prices, render live prices and buy links on your site with get_prices and purchase_url, run the seller walkthrough, and go live. - [Hosting Provider](https://docs.usethatapp.com/hosting): Deploy the SDK as a server-side confidential client: store UTA_CLIENT_SECRET as a managed secret, set the client id and redirect URI, and register your production URLs — including the Login URL buyers return to after checkout. A separate marketing site needs no secrets at all. - [Error Handling](https://docs.usethatapp.com/error-handling): The UtaError hierarchy across sign-in, entitlements, and the purchase/pricing surface: UtaTokenError (401), UtaPermissionError (403), UtaError (404 from get_prices/get_app_info when external sales isn't enabled), UtaServerError (429/5xx, retriable), UtaAuthError, UtaConfigError, UtaDiscoveryError. - [Gotchas](https://docs.usethatapp.com/gotchas): Integration pitfalls across the loop: exact-match redirect URIs; server-side client secret (SPAs need a BFF); localhost vs 127.0.0.1; check the callback error param; reconcile on logout; gate on product_public_id; don't build payment webhooks (the entitlement is live immediately after purchase); never hardcode prices; purchase-link next URLs follow the domain rule. ## Authentication - [Sign in with UseThatApp](https://docs.usethatapp.com/openid-connect): The Hosted sign-in add-on: let UseThatApp run login so buyers return from hosted checkout — and marketplace users launch — through one OpenID Connect sign-in, arriving with a live entitlement. Optional; apps keeping their own auth use license keys instead. Sign-in itself is free and unmetered. Covers begin_login/complete_login, the pairwise sub, get_entitlement, logout, errors, and the dashboard setup. - [Authentication](https://docs.usethatapp.com/authentication): How identity works: UseThatApp signs users in over OpenID Connect, giving a pairwise pseudonymous sub (no PII). Your app owns accounts and roles, keyed on sub. ## Licensing - [Licensing](https://docs.usethatapp.com/licensing): How your app learns what a buyer purchased, in either verification mode. With the Hosted sign-in add-on a buyer is entitled the moment hosted checkout completes (no webhooks): read the live plan with get_entitlement, gate on the stable product_public_id, and offer the upgrade with purchase_url. Fields, every status (active, trialing, one_time_active, free, preview, none), errors including 403 service_not_enabled, and how license keys compare. - [License Keys](https://docs.usethatapp.com/license-keys): Verify purchases while keeping your own authentication: every purchase mints an opaque license key your server checks with validate_license_key / validateLicenseKey. Exchange the checkout redirect's uta_order reference for the key with get_order / getOrder, revoke a compromised key with regenerate_license_key, and gate on product_public_id. Configure with UTA_CLIENT_ID and UTA_CLIENT_SECRET; included in the base per-sale fee. ## Purchase Support - [Sell from your own website](https://docs.usethatapp.com/purchase/sell-from-your-website): Market and sell your app from your own site while UseThatApp stays merchant of record: render live prices (getPrices or browser fetch), link Buy buttons to hosted checkout (purchase_url / buy_url), and the buyer returns to your app signed in with a live entitlement. - [Purchase links](https://docs.usethatapp.com/purchase/links): Reference for hosted buy links — https://www.usethatapp.com/buy/{price_id}/ — and the SDK builders purchase_url / purchaseUrl and manage_url / manageUrl: next, ref, and email params, validation rules, default return via your Login URL, already-licensed behavior, the receipt email, and the beta flag. - [Pricing API](https://docs.usethatapp.com/purchase/pricing-api): Live prices for your pricing page: the SDK's get_prices / getPrices and get_app_info / getAppInfo, or the public CORS-enabled endpoints GET /api/v1/public/apps/{client_id}/ and /prices/. Each price carries a ready-made buy_url and the product_id that matches the entitlement's product_public_id — never hardcode prices. - [Test your purchase flow](https://docs.usethatapp.com/purchase/testing): Walkthrough mode: open your own buy link as the developer and run checkout with no Stripe calls and no charge — finishing sets the developer-preview entitlement (entitled: true, status "preview"). Includes the launch checklist. ## REST API - [REST API](https://docs.usethatapp.com/rest-api): The raw HTTP surface behind the merchant-of-record offering: /api/v1/ conventions, public app-profile and prices endpoints, the Bearer-authed entitlement endpoint (request, response, and errors), OIDC discovery, rate limits, and the live OpenAPI schema + Swagger UI — for stacks the SDKs don't cover. ## MCP - [MCP Server](https://docs.usethatapp.com/mcp): Connect Claude Code, Claude Desktop, or Cursor to UseThatApp's remote MCP server and let your AI agent manage your apps: OAuth integration settings, listing content (tagline, description, categories, detail sections, feature table, listing mode), and product descriptions — authorized with your own account, scoped to your own apps. ## Python - [Python Overview](https://docs.usethatapp.com/python): The usethatapp Python SDK: OpenID Connect sign-in (begin_login/complete_login), live entitlements (get_entitlement), license key verification (validate_license_key, get_order, regenerate_license_key), and the purchase surface (purchase_url, manage_url, get_prices, get_app_info). Server-side, confidential client. - [Flask](https://docs.usethatapp.com/python/flask): Sign users in with /login and /callback, gate features with get_entitlement, and offer the upgrade with purchase_url / manage_url when the check says free tier. - [Django](https://docs.usethatapp.com/python/django): OIDC views and URLconf: begin_login / complete_login, get_entitlement, configured from Django settings; gate on product_public_id and offer the upgrade with purchase_url. - [FastAPI](https://docs.usethatapp.com/python/fastapi): Async OpenID Connect: Starlette SessionMiddleware, complete_login in the callback, get_entitlement_async on the hot path, and purchase_url / get_prices_async for the upgrade path. - [Dash](https://docs.usethatapp.com/python/dash): Add the OIDC routes (/login, /callback, /logout) to the underlying Flask server (app.server), read the entitlement inside a Dash callback, and render the upgrade CTA with purchase_url. - [Streamlit](https://docs.usethatapp.com/python/streamlit): Backend-for-frontend pattern — a small Flask/FastAPI companion server owns the OIDC flow, exposes the entitlement, and builds purchase/manage URLs the Streamlit app renders. ## JavaScript - [JavaScript Overview](https://docs.usethatapp.com/javascript): The usethatapp npm package: a server-side, confidential client for sign-in (beginLogin/completeLogin), entitlements (getEntitlement), license key verification (validateLicenseKey, getOrder, regenerateLicenseKey), and the purchase surface (purchaseUrl, manageUrl, getPrices, getAppInfo). Browser SPAs use a backend-for-frontend. - [Express](https://docs.usethatapp.com/javascript/express): Sign users in with /login and /callback, gate with getEntitlement, and offer the upgrade with purchaseUrl / manageUrl — express-session for the server session. - [Node.js](https://docs.usethatapp.com/javascript/nodejs): Plain node:http confidential client — /login, /callback, /logout, getEntitlement with a small cookie session, and an /account branch offering purchaseUrl / manageUrl. - [Fastify](https://docs.usethatapp.com/javascript/fastify): Fastify routes for OIDC sign-in, entitlement gating, and the purchaseUrl / manageUrl upgrade path, using @fastify/cookie and @fastify/session. - [Next.js](https://docs.usethatapp.com/javascript/nextjs): Run the SDK in App Router Route Handlers (server-only): /api/login, /api/callback, /api/logout, /api/entitlement, and an /api/upgrade redirect built with purchaseUrl / manageUrl, with an iron-session cookie. - [Nuxt](https://docs.usethatapp.com/javascript/nuxt): Run the SDK in Nitro server routes (server/api/*), including an upgrade redirect via purchaseUrl / manageUrl; the Vue app calls them via useFetch. - [React](https://docs.usethatapp.com/javascript/react): A React SPA with a backend-for-frontend that runs the SDK; the browser calls /api/entitlement and renders upgrade/manage links from /api/upgrade-url. The client secret never reaches the bundle. - [Vue](https://docs.usethatapp.com/javascript/vue): A Vue SPA with a backend-for-frontend that runs the SDK; the browser calls /api/entitlement and renders upgrade/manage links from /api/upgrade-url. The client secret stays server-side. ## Optional - [Full documentation text](https://docs.usethatapp.com/llms-full.txt): Every page above as a single plain-text Markdown file.