From tiun-sdk
Use when integrating or debugging the tiun SDK (@tiun/sdk), tiun's JavaScript library for authentication, subscription billing, and time-based paywalls. Triggers on imports of `@tiun/sdk`, calls like `tiun.init`, `tiun.checkout`, `tiun.login`, `tiun.start`, or questions about tiun products, entitlements, time-based sessions, or server-side verification.
How this skill is triggered — by the user, by Claude, or both
Slash command
/tiun-sdk:tiun-sdkThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Use this skill whenever the user is integrating, extending, or debugging code that uses `@tiun/sdk`. Authoritative upstream docs: https://docs.tiun.io/llms-full.txt.
Use this skill whenever the user is integrating, extending, or debugging code that uses @tiun/sdk. Authoritative upstream docs: https://docs.tiun.io/llms-full.txt.
A commercial backend platform providing authentication, payments, and entitlements through a single JS SDK. The tiun singleton supports two flows; you pick based on the integrator's intent (see "Step 0 — Discovery before code"):
user.productAccess[]. Entry point: tiun.checkout({ productId }). See references/subscriptions.md.tiun.start() + paywallShow / paywallHide events. See references/time-based.md.Install: npm install @tiun/sdk. Init: tiun.init({ snippetId, language: 'en' }) on app start (idempotent).
tiun runs live and sandbox as two independent parallel environments. The SDK's sandbox flag selects which one — see references/installation.md.
Before writing any integration code, establish four things. Ask only for items the user has not already stated. If their prompt is fully specified ("wire up subscription with product p-test-pro in sandbox to gate /watch/*"), skip discovery.
Use a structured question primitive (e.g. AskQuestion) if your client supports one; otherwise ask inline in chat.
0a. Detect the MCP and offer to install if missing. See references/mcp.md for per-client install instructions and detection. Three states:
0b. Establish integration mode. Subscription, time-based, or both? See references/discovery.md for cues that map user language to each mode. Do not infer mode from get_products inventory. A provider with only one product type today may be planning the other tomorrow.
0c. Gather identifiers. Questions depend on mode and MCP availability:
snippetId; ask one product or multiple tiers; for each, ask productId and label; confirm sandbox or live (the p-test-... / p-live-... prefix is a strong hint).snippetId; confirm sandbox or live.When the MCP is present, ground questions in inventory ("you have a sandbox time-based product p-test-xxx — wire that up, or set up subscription products first?") rather than asking blind.
0d. Identify what to gate. Without this step the agent is generating boilerplate with no target. Ask:
| Task | Route to |
|---|---|
| Discovery, scoping, MCP detection, mode selection | references/discovery.md |
| MCP installation per client, detection, auth | references/mcp.md |
| What tiun is, supported platforms, product model | references/overview.md |
| Install / init / config / per-host env injection | references/installation.md |
| Method or property lookup | references/api-reference.md |
| Event names and payloads | references/events.md |
| Subscription gating (accounts + recurring billing) | references/subscriptions.md |
| Time-based paywall (per-session, anonymous, metered) | references/time-based.md |
| Trusted backend authorization | references/server-verification.md |
| Framework wiring (any stack) + lifecycle matrix | references/frameworks.md |
| "Overlay not appearing", SSR errors, sandbox mismatch | references/troubleshooting.md |
tiun.init({ snippetId, language }) runs on the client, early in startup. In Next.js/Nuxt, wrap in a client-only component/plugin. Never call it on the server. init is idempotent — calling it again merges config rather than re-initializing, so no isInitialized guard is needed.snippetId is not a secret. It identifies the environment. Use NEXT_PUBLIC_* / public runtime config.userChange is the source of truth for subscription gating, not a one-shot tiun.user read. Entitlements change mid-session. The payload includes event: 'init' | 'login' | 'checkout' | 'logout' | 'update' for cases where you need to know what triggered the change.tiun.getUserVerificationToken() returns a JWT (5-minute lifetime), send it to your backend, the backend validates it via POST /live_api/s2s/v1/users/verification with X-TIUN-API-KEY. For time-based, use the sessionId from paywallHide against PATCH /live_api/s2s/v1/sessions/{sessionId}/status. See references/server-verification.md.tiun.checkout({ productId }), tiun.login(), or tiun.start() to open them.ready may queue or no-op. Methods like checkout/login/start/setContent/logout already call ensureInitialized() and await this.waitForReady() internally — no need to wrap them.tiun.on(...) on component unmount to avoid stale listeners. Or call tiun.destroy() if the whole subtree is going away.p-live-... vs p-test-...), API keys, and API base URL (https://api.tiun.live vs https://api-sandbox.tiun.live). The SDK's sandbox flag must match the dashboard view and the product-ID prefix, or checkout silently fails. localhost is blocked in live and enabled by default in sandbox.my.tiun.business) and referenced by hardcoded productId strings. Do not invent methods like tiun.getProducts() or REST endpoints; direct users to the dashboard.getUserVerificationToken() or the sessionId from paywallHide. Do not invent webhook endpoints or event payloads.get_products inventory. Always confirm with the user (see "Step 0"). The list reports what exists; it does not report what the integrator wants to build.isInitialized / waitForReady guards. tiun.checkout, tiun.login, tiun.start, tiun.setContent, and tiun.logout already do both internally. Wrapper helpers around these methods are noise.baseUrl to init(). It is an internal-only field reserved for tiun's own infrastructure. Use sandbox: true for non-production environments; that is the only public environment switch. The SDK routes to the matching API host automatically.language is a closed enum: 'en' | 'de' | 'fr', case-insensitive. Unsupported values trigger a one-time console warning and fall back to 'en'. Do not generate other values.error.code. It's a string but there's no published enum; codes can change between SDK versions. Display err.message to users and log err.code for support..env.example is documentation and is never evaluated. Vite loads .env / .env.local; Next.js loads .env.local and requires the NEXT_PUBLIC_* prefix for client-exposed values; Nuxt loads via runtimeConfig.public in nuxt.config.ts. See references/installation.md for the per-host table.Three primitives — works in every supported environment. Adapt the reactive primitive (state hook, ref, signal, store, DOM update) to your stack.
import { tiun } from '@tiun/sdk';
tiun.init({ snippetId: 'YOUR_SNIPPET_ID', language: 'en' });
const off = tiun.on('userChange', ({ event, isAuthenticated, user }) => {
// push into your framework's reactive primitive
});
document.querySelector('#buy').onclick =
() => tiun.checkout({ productId: 'p-live-pro' });
// off(); tiun.destroy();
Full per-mode walkthroughs in references/subscriptions.md and references/time-based.md. Per-framework adaptations in references/frameworks.md.
gh skill install tiun-app/skills tiun-sdk quickstart in references/mcp.md.my.tiun.business; there is no runtime product-list API. (The MCP exposes inventory to the agent for setup; this is not a runtime SDK feature.)X-TIUN-API-KEY header; per-environment base URLs).localhost / "why won't it work locally" → confirm sandbox: true + sandbox snippet ID + p-test-... product IDs (live is hard-blocked on localhost).Provides CDSS development patterns for drug interaction checking, dose validation, clinical scoring (NEWS2, qSOFA), and alert classification integrated into EMR workflows.
npx claudepluginhub tiun-app/skills --plugin tiun-sdk