TypeScript SDK

View as Markdown

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, and its source is available on GitHub.

Install

$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, 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.

1import { SimjunoApiClient } from "simjuno";
2
3const apiKey = process.env.SIMJUNO_API_KEY;
4if (!apiKey) throw new Error("SIMJUNO_API_KEY is required");
5
6const client = new SimjunoApiClient({ apiKey });
7
8const { balance } = await client.reseller.balance();
9console.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. This example finds a plan, confirms its current details, and places an order:

1import { randomUUID } from "node:crypto";
2
3const { packages } = await client.esim.listPackages({ slug: "spain" });
4const selectedPackage = packages[0];
5if (!selectedPackage) throw new Error("No packages found");
6
7const currentPackage = await client.esim.getPackage({
8 slug: selectedPackage.slug,
9});
10
11const { esim_ids } = await client.esim.orderEsim({
12 transaction_id: randomUUID(),
13 orderList: [{ slug: currentPackage.slug, count: 1 }],
14});

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, retrieve the provisioning details for each returned eSIM ID:

1const [esimId] = esim_ids;
2if (!esimId) throw new Error("The order returned no eSIM IDs");
3
4const esim = await client.esim.getEsim({ id: esimId });
5console.log(esim.qrCodeUrl, esim.shortUrl, esim.ac);

Available methods

TaskMethod
Get reseller balanceclient.reseller.balance()
List destinationsclient.esim.listDestinations()
List plans for a destinationclient.esim.listPackages({ slug })
Get current plan detailsclient.esim.getPackage({ slug })
Order eSIMsclient.esim.orderEsim(request)
List ordered eSIMsclient.esim.listEsims()
Get an eSIMclient.esim.getEsim({ id })
Get current usageclient.esim.checkUsage({ id })
List top-up plansclient.esim.listTopupPackages({ slug })
Cancel an eligible eSIMclient.esim.cancelEsim({ id })

Handle errors

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

1import { SimjunoApiError } from "simjuno";
2
3try {
4 await client.reseller.balance();
5} catch (error) {
6 if (error instanceof SimjunoApiError) {
7 console.error(error.statusCode, error.body);
8 }
9 throw error;
10}

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.

Set defaults when creating the client:

1const client = new SimjunoApiClient({
2 apiKey,
3 maxRetries: 3,
4 timeoutInSeconds: 30,
5});

Override them for one request with the second argument:

1const destinations = await client.esim.listDestinations(
2 {},
3 { maxRetries: 0, timeoutInSeconds: 10 },
4);

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

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

Use exported types

Request and response interfaces are available from the SimjunoApi namespace:

1import { SimjunoApi } from "simjuno";
2
3const request: SimjunoApi.OrderEsimRequest = {
4 transaction_id: "your-order-123",
5 orderList: [{ slug: "ES_1_7", count: 1 }],
6};