Python SDK

View as Markdown

The SimJuno Python SDK provides typed synchronous and asynchronous access to the reseller and eSIM APIs. It includes authentication, retries, timeouts, API errors, and Pydantic request and response models.

The package is configured for publication as simjuno on PyPI, and its source repository is available on GitHub.

Install

$pip install simjuno

The SDK requires Python 3.10 or later.

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 os
2
3from simjuno import SimjunoApi
4
5client = SimjunoApi(api_key=os.environ["SIMJUNO_API_KEY"])
6
7balance = client.reseller.balance()
8print(f"Balance: ${balance.balance / 10_000:.2f}")

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:

1from uuid import uuid4
2
3from simjuno.esim import OrderEsimRequestOrderListItem
4
5package_list = client.esim.list_packages("spain")
6if not package_list.packages:
7 raise RuntimeError("No packages found")
8
9selected_package = package_list.packages[0]
10current_package = client.esim.get_package(selected_package.slug)
11
12order = client.esim.order_esim(
13 transaction_id=str(uuid4()),
14 order_list=[
15 OrderEsimRequestOrderListItem(
16 slug=current_package.slug,
17 count=1,
18 )
19 ],
20)

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

After receiving the ORDER_STATUS webhook, retrieve the provisioning details for each returned eSIM ID:

1if not order.esim_ids:
2 raise RuntimeError("The order returned no eSIM IDs")
3
4esim = client.esim.get_esim(order.esim_ids[0])
5print(esim.qr_code_url, esim.short_url, esim.ac)

Available methods

TaskMethod
Get reseller balanceclient.reseller.balance()
List destinationsclient.esim.list_destinations()
List plans for a destinationclient.esim.list_packages(slug)
Get current plan detailsclient.esim.get_package(slug)
Order eSIMsclient.esim.order_esim(...)
List ordered eSIMsclient.esim.list_esims()
Get an eSIMclient.esim.get_esim(id)
Get current usageclient.esim.check_usage(id)
List top-up plansclient.esim.list_topup_packages(slug)
Cancel an eligible eSIMclient.esim.cancel_esim(id)

Handle errors

Non-success responses throw ApiError:

1from simjuno.core.api_error import ApiError
2
3try:
4 client.reseller.balance()
5except ApiError as error:
6 print(error.status_code, error.body)
7 raise

Configure retries and timeouts

Requests time out after 60 seconds and retry up to two times by default for 408, 409, 429, and 5xx responses. Retries count toward your rate limit.

Set defaults when creating the client:

1client = SimjunoApi(
2 api_key=os.environ["SIMJUNO_API_KEY"],
3 max_retries=3,
4 timeout=30.0,
5)

Override them for one request with request_options:

1destinations = client.esim.list_destinations(
2 request_options={"max_retries": 0, "timeout": 10.0}
3)

Use the async client

AsyncSimjunoApi provides the same methods for asynchronous applications:

1import asyncio
2import os
3
4from simjuno import AsyncSimjunoApi
5
6async_client = AsyncSimjunoApi(api_key=os.environ["SIMJUNO_API_KEY"])
7
8
9async def main() -> None:
10 balance = await async_client.reseller.balance()
11 print(f"Balance: ${balance.balance / 10_000:.2f}")
12
13
14asyncio.run(main())

Access the raw response

Use with_raw_response when you need response headers or status metadata:

1response = client.reseller.with_raw_response.balance()
2print(response.status_code, response.headers)
3balance = response.data