Skip to Content
SDK v3newQuickstart

Quickstart — zero to paywall in 5 minutes

SDK 3.0 covers three scenarios with one npm package: a modal in the browser, popup/content-script in a Chrome extension, and headless calls from a server. All three share one paywallId — you don’t need separate paywalls per channel.

Using an AI coding agent? Feed it llms-sdk-v3.txt — a single-file pack with the full SDK 3.0 API and integration patterns. Cursor, Claude Code, Copilot and the like produce far more accurate code with it in context.

Before you start

  1. A paywall is created in the dashboard → “Paywalls” → “New Paywall”. Remember the paywallId (the number in the URL).
  2. At least one payment processor is connected (Stripe / Paddle / Chargebee / Freemius).
  3. If you’ll be using the API Gateway (metered AI calls) — also have a providerId (UUID from the “API Providers” section in the dashboard).

apiOrigin for every example is https://YOUR_DOMAIN. If you have a custom domain, substitute yours.

Pick a scenario

Three integration paths — pick by how much UI you want to own and where your auth lives. See Overview for a side-by-side comparison.

Drop-in PaywallUI — Web / SPA

Install the npm package, open the paywall with one line, listen for checkout success. Ready-made modal in a Shadow DOM with built-in email / OTP / OAuth login.

Install

pnpm add @monetize.software/sdk # or: npm i @monetize.software/sdk

Initialize

import { PaywallUI } from '@monetize.software/sdk/ui'; const paywall = new PaywallUI({ paywallId: '3', apiOrigin: 'https://YOUR_DOMAIN', auth: true // turns on built-in email / OTP / OAuth login });

auth: true is enough for most integrations — the SDK creates an AuthClient itself, persists the session, refreshes tokens. If you already have your own AuthClient (or want a hybrid identity), pass identity or auth: <AuthClient> explicitly.

Open the paywall

document.getElementById('upgrade-btn').addEventListener('click', () => { paywall.open(); });

Already rendering your own pricing cards and want the click to skip the plan-picker step? Use paywall.checkout(priceId) — the modal still handles preauth signin, popup-blocked retry, and the awaiting-payment screen:

document.querySelectorAll<HTMLButtonElement>('[data-price-id]').forEach((el) => { el.addEventListener('click', () => paywall.checkout(el.dataset.priceId!)); });

React to the purchase

paywall.on('purchase_completed', ({ priceId, sessionId }) => { // update user state, unlock the feature }); paywall.on('close', () => { // user closed the modal without buying }); paywall.on('error', (err) => { console.error('paywall error', err); });

Full event list — in the PaywallUI API.

What’s next: BillingClient — when you need prices and user state before opening the modal. Authentication — customising the login flow.

What all scenarios have in common

  • One paywallId across drop-in / custom UI / headless — switch paths without migrating data.
  • One apiOrigin (or one custom domain), or none at all for pure headless.
  • Unified auth modelAuthClient behaves the same way in browser scenarios; headless uses apiKey + identity and gets the same outcome on the backend.
  • Identical event signaturespurchase_completed, authChange, userChange have the same shape whether you’re listening from PaywallUI, BillingClient, or webhooks.

Next steps