For the complete documentation index, see llms.txt. This page is also available as Markdown.

Sell one-time products

This guide walks through wiring up a one-time purchase — a buy button, checkout, and gating content once the user has paid. Login and logout are not covered here; see authenticating your user for those.

One-time products use the same SDK call as subscriptions. The difference is what happens afterwards: the customer pays a single fixed fee and keeps access permanently, so there's no renewal or expiration for your app to handle.


1. Create a one-time product

In the dashboard, create a product with the One-time Purchase pricing model and set its Fixed fee — the single amount charged at checkout. The full walkthrough is in creating your first product; copy the product ID when you're done.


2. Install and initialize the SDK

Install @tiun/sdk and call tiun.init once at app startup. The Quickstart has the full install commands.

import { tiun } from '@tiun/sdk';

tiun.init({
  snippetId: 'YOUR_SNIPPET_ID',
  language: 'en',
});

3. Add a buy button

Keep product IDs in one place so buy buttons, gating logic, and analytics all reference the same source. The JS will throw on typos instead of failing silently.

Wire the button to tiun.checkout() with the matching product ID:

When the user clicks, tiun opens the checkout overlay — it shows the fixed fee, collects their email, handles identity verification, processes the payment, and grants access in one flow. For what the overlay does behind the scenes, see Checkout / How it works in Reference.


4. Handle checkout success

After a successful purchase, userChange fires with event: 'checkout'. The user object includes their email and a productAccess array containing the product they just bought.

That product ID stays in productAccess permanently — one-time purchases don't renew and don't expire, so your gate never has to handle revocation for them. See One-time purchases in Reference for the full lifecycle.


5. Gate content based on access

Use the productAccess array to decide what to show. The same userChange handler covers checkout success, login, logout, and the initial session restore on page load — so your gates stay in sync without extra work.

Use the same check to hide or disable the buy button once the customer owns the product. They can't buy it a second time — checkout links their existing entitlement and shows an "already purchased" screen instead of charging — so a live buy button only sends a paying customer somewhere that can't do anything for them. See One-time purchases in Reference.


6. Add login and logout

Returning customers need to sign in to get their purchase back on a new browser or after logging out. The setup is covered in authenticating your user — once that's wired up, the same userChange handler picks up their existing productAccess.

Because a one-time purchase never expires, login is the only thing standing between a returning customer and the content they paid for. Make sure a Log in affordance is visible on your sales page, not just a buy button — otherwise a returning customer's only visible option is to pay again.


7. Go live

If you've been testing in sandbox, set up live as a separate environment in the dashboard, then for production traffic:

  1. Remove sandbox: true from your tiun.init (or set it to false).

  2. Use your live snippet ID and live product IDs (prefixed p-live-).

  3. If you verify server-side, switch to the live API base URL and a live API key.

See setting up your environment for the full sandbox / live workflow.


Full example

The one-time purchase integration in one place (login / logout wiring lives in the Auth guide):


For framework-specific implementations, see React, Vue, and Nuxt in the SDK reference.

If your backend needs to verify the purchase before serving protected data, use the same productAccess-based check documented in verifying purchases server-side.

Last updated

Was this helpful?