> ## Documentation Index
> Fetch the complete documentation index at: https://alguna.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# TypeScript SDK

> Official TypeScript SDK for the Alguna Public API: installation, authentication, resources, pagination, and error handling.

The official TypeScript SDK (`@alguna/sdk`) wraps the Alguna Public API with a fully typed client — customers, products, subscriptions, invoices, and payment links, with request and response types generated from the versioned OpenAPI specification.

<Note>
  The SDK is server-side only. API keys are secret — never ship them to a browser. For embedding a purchase flow in your frontend, use [Embedded Checkout](/docs/docs/hosted/embedded-checkout) (`@alguna/checkout-sdk`) instead: your server mints the session with this SDK's API key, your frontend mounts it.
</Note>

***

## How it works

1. **Create an API key** in your [dashboard](https://dashboard.alguna.io/settings/credentials) (format `id.secret` — a server secret).
2. **Instantiate the client** with the key. Every request it makes carries `Authorization: Bearer` and pins the API version via the `Alguna-Version` header.
3. **Call resources** (`alguna.customers`, `alguna.subscriptions`, …). Methods return typed response objects; failed requests throw typed errors.

## Installation

```bash theme={null}
npm install @alguna/sdk
# or
pnpm add @alguna/sdk
```

Requires Node.js 18 or later.

```typescript theme={null}
import { Alguna } from "@alguna/sdk";

const alguna = new Alguna({
  apiKey: process.env.ALGUNA_API_KEY,
  apiVersion: "2026-04-01", // required — pin the version you integrate against
});
```

***

## Quick start: customer → subscription → payment link

```typescript theme={null}
// 1. Create a customer
const customer = await alguna.customers.create({
  name: "Acme Corp",
  currency: "USD",
  contacts: [{ email: "billing@acme.com", is_primary: true }],
});

// 2. Create a product and start a subscription
const product = await alguna.products.create({
  name: "Platform Fee",
  fee_type: "fixed",
  billing_frequency: "recurring",
  payment_terms: "advance",
});

const subscription = await alguna.subscriptions.create({
  customer_id: customer.id,
  currency: "USD",
  items: [
    {
      product_id: product.id,
      price: {
        type: "fixed",
        fee_type: "fixed",
        billing_direction: "advance",
        billing_frequency: "recurring",
        billing_interval: "monthly",
        fixed_pricing_model: { price_per_unit: "99.00", units: 1 },
      },
    },
  ],
  contract: { period_type: "fixed", duration_months: 12, start_date: "2026-07-01" },
  auto_activate: true,
});

// 3. Issue a one-off invoice
const invoice = await alguna.invoices.create({
  customer_id: customer.id,
  currency: "USD",
  line_items: [{ description: "Onboarding", unit_price: "500.00", quantity: "1" }],
});

// 4. Generate a payment link (hosted customer portal session)
const session = await alguna.portal.createSession({ customer_id: customer.id });
console.log(session.url); // share with the customer; expires after 1 hour
```

<Note>
  Subscriptions are created in `draft` status. Pass `auto_activate: true` (as above) or call `alguna.subscriptions.activate(id)` when you are ready to go live. See [Creating a Subscription](/docs/docs/api-reference/v2/examples/creating-a-subscription) for the full set of patterns — plans, overrides, and bundles all work the same way through the SDK.
</Note>

***

## Resources

The SDK covers every public API operation, one field per resource. Highlights:

| Resource                                    | Methods                                                                                           |
| ------------------------------------------- | ------------------------------------------------------------------------------------------------- |
| `alguna.customers`                          | `create`, `get`, `list`, `update`, entitlements, connected accounts                               |
| `alguna.subscriptions`                      | `create`, `get`, `list`, `update`, `activate`, `cancel`, `delete`, credits, entitlements, revenue |
| `alguna.subscriptionVersions`               | `create`, `get`, `list`, `publish`, `replace`, `delete`                                           |
| `alguna.invoices`                           | `create`, `get`, `list`, `update`, `markAsPaid`, `void`, `generatePdf`, line items                |
| `alguna.portal` / `alguna.checkoutSessions` | payment links and checkout sessions                                                               |

Plus `products`, `plans`, `bundles`, `creditNotes`, `credits`, `wallets`, `walletGrants`, `metrics`, `events`, `payments`, `refunds`, `integrations`, `insights`, `revenueSchedules`, and `tax` — the resource layer is generated from the versioned spec, and generation enforces parity: it fails if any API operation is missing from the SDK.

Request and response types are exported from the package root:

```typescript theme={null}
import type { CreateCustomerRequest, InvoiceResponse } from "@alguna/sdk";
```

## Pagination & filtering

List endpoints accept `limit`, `offset`, `sort` (in `field:order` format), and the same filter parameters as the [HTTP API](/docs/docs/api-reference/v2/overview#filtering--sorting):

```typescript theme={null}
const { data, pagination } = await alguna.customers.list({
  limit: 50,
  offset: 0,
  sort: "name:asc",
});
// data: CustomerResponse[]
// pagination: { per_page, total_pages }
```

***

## Error handling

Failed requests throw typed errors, all extending `AlgunaError`:

```typescript theme={null}
import { NotFoundError, RateLimitError, ValidationError } from "@alguna/sdk";

try {
  await alguna.customers.get("nope");
} catch (error) {
  if (error instanceof NotFoundError) {
    // error.message, error.statusCode, error.requestId
  } else if (error instanceof RateLimitError) {
    // error.retryAfter — seconds to wait before retrying
  } else if (error instanceof ValidationError) {
    // error.fields — per-field validation messages
  }
}
```

| Error                 | Status | Extra fields |
| --------------------- | ------ | ------------ |
| `ValidationError`     | 400    | `fields`     |
| `AuthenticationError` | 401    |              |
| `NotFoundError`       | 404    | `resource`   |
| `RateLimitError`      | 429    | `retryAfter` |
| `ApiError`            | other  |              |

All errors expose `statusCode`, `code`, and `requestId`. Include the `requestId` when contacting support about a failed call.

***

## Idempotency

Mutating methods accept an optional trailing `options` argument. Pass `idempotencyKey` to make retries safe — the API returns the original result instead of repeating the action (see [Idempotency](/docs/docs/api-reference/v2/idempotency)):

```typescript theme={null}
await alguna.subscriptions.create(
  { customer_id: customer.id, plan_id: "plan_abc123", auto_activate: true },
  { idempotencyKey: "order_1234" },
);
```

***

## Configuration

```typescript theme={null}
const alguna = new Alguna({
  apiKey: "key_id.key_secret",           // required
  apiVersion: "2026-04-01",              // required — pins the Alguna-Version header
  baseUrl: "https://api.alguna.io/beta", // optional — the default
  timeout: 30_000,                       // optional — request timeout in ms
});
```

`apiVersion` is required: pin the version your integration is written against, so upgrading the SDK package never silently moves you to a different API version — see [Versioning](/docs/docs/api-reference/v2/overview#versioning).

***

## FAQ

**Can I use the SDK in the browser?**
No. It authenticates with your secret API key. For browser purchase flows, mint a checkout session server-side and mount it with [Embedded Checkout](/docs/docs/hosted/embedded-checkout).

**Does the SDK cover every endpoint?**
Yes. The resource layer is generated from the versioned OpenAPI spec, and generation fails if any operation in the [API reference](/docs/docs/api-reference/v2/overview) is missing from the SDK.

**How do I point it at a sandbox or local environment?**
Pass `baseUrl` — for example `http://localhost:4000/beta`. Everything else works identically.

**What happens on rate limits?**
The SDK throws `RateLimitError` with `retryAfter` (seconds). It does not retry automatically — wrap calls in your own retry logic if you need it.
