UseThatApp Logo

    Pricing API

    Two public, read-only endpoints that let your website render your app's profile and live prices — no auth, no API key, CORS-enabled, callable straight from the browser. Every price carries a ready-made buy_url, so your pricing page and your Buy buttons stay correct the moment you edit a price on the dashboard.

    Never hardcode prices

    Render prices from this API instead of hardcoding amounts that drift the moment you change a price, and use the returned buy_url for your Buy buttons instead of assembling checkout URLs yourself.

    App profile

    request
    GET https://www.usethatapp.com/api/v1/public/apps/{client_id}/

    client_id is your app's public OAuth client id, from the dashboard's Integration page — the same identifier your OIDC integration already uses.

    response
    {
      "client_id": "AbC123dEf456...",
      "name": "Acme Analytics",
      "tagline": "Dashboards your team actually reads",
      "listing_mode": "external",
      "url": "https://acmeanalytics.com",
      "marketplace_url": "https://www.usethatapp.com/apps/acme-analytics/"
    }

    listing_mode is "marketplace" (the app has a full product page on usethatapp.com) or "external" (the app still appears in UseThatApp search, but its card links out to your own registered website). You can change it from the dashboard or via the MCP update_app_listing tool — see MCP Server.

    Prices

    request
    GET https://www.usethatapp.com/api/v1/public/apps/{client_id}/prices/
    response
    {
      "client_id": "AbC123dEf456...",
      "app_name": "Acme Analytics",
      "has_free_tier": true,
      "prices": [
        {
          "public_id": "prc_9f2kq8w7",
          "product_id": "prod_9XkKe2QGxN4Ttz1Rw7Ya",
          "product_name": "Pro",
          "amount": "10.00",
          "currency": "usd",
          "is_recurring": true,
          "frequency": "month",
          "buy_url": "https://www.usethatapp.com/buy/prc_9f2kq8w7/"
        },
        {
          "public_id": "prc_x4n7d2mk",
          "product_id": "prod_Vt3mPa8LqZc5Ryw2Kd0B",
          "product_name": "Lifetime",
          "amount": "199.00",
          "currency": "usd",
          "is_recurring": false,
          "frequency": null,
          "buy_url": "https://www.usethatapp.com/buy/prc_x4n7d2mk/"
        }
      ]
    }
    FieldMeaning
    public_idOpaque price identifier (prefix prc_) — the id inside buy links.
    product_idThe product this price belongs to (prod_…). Matches product_public_id from the entitlement endpoint, so gate your features on it — the plan bought is the plan you unlock. (The entitlement's own product_id carries the same value — the fields are equal-valued aliases.) See Licensing.
    amount / currencyDecimal string (e.g. "10.00") and lowercase ISO currency code (e.g. "usd").
    is_recurring / frequencyBilling interval for recurring prices: "day", "week", "month", or "year"; frequency is null for one-time prices.
    buy_urlReady-made hosted checkout link for this price — use it as your Buy button's href.
    has_free_tierTrue when the app offers a free product. Free tiers have no price rows, so render your "Free" column from this flag.

    Call it with the SDK

    On a server, prefer the SDK — it wraps both endpoints with typed results (AppInfo, AppPrices with Price / UtaPrice entries) and needs only UTA_CLIENT_ID, no OAuth secrets:

    Python

    server-side
    from usethatapp import get_app_info, get_prices
    
    info = get_app_info()      # AppInfo(name, tagline, listing_mode, ...)
    plans = get_prices()       # AppPrices(..., has_free_tier, prices)
    for p in plans.prices:
        render_plan(p)         # p.buy_url is your Buy button href
    # async variants: get_app_info_async(), get_prices_async()

    JavaScript

    server-side
    import { getAppInfo, getPrices } from "usethatapp";
    
    const info = await getAppInfo();   // { name, tagline, listing_mode, ... }
    const { prices, has_free_tier } = await getPrices();
    for (const p of prices) {
      renderPlan(p);                   // p.buy_url is your Buy button href
    }

    Error mapping: 404 raises a plain UtaError (app unknown, unpublished, or external sales not enabled yet); 429 and 5xx raise UtaServerError (retriable). See Error Handling.

    Call it from the browser

    Because the endpoints are CORS-enabled, a static marketing page with no server at all can fetch them directly:

    browser
    const CLIENT_ID = "<your-client-id>";
    const res = await fetch(
      `https://www.usethatapp.com/api/v1/public/apps/${CLIENT_ID}/prices/`
    );
    const { prices, has_free_tier } = await res.json();
    // render prices → each price's buy_url is your Buy button href

    Behavior notes

    • Visibility: both endpoints only resolve for published apps with external sales enabled — anything else is a 404 (indistinguishable from an unknown client_id).
    • Caching: responses send Cache-Control: public, max-age=60 — prices can change, so the public cache is kept short.
    • Rate limit: 120 requests/minute per IP; excess requests get 429.
    • CORS: Access-Control-Allow-Origin: * — call it from any origin, no proxy needed.
    • Auth: none. Everything here is public data; there are no secrets to leak from a browser call.

    Next steps

    See the full funnel in Sell from your own website, the link parameters in Purchase links, and the rest of the HTTP surface in the REST API reference.

    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.