> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.simjuno.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.simjuno.com/_mcp/server.

# TypeScript SDK

> Install and use the SimJuno TypeScript SDK.

The SimJuno TypeScript SDK provides typed access to the reseller and eSIM APIs from TypeScript or JavaScript. It includes authentication, retries, timeouts, error types, and request and response types.

The package is available as [`simjuno` on npm](https://www.npmjs.com/package/simjuno), and its source is available on [GitHub](https://github.com/SimJuno-com/typescript-sdk).

## Install

```bash
npm install simjuno
```

The SDK supports Node.js 18+, Bun 1.0+, Deno 1.25+, Cloudflare Workers, Vercel, and React Native.

## Create a client

Create an [API key](/authentication), store it in `SIMJUNO_API_KEY`, and initialize the client. Keep the key in server-side code; do not expose it in a browser or mobile application.

```typescript
import { SimjunoApiClient } from "simjuno";

const apiKey = process.env.SIMJUNO_API_KEY;
if (!apiKey) throw new Error("SIMJUNO_API_KEY is required");

const client = new SimjunoApiClient({ apiKey });

const { balance } = await client.reseller.balance();
console.log(`Balance: $${balance / 10_000}`);
```

The SDK uses `https://api.simjuno.com/v1` by default and sends the API key in the `x-api-key` header.

## Work with eSIMs

The SDK follows the standard [SimJuno integration flow](/#simjuno-integration-flow). This example finds a plan, confirms its current details, and places an order:

```typescript
import { randomUUID } from "node:crypto";

const { packages } = await client.esim.listPackages({ slug: "spain" });
const selectedPackage = packages[0];
if (!selectedPackage) throw new Error("No packages found");

const currentPackage = await client.esim.getPackage({
  slug: selectedPackage.slug,
});

const { esim_ids } = await client.esim.orderEsim({
  transaction_id: randomUUID(),
  orderList: [{ slug: currentPackage.slug, count: 1 }],
});
```

Ordering eSIMs debits your reseller balance. If you retry the same order, reuse both its `transaction_id` and `orderList`.

After receiving the [`ORDER_STATUS` webhook](/webhook#order-status), retrieve the provisioning details for each returned eSIM ID:

```typescript
const [esimId] = esim_ids;
if (!esimId) throw new Error("The order returned no eSIM IDs");

const esim = await client.esim.getEsim({ id: esimId });
console.log(esim.qrCodeUrl, esim.shortUrl, esim.ac);
```

### Available methods

| Task                         | Method                                    |
| ---------------------------- | ----------------------------------------- |
| Get reseller balance         | `client.reseller.balance()`               |
| List destinations            | `client.esim.listDestinations()`          |
| List plans for a destination | `client.esim.listPackages({ slug })`      |
| Get current plan details     | `client.esim.getPackage({ slug })`        |
| Order eSIMs                  | `client.esim.orderEsim(request)`          |
| List ordered eSIMs           | `client.esim.listEsims()`                 |
| Get an eSIM                  | `client.esim.getEsim({ id })`             |
| Get current usage            | `client.esim.checkUsage({ id })`          |
| List top-up plans            | `client.esim.listTopupPackages({ slug })` |
| Cancel an eligible eSIM      | `client.esim.cancelEsim({ id })`          |

## Handle errors

Non-success responses throw `SimjunoApiError` or one of its status-specific subclasses:

```typescript
import { SimjunoApiError } from "simjuno";

try {
  await client.reseller.balance();
} catch (error) {
  if (error instanceof SimjunoApiError) {
    console.error(error.statusCode, error.body);
  }
  throw error;
}
```

## Configure retries and timeouts

Requests time out after 60 seconds and retry up to two times by default for `408`, `429`, and `5xx` responses. Retries count toward your [rate limit](/rate-limits).

Set defaults when creating the client:

```typescript
const client = new SimjunoApiClient({
  apiKey,
  maxRetries: 3,
  timeoutInSeconds: 30,
});
```

Override them for one request with the second argument:

```typescript
const destinations = await client.esim.listDestinations(
  {},
  { maxRetries: 0, timeoutInSeconds: 10 },
);
```

Each request also accepts `headers`, `queryParams`, and an `abortSignal`. Add `.withRawResponse()` to a request when you need response headers or status metadata:

```typescript
const { data, rawResponse } =
  await client.reseller.balance().withRawResponse();
```

## Use exported types

Request and response interfaces are available from the `SimjunoApi` namespace:

```typescript
import { SimjunoApi } from "simjuno";

const request: SimjunoApi.OrderEsimRequest = {
  transaction_id: "your-order-123",
  orderList: [{ slug: "ES_1_7", count: 1 }],
};
```