npm package: @synko-lab/paymints
Description: Browser SDK for Paymints subscription management
Author: Synko Lab
Latest version: 0.2.0

# @synko-lab/paymints

Minimal, ESM-only, tree-shakeable utilities for integrating Paymints into browser frontends.

## Installation

```bash
npm install @synko-lab/paymints
# or
pnpm add @synko-lab/paymints
# or
yarn add @synko-lab/paymints
```

## Quick Start

### 1. Initialize

Initialize the library with your public API key before using any other functionality. This is typically done at the root of your application (e.g., in `App.tsx` or `main.ts`).

```typescript
import { config } from "@synko-lab/paymints";

config.init({
  key: "pmts.your_public_key",
});
```

### 2. Launch Checkout

Redirect the user to a hosted checkout page to subscribe to a plan. This function creates a checkout session and automatically handles the browser redirect.

```typescript
import { subscription } from "@synko-lab/paymints";

async function handleSubscribe() {
  try {
    await subscription.launchCheckout({
      customerReference: "user_123456", // Required: unique ID of the user
      customerName: "John Doe", // Optional: customer's name
      customerEmail: "john@example.com", // Optional: customer's email
      priceId: "price_xxxxx", // Optional: specific plan/variant ID
      successUrl: "https://myapp.com/success", // Optional: redirect after success
      cancelUrl: "https://myapp.com/cancel", // Optional: redirect if cancelled
    });
  } catch (error) {
    console.error("Failed to launch checkout:", error);
  }
}
```

### 3. Check Subscription Status

Check if a specific customer has an active subscription.

```typescript
import { subscription } from "@synko-lab/paymints";

async function checkUserSubscription() {
  try {
    const result = await subscription.checkStatus({
      customerReference: "user_123456",
    });

    if (result.hasActiveSubscription) {
      console.log("Project:", result.projectName);
      console.log("Product:", result.subscription?.productName);
      console.log("Plan:", result.subscription?.planName);
      console.log("Variant:", result.subscription?.variantName);
      console.log("Status:", result.subscription?.status);
      console.log(
        "Amount:",
        result.subscription?.amount,
        result.subscription?.currency
      );
    } else {
      console.log("No active subscription found.");
    }
  } catch (error) {
    console.error("Failed to check status:", error);
  }
}
```

## Advanced: Multiple Pricing Options

### ⚠️ Important Note on Backward Compatibility

The `availableVariants` field in `checkStatus()` response is **completely optional to use**:

- ✅ **No changes required** if you already use a hardcoded/default priceId
- ✅ **100% backward compatible** - existing code continues working
- ✅ **Use variants only** if you want to offer multiple pricing options to users

### Example: Displaying Available Plans

```typescript
import { subscription } from "@synko-lab/paymints";

async function showAvailablePlans() {
  const result = await subscription.checkStatus({
    customerReference: "user_123456",
  });

  // Display available pricing options
  result.availableVariants.forEach((product) => {
    console.log(`\n📦 ${product.productName}`);

    product.variants.forEach((variant) => {
      const price = (variant.price / 100).toFixed(2);
      const isCurrentPlan =
        result.subscription?.variantId === variant.variantId;

      console.log(
        `${isCurrentPlan ? "✓" : " "} ${variant.name}: $${price} ${
          variant.currency
        }/${variant.interval}`
      );
    });
  });
}
```

### Example: User Selects a Plan

```typescript
async function handlePlanSelection(selectedVariantId: string) {
  // Send the selected variantId as priceId to the backend
  await subscription.launchCheckout({
    customerReference: "user_123456",
    customerEmail: "user@example.com",
    priceId: selectedVariantId, // 👈 Send selected variant
    successUrl: "https://myapp.com/success",
    cancelUrl: "https://myapp.com/cancel",
  });
}

// Complete example: Display plans and subscribe
async function showPlansAndSubscribe() {
  const result = await subscription.checkStatus({
    customerReference: "user_123456",
  });

  // User selects a variant from the UI
  const selectedVariant = result.availableVariants[0].variants[0];

  // Use the variantId as priceId in checkout
  await subscription.launchCheckout({
    customerReference: "user_123456",
    customerEmail: "user@example.com",
    priceId: selectedVariant.variantId,
    successUrl: "https://myapp.com/success",
    cancelUrl: "https://myapp.com/cancel",
  });
}
```

> **Note:**
>
> - If `priceId` is provided, the backend will use that specific variant
> - If `priceId` is omitted, the backend will use the default plan configured in your project

## API Reference

### `config`

#### `init(config: PaymintsConfig): void`

Initializes the Paymints SDK.

- **key** (required): Your Paymints public API key. Must start with `pmts.`.
- **baseUrl** (optional): Override the default API URL.

### `subscription`

#### `launchCheckout(params: CreateCheckoutParams): Promise<void>`

Creates a checkout session and automatically redirects the browser to the payment page.

- **customerReference** (required): A unique identifier for the customer in your system.
- **customerName** (optional): Customer's name.
- **customerEmail** (optional): Customer's email address.
- **priceId** (optional): Specific variant/price ID to use. If not provided, uses the default plan configured in your project.
- **successUrl** (optional): URL to redirect after successful payment (defaults to current origin).
- **cancelUrl** (optional): URL to redirect if payment is cancelled (defaults to current origin).

#### `checkStatus(params: CheckSubscriptionParams): Promise<SubscriptionCheckResponse>`

Checks the subscription status for a customer. Returns subscription details and available pricing variants.

- **customerReference** (required): The unique identifier for the customer.

**Response includes:**

- `hasActiveSubscription`: Boolean indicating if customer has active subscription
- `subscription`: Current subscription details (or null)
- `availableVariants`: Array of products with their pricing variants (optional to use)

### Types

The package exports the following TypeScript interfaces for better type safety:

- `PaymintsConfig`
- `CreateCheckoutParams`
- `CheckSubscriptionParams`
- `CheckoutResponse`
- `SubscriptionCheckResponse`
- `ProductVariant`
- `ProductWithVariants`

### Error Classes

The package exports custom error classes for specific error scenarios:

- `PaymintsError` - Base error class
- `PaymintsInitError` - Thrown when SDK is not initialized
- `PaymintsNetworkError` - Thrown when API requests fail
- `PaymintsValidationError` - Thrown when validation fails

## Features

- ✅ **ESM-only**: Modern, tree-shakeable module format
- ✅ **TypeScript**: Full type safety with exported interfaces
- ✅ **Zero dependencies**: Lightweight and minimal
- ✅ **Browser-first**: Designed for frontend applications
- ✅ **Auto-redirect**: Seamless checkout flow
- ✅ **Error handling**: Custom error classes for better debugging
- ✅ **Multiple pricing options**: Optional support for displaying variants
- ✅ **100% backward compatible**: No breaking changes

## License

MIT