Sell from your website
The whole integration, in order. Steps 1–3 and 5 are identical for every app. Step 4 depends on how your app verifies purchases: license keys (the default) or Hosted sign-in.
Before you start
- A seller account on usethatapp.com. Sellers must be based in the United States: payouts run through Stripe Connect, which asks for a US identity and bank account.
- The app, created on usethatapp.com (dashboard → List your app, or the MCP
create_apptool) with at least one version and price. A paid version is a product with aprod_…id; each of its prices has aprc_…id. - From Manage app → Integration: the app's
client_id(public) and client secret (shown once; keep it on your server).
1. Show live prices
Render your pricing page from the Pricing API. It is public, needs no key, and allows any origin, so a static page can call it from the browser. Never hardcode an amount: when a price changes on the dashboard, the API changes with it.
const CLIENT_ID = "<your-client-id>";
const res = await fetch(
`https://www.usethatapp.com/api/v1/public/apps/${CLIENT_ID}/prices/`
);
const { has_free_tier, prices } = await res.json();
for (const p of prices) {
// p.product_name, p.amount ("10.00"), p.currency ("usd"),
// p.frequency ("month" | "year" | "week" | "day" | null for one-time),
// p.trial_period_days (7 | 14 | 30 | null)
addPlan(p.product_name, p.amount, p.currency, p.frequency, p.buy_url);
}
if (has_free_tier) addFreePlan(); // free tiers have no price rowsOn a server, get_prices() / getPrices() returns the same data typed (trial_period_days is only in the untyped raw copy), and needs only UTA_CLIENT_ID. Every field is listed in the reference.
2. Link Buy buttons to checkout
Use each price's buy_url as the button's href. It has the form https://www.usethatapp.com/buy/{prc_id}/ and accepts three optional query parameters:
next— where the buyer returns after paying. It must be HTTPS on your app's registered domain (localhostis allowed in development). Without it, the buyer returns to the app's Login URL, or to the app's URL if no Login URL is set. In license-key mode, point it at the route that readsuta_order.ref— an affiliate's code. Forward one if an affiliate sent you the visitor; you never need your own. A plain link bills at the seller rate, an affiliate-referred sale at the platform rate (see pricing). The code is remembered for 60 days (last click wins) once the buyer accepts cookies; before that it is held for the visit only.email— prefills the buyer's email.
To add parameters, use purchase_url(price_id, next=…) / purchaseUrl(priceId, { next }): pure URL builders with no network call and no configuration.
When a buy link does not sell
A buy link sells only while all four hold: your seller account is verified, the app is published, the product is active, and external sales is on for the app (it is on by default; UseThatApp switches it off only to suspend an app's sales). The app's Manage page shows the four as a readiness list. While the seller is unverified, the app unpublished or the product inactive, the link shows the buyer a "not available" page (HTTP 200); it answers 404 only for an unknown price id or while external sales is off. The Pricing API answers 404 unless the app is published and external sales is on, and lists only active products.
Who can buy. Buyers in the United States, the European Union, Canada, Australia and the other countries offered at checkout. The country is checked against both the buyer's tax address and the card's billing country. EU consumers see VAT-inclusive prices; an EU business can enter a VAT number and is invoiced net under the reverse charge.
3. What the buyer sees
- One page for email, country and postal code. An email with an existing UseThatApp account signs in (including two-factor). A new email gets an account created on the spot, with no password and no verification step in the way.
- Card entry through Stripe, then a confirmation.
- A success page showing the license key, which then continues to your
nextURL withuta_order=…appended. - A receipt email with the license key, a link back to your app (also carrying
uta_order), an email-verification link, a set-a-password link for new accounts, and a link to manage the subscription.
A buyer who already holds any active plan of your app is not charged again: the link shows a "you already have access" page with a button back to next, and that return carries no uta_order (they already hold a key). Your return route must treat a missing uta_order as nothing to link. It is safe to show Buy buttons to everyone.
4. Verify the purchase
The license is created during checkout, before the redirect. Do not add webhooks, polling, or a "payment pending" state.
License keys (default). Your return route exchanges uta_order for the key once, stores it on the signed-in user, and every gate validates the stored key. Full detail: License keys.
from usethatapp import get_order, validate_license_key
# Return route: /thanks?uta_order=...
order = get_order(request.args["uta_order"])
current_user.license_key = order.license_key
save(current_user)
# Any gate:
state = validate_license_key(current_user.license_key)
if state.entitled and state.product_public_id == "prod_<pro-id>":
... # paid featureimport { getOrder, validateLicenseKey } from "usethatapp";
// Return route: /thanks?uta_order=...
const order = await getOrder(req.query.uta_order);
currentUser.licenseKey = order.license_key;
await save(currentUser);
// Any gate:
const state = await validateLicenseKey(currentUser.licenseKey);
if (state.entitled && state.product_public_id === "prod_<pro-id>") {
// paid feature
}Hosted sign-in. Leave next off. The buyer lands on your Login URL, which signs them in, and get_entitlement reports what they bought. Full detail: Hosted sign-in.
5. Link to subscription management
Put a "Manage subscription" link in your app's account settings. It opens the buyer's page for your app on usethatapp.com: change plan, cancel or resume auto-renew, update the card, see invoices, and re-view the license key.
https://www.usethatapp.com/manage/<client_id>/?next=https://yourapp.com/accountnext follows the same domain rule and becomes the page's "Back to your app" button. The SDK builder is manage_url(next=…) / manageUrl({ next }). Send existing customers here to upgrade: a buy link sends anyone who already holds a plan of your app back without charging them.
Free trials
- Any recurring price can carry a 7, 14 or 30-day trial, set per price on the Manage page (Versions & pricing) or through MCP
replace_versions. The Pricing API reports it astrial_period_days. - The buyer saves a card first and pays nothing until the trial ends. There is no fee or payout until the first paid invoice.
- One trial per buyer per app. A buyer who already had one is charged immediately, and checkout says so. Show the trial as offered and let checkout decide eligibility.
- Checkout states the terms ("Free for 14 days, then $9.00/month…"), and the buyer gets a reminder three days before the first charge. Keep your own pricing copy consistent with it; the seller terms require that.
- Your app sees
entitled: true,is_trial: true, andperiod_endset to the conversion date. Show a banner if you like; gate nothing extra. Conversion needs no action from you. - A plan change during a trial keeps the trial and its end date; a trial is never restarted or extended by switching plans. A buyer who cancels during the trial keeps access until
period_end. Affiliate commission, like the fee, starts at conversion.
Test before launch
Walkthrough. Sign in to usethatapp.com as the app's developer and open your own buy link. You see the buyer's pages with a test banner; nothing touches Stripe and nothing is charged. It proves the pages, your next URL, and the return into your app. It creates no license and no uta_order. With Hosted sign-in, it sets a developer-preview entitlement (status: "preview", the product's real prod_… id) so you can exercise your gates.
One real purchase. The walkthrough cannot test card processing, tax, the receipt email, or, in license-key mode, your get_order and validation code. Buy your cheapest price once from a second account, check the receipt and your gates, then cancel from that account's manage page and ask support@usethatapp.com for a refund. The platform fee is reversed with the refund.
Launch checklist
- The readiness list on the app's Manage page is complete.
- Your pricing page renders from the Pricing API; no amount is typed by hand.
- Every distinct buy link your site renders has been opened once (a bad
nextshows an error page). - License keys: the return route stores the key, even when the buyer must first sign in to your app. Hosted sign-in: the Login URL signs the buyer straight in.
- Gates check
entitledandproduct_public_id. - Account settings link to the manage page.
- One real purchase has gone through end to end and been refunded.
