@tiun/sdk
Version:
tiun SDK for payments and subscriptions
381 lines (275 loc) • 13.3 kB
Markdown
# tiun SDK
The tiun SDK provides a simple API for integrating payments, subscriptions, and authentication into any website or app.
---
## Installation
```bash
npm install @tiun/sdk
```
---
## Quick Start
```typescript
import { tiun } from '@tiun/sdk';
tiun.init({
snippetId: 'your-snippet-id',
language: 'en', // set to your site's language
});
// Subscription checkout for a specific product
tiun.checkout({ productId: 'prod_monthly' });
// Time-based connect flow
tiun.start();
```
> **Set `language` to match your site.** If omitted, the snippet UI defaults to `'en'`. See all supported codes in the [Init options](#init-options) table below.
The snippet is loaded automatically from the backend when you call `tiun.init()` with a `snippetId`. No script tags or extra HTML are required.
---
## Configuration
### `tiun.init(config)`
Initialize the SDK. Call once at app startup.
```typescript
tiun.init({
snippetId: 'your-snippet-id',
language: 'en', // set to your site's language
tone: 'formal',
debug: false,
sandbox: false,
// Lifecycle callbacks
onReady: () => {},
onPaywallShow: (data) => {},
onPaywallHide: (data) => {},
onError: (error) => {},
// Auth callbacks
onUserChange: (event) => {},
onLogin: (event) => {},
onLogout: () => {}
});
```
### Init options
| Option | Type | Default | Description |
| --------------- | ---------------------------------- | ---------- | ------------------------------------------------------------------ |
| `snippetId` | `string` | — | **Required.** Your unique tiun snippet ID from the dashboard. |
| `language` | `string` | `'en'` | Language for the snippet UI (e.g. `'en'`, `'de'`, `'fr'`). Set this to match your site; falls back to `'en'` if omitted. |
| `tone` | `'formal' \| 'informal'` | `'formal'` | UI tone/style. |
| `debug` | `boolean` | `false` | Enable console logging. |
| `sandbox` | `boolean` | `false` | Use sandbox base URL instead of production. |
| `onReady` | `() => void` | — | Called when snippet is ready. |
| `onPaywallShow` | `(data: PaywallShowEvent) => void` | — | Called when paywall should be shown. |
| `onPaywallHide` | `(data: PaywallHideEvent) => void` | — | Called when user has access. |
| `onUserChange` | `(data: UserChangeEvent) => void` | — | Called on every user state change (init, login, logout, checkout). |
| `onLogin` | `(data: LoginEvent) => void` | — | Called when user logs in. |
| `onLogout` | `() => void` | — | Called when user logs out. |
| `onError` | `(error: TiunError) => void` | — | Called on errors. |
---
## Authentication
tiun provides built-in passwordless authentication (OTP via SMS/email). Users authenticate once during checkout, and their session persists across visits.
### `tiun.login()`
Open the login modal for returning subscribers.
```typescript
tiun.login();
```
### `tiun.logout()`
Log the user out and clear the session.
```typescript
tiun.logout();
```
### `tiun.getUser()`
Returns the cached user state synchronously.
```typescript
const { isAuthenticated, user } = tiun.getUser();
if (isAuthenticated) {
console.log('Logged in as', user.email);
console.log('Product access:', user.productAccess);
}
```
Returns `GetUserResponse`:
| Property | Type | Description |
| ----------------- | ------------------ | ----------------------------------------- |
| `isAuthenticated` | `boolean` | Whether the user has an active session. |
| `user` | `UserInfo \| null` | User details, or `null` if not logged in. |
### `UserInfo`
| Property | Type | Description |
| --------------- | ---------- | ------------------------------------------- |
| `userId` | `string` | Unique user identifier. |
| `email` | `string` | User's email address. |
| `productAccess` | `string[]` | List of product IDs the user has access to. |
### `tiun.getUserVerificationToken()`
Returns a secure token that can be used for server-to-server user verification. The token is valid for 5 minutes. Returns `null` if the user is not authenticated.
```typescript
const token = await tiun.getUserVerificationToken();
```
Your backend can verify the token using your tiun API key from the business dashboard.
---
## Start & Checkout
tiun supports two flows:
- **Subscription checkout** (`checkout`) -- Opens the checkout flow for a specific product. Requires a `productId`.
- **Time-based connect** (`start`) -- Opens the connect flow without a specific product. Used for time-based access models.
### `tiun.checkout(options)`
Open the subscription checkout flow for a specific product.
```typescript
tiun.checkout({ productId: 'prod_monthly' });
```
| Option | Type | Description |
| ----------- | -------- | ----------------------------------------------------- |
| `productId` | `string` | The product ID to checkout. From your tiun dashboard. |
---
### `tiun.start()`
Open the time-based connect flow.
```typescript
tiun.start();
```
## Events
Subscribe with `tiun.on()`. Returns an unsubscribe function.
### `ready`
Fired when the snippet has initialized and is ready to use.
```typescript
tiun.on('ready', () => {
console.log('tiun is ready');
});
```
### `userChange`
Fired on every user state change -- initialization, login, logout, and checkout. This is the single event to track all user state transitions.
```typescript
tiun.on('userChange', (event) => {
console.log('Event:', event.event);
console.log('Authenticated:', event.isAuthenticated);
console.log('User:', event.user);
});
```
| Property | Type | Description |
| ----------------- | ------------------ | ---------------------------------------------------------------------------------------- |
| `event` | `string` | What triggered the change: `'init'`, `'login'`, `'logout'`, `'checkout'`, or `'update'`. |
| `isAuthenticated` | `boolean` | Whether the user is currently authenticated. |
| `user` | `UserInfo \| null` | User details, or `null`. |
### `login`
Fired specifically when a user logs in. Convenience event -- the same data is also available via `userChange`.
```typescript
tiun.on('login', (event) => {
console.log('Welcome back,', event.user.email);
});
```
| Property | Type | Description |
| -------- | ---------- | ------------- |
| `user` | `UserInfo` | User details. |
### `logout`
Fired when the user logs out.
```typescript
tiun.on('logout', () => {
console.log('User logged out');
});
```
### `error`
Fired when an error occurs.
```typescript
tiun.on('error', (error) => {
console.error('tiun error:', error.code, error.message);
});
```
| Property | Type | Description |
| --------- | --------- | ------------------------- |
| `code` | `string` | Error code. |
| `message` | `string` | Error message. |
| `details` | `unknown` | Additional error details. |
### All events
| Event | Description |
| ------------- | --------------------------------------------------------------------------------------------------- |
| `ready` | Snippet has initialized and is ready. |
| `userChange` | User state changed. Payload: `UserChangeEvent`. |
| `login` | User logged in. Payload: `LoginEvent`. |
| `logout` | User logged out. No payload. |
| `paywallShow` | Paywall should be shown (user doesn't have access). Payload: `{ isConnected: boolean }`. |
| `paywallHide` | Paywall should be hidden (user has access). Payload: `{ sessionId: string, isConnected: boolean }`. |
| `error` | An error occurred. Payload: `TiunError`. |
### Paywall events (payloads)
**paywallShow:** `{ isConnected: boolean }`
**paywallHide:** `{ sessionId: string, isConnected: boolean }`
### One-time and unsubscribe
```typescript
tiun.once('login', (event) => console.log('First login:', event.user.email));
const unsubscribe = tiun.on('userChange', () => {});
unsubscribe();
```
---
## Properties
| Property | Type | Description |
| ---------------------- | ------------------ | ---------------------------------------------- |
| `tiun.version` | `string` | SDK version. |
| `tiun.isInitialized` | `boolean` | Whether `init()` has been called. |
| `tiun.isReady` | `boolean` | Whether the snippet is ready. |
| `tiun.isAuthenticated` | `boolean` | Whether the user has a valid session. |
| `tiun.user` | `UserInfo \| null` | Current user info, or `null` if not logged in. |
---
## Methods
| Method | Description |
| --------------------------------- | ----------------------------------------------------------- |
| `tiun.init(config)` | Initialize the SDK. Call once at startup. |
| `tiun.start()` | Open the time-based connect flow. |
| `tiun.checkout(options)` | Open the subscription checkout flow for a specific product. |
| `tiun.login()` | Open the login modal for returning subscribers. |
| `tiun.logout()` | Log the user out and clear the session. |
| `tiun.getUser()` | Get cached user state (synchronous). |
| `tiun.getUserVerificationToken()` | Get a secure token for server-to-server verification. |
| `tiun.setContent(options)` | Update the current content context. |
| `tiun.on(event, callback)` | Subscribe to an event. Returns unsubscribe function. |
| `tiun.once(event, callback)` | Subscribe to an event once. Returns unsubscribe function. |
| `tiun.destroy()` | Destroy the SDK and clean up listeners. |
| `tiun.waitForReady()` | Wait for the SDK to be ready. Returns a Promise. |
### `tiun.setContent(options)`
Tell tiun what content the user is viewing.
```typescript
tiun.setContent({
type: 'active',
contentId: 'episode-123',
mediaType: 'audio'
});
```
| Option | Type | Description |
| ----------- | ------------------------------------ | ---------------------------------- |
| `type` | `'active' \| 'inactive' \| 'paused'` | **Required.** Content state. |
| `contentId` | `string` | Unique identifier for the content. |
| `mediaType` | `'text' \| 'audio' \| 'video'` | Type of media. Default: `'text'`. |
---
## Framework examples
### Vue
```vue
<script setup lang="ts">
import { tiun } from '@tiun/sdk';
import { onMounted, onUnmounted } from 'vue';
onMounted(() => {
tiun.init({ snippetId: 'your-snippet-id', language: 'en' });
});
onUnmounted(() => {
tiun.destroy();
});
</script>
<template>
<button @click="tiun.checkout({ productId: 'prod_monthly' })">
Subscribe
</button>
</template>
```
### React
```tsx
import { tiun } from '@tiun/sdk';
import { useEffect } from 'react';
function App() {
useEffect(() => {
tiun.init({ snippetId: 'your-snippet-id', language: 'en' });
return () => tiun.destroy();
}, []);
return (
<div>
<button onClick={() => tiun.checkout({ productId: 'prod_monthly' })}>
Subscribe
</button>
</div>
);
}
```
### Vanilla JS
```html
<script src="https://cdn.tiun.io/sdk.js"></script>
<script>
tiun.init({ snippetId: 'your-snippet-id', language: 'en' });
</script>
<button onclick="tiun.checkout({ productId: 'prod_monthly' })">
Subscribe
</button>
```