LogoLogo
ProductsDevelopersAPI ReferenceContact Us
Super SIM
Super SIM
  • Super SIM
  • Super SIM's Available Networks
  • Super SIM’s Multi-IMSI Applet
  • Over-the-Air Updates
  • Get Started with Super SIM
    • Overview
    • Get Started with Super SIM, the Raspberry Pi 4 and the Waveshare 4G Hat
    • Get Started with Super SIM, the Raspberry Pi 4 and the Sixfab Base Hat
    • Get Started with Data Comms and the Raspberry Pi Pico
    • Get Started with Super SIM SMS Commands and the Raspberry Pi 4
    • Get Started with Super SIM SMS Commands and the Raspberry Pi Pico
    • Get Started with Super SIM IP Commands and the Raspberry Pi
    • Get Started with Super SIM IP Commands and the Raspberry Pi Pico
    • Get Started with Super SIM eSIM Profiles for eUICCs
    • Get Started with Super SIM Connection Events
  • How To
    • How to Set a Device’s APN for Super SIM
    • How to Enable Device Roaming for Super SIM
    • How to Determine Whether a Device Contains a Super SIM
    • How to Set up iPhones for Super SIM
    • How to Determine a Super SIM’s Status
    • How to Use Console Bulk Actions to Update Multiple Super SIMs
    • How to Download Bulk Super SIM Data
    • How to Use Super SIM Fleets and Network Access Profiles
    • How to Understand the Settings on your SIM
      • Base Settings Package
    • How and Why You Can Set Super SIM’s Network Attach Priority List
    • How to Set Up and Use a Super SIM VPN
    • How to Configure AWS for a Super SIM VPN
    • How to Make and Take IoT VoIP Calls via Super SIM
    • How to Use Super SIM Connection Events
    • How to use Super SIM eSIM Profiles
    • How to Monitor Super SIM Connection Events using AWS ElasticSearch and Kibana
    • How to Use OpenAPI Clients with Super SIM
  • Into Production
    • Prepare for Production Deployments with Super SIM
    • Super SIM Datasheet
    • Super SIM Network Timeouts
  • Works with Super SIM
    • Works with Super SIM: Quectel BG95
    • Works with Super SIM: Quectel EG21-G
    • Works with Super SIM: Quectel EG25-G
    • Works with Super SIM: Thales Cinterion EXS62-W
    • Works with Super SIM: u-blox SARA-R5
  • Cellular Module Knowledgebase
    • Overview
    • About AT Commands
    • Nordic Modules with Super SIM
    • Quectel Modules with Super SIM
    • Quectel Modules with the KORE Narrowband SIM
    • Simcom Modules with Super SIM
    • Telit Modules with Super SIM
    • Thales Cinterion Modules with Super SIM
    • U-blox Modules with Super SIM
    • Cellular IoT Terminology
    • Low-power Optimization for Cellular Modules
    • Four Best Practices for Cellular Module Registration
    • How to Determine Good Cellular Signal Strength
    • How Super SIM Devices Connect to Cell Networks
  • Super SIM API
On this page
  • Create Your KORE API Client Resource
  • Generating Your Local Client
  • Install Other Dependencies
  • Authenticating to the KORE REST API
  • Generate API Client Instances for Each Endpoint
  • Bringing It All Together

Was this helpful?

  1. How To

How to Use OpenAPI Clients with Super SIM

Learn how to use KORE's OpenAPI specification file to generate an API client that you can use to make calls to the Super SIM APIs.

PreviousHow to Monitor Super SIM Connection Events using AWS ElasticSearch and KibanaNextInto Production

Last updated 3 months ago

Was this helpful?

In this guide, we're going to build a python script that API clients built from our OpenAPI specification file. The tool used below to generate the client, openapi-generator, supports many different programming languages, not just python.

If you're not already familiar with how to use OpenAPI specification files to generate clients or how to install and use them, LLMs like ChatGPT can be very helpful with navigating the unique aspects and build tools for your programming language.

Create Your KORE API Client Resource

To make requests to the KORE REST APIs, you need to first create a Client resource in the . Note this is different than the "clients" that we'll be generating from the OpenAPI specification file and will be using to make requests to the APIs. You get your necessary credentials by creating this Client resource.

KORE's API's follow OAuth2 for authenticating to the APIs. You'll create a Client that includes Super SIM within its scoped products and then use the ID and secret of the Client to generate an access token that you'll include in your request headers to authenticate to the API endpoints.

Learn more about how to generate this Client to use with Super SIM . You can jump to "Get Started!" section for the steps to create your Client. Once you have your client ID and secret return here.

Your client secret will only be shown to you once so be sure to save it somewhere. Don't worry though, if you lose it you can always generate a new Client or refresh your secret.

Generating Your Local Client

There are many options you can choose from for to generate API clients from OpenAPI specification files that may work better for your development environment or that use syntax and patterns that you may find easier to understand. How you install and use them and then use the generated clients will vary significantly from tool to tool. For this guide we'll be using the openapi-generator CLI tool.

First, install the openapi-generator CLI tool.

brew install openapi-generator

Next, download a copy the specification file from Github and save it in your project directory.

Generate a python client using the OpenAPI specification file and the generator tool.

openapi-generator generate -i ./kore-supersim-v1.json -g python -o ./clients/kore_supersim_client --package-name supersim_client

For additional approaches to install and generate clients using the openapi-generator tool, such as with Windows, please refer to the .

From this point forward, all the code and commands will be specific to Python3. Except for the final section, where we provide a comprehensive example of using multiple endpoints to generate a CSV file, we've minimized the use of Python-specific patterns or tricks. This approach makes it easier for those less familiar with Python to follow along.

We understand that not everyone is familiar with Python. If you find any sections of this guide or code difficult to follow, please use the "Was this helpful?" tool on this page and leave a comment. Your feedback helps us improve, and we'll do our best to add more clarifications or comments to the code to explain what is being done.

Create a python virtual environment to which you'll install your packages including your generated client.

python3 -m venv ./env

Activate the virtual environment.

source env/bin/activate

Install the package locally in your virtual environment.

pip3 install ./clients/kore_supersim_client

With that done, let's generate a file called client-test.py and make sure that we can successfully import the installed client and run the code without errors.

from supersim_client import ApiClient, Configuration

def main():
    print("hello world")

if __name__ == "__main__":
    main()

Run your code.

python3 client-test.py

If you see "hello world" successfully logged with no errors, then you should be all set to begin making API requests with your generated and installed client. We'll be doing all coding for this guide in the client-test.py file.

Install Other Dependencies

pip3 install requests

Authenticating to the KORE REST API

To access the KORE REST APIs, we'll need an access token. We'll use the client ID and secret from the Client resource you created earlier to generate a temporary token used to authenticate your requests.

We'll add a function to our code to get a token with our secrets and use it to print out the some useful properties from the access token response. Replace <YOUR_CLIENT_ID> and <YOUR_CLIENT_SECRET> with your unique credentials.

Treat your client ID, secret, and access tokens like they are passwords. Do not share them with anyone and never commit them to any public code repositories.

from supersim_client import ApiClient, Configuration
import requests

TOKEN_URL = "https://api.korewireless.com/api-services/v1/auth/token"
CLIENT_ID='<YOUR_CLIENT_ID>'
CLIENT_SECRET='<YOUR_CLIENT_SECRET>'

def get_access_token(client_id, client_secret, token_url):
	response = requests.post(token_url, data={
		'grant_type': 'client_credentials',
		'client_id': client_id,
		'client_secret': client_secret
	})
	token_data = response.json()
	return token_data

def main():
	token_data = get_access_token(CLIENT_ID, CLIENT_SECRET, TOKEN_URL)
	print(token_data['access_token'])
	print(token_data['expires_in'])

if __name__ == "__main__":
	main()

Access tokens are temporary. You can see how many seconds the token is valid for by checking the expires_in property the response. If you use an expired token, your requests will be rejected. When you get a new token, you'll need to regenerate the clients with a new configuration that has the updated token. We recommend creating a class that manages refreshing the token and regenerating the clients that wraps around the generated client resources in a production setting where your code is deployed and running on servers versus writing simple scripts like we are here.

Generate API Client Instances for Each Endpoint

Now, we'll use our access token to begin generating instances of our API clients, one for each endpoint we'll be making requests to. Note that there is a module to be imported for each endpoint that you'll use to generate a client for that endpoint.

from supersim_client import ApiClient, Configuration, SupersimV1SimApi, SupersimV1FleetApi
import requests

TOKEN_URL = "https://api.korewireless.com/api-services/v1/auth/token"
CLIENT_ID='<YOUR_CLIENT_ID>'
CLIENT_SECRET='<YOUR_CLIENT_SECRET>'

def get_access_token(client_id, client_secret, token_url):
	response = requests.post(token_url, data={
		'grant_type': 'client_credentials',
		'client_id': client_id,
		'client_secret': client_secret
	})
	token_data = response.json()
	return token_data

def main():
	token_data = get_access_token(CLIENT_ID, CLIENT_SECRET, TOKEN_URL)
	access_token = token_data['access_token']

	config = Configuration(
		access_token=access_token # Set your OAuth2 token here
	)
	
	# Generate base API client passed to each endpoint client
	api_client = ApiClient(config)

	# Generate clients for each endpoint
	sim_api_client = SupersimV1SimApi(api_client)
	fleet_api_client = SupersimV1FleetApi(api_client)

if __name__ == "__main__":
	main()

You can use the clients generated for each endpoint to list out your Sims and Fleet resources.

from supersim_client import ApiClient, Configuration, SupersimV1SimApi, SupersimV1FleetApi
import requests

TOKEN_URL = "https://api.korewireless.com/api-services/v1/auth/token"
CLIENT_ID='<YOUR_CLIENT_ID>'
CLIENT_SECRET='<YOUR_CLIENT_SECRET>'

def get_access_token(client_id, client_secret, token_url):
	response = requests.post(token_url, data={
		'grant_type': 'client_credentials',
		'client_id': client_id,
		'client_secret': client_secret
	})
	token_data = response.json()
	return token_data

def main():
	token_data = get_access_token(CLIENT_ID, CLIENT_SECRET, TOKEN_URL)
	access_token = token_data['access_token']

	config = Configuration(
		access_token=access_token # Set your OAuth2 token here
	)

	# Generate base API client passed to each endpoint client
	api_client = ApiClient(config)

	# Generate clients for each endpoint
	sim_api_client = SupersimV1SimApi(api_client)
	fleet_api_client = SupersimV1FleetApi(api_client)

	sims_response = sim_api_client.list_sim()
	fleets_response = fleet_api_client.list_fleet()

	print(sims_response.sims)
	print(fleets_response.fleets)

if __name__ == "__main__":
	main()

Go ahead and run your code.

Assuming you already have SIMs and Fleets created on your account, you should see arrays of these resources printed out when you run your code. If you have more than the default page size (50) of either resource though, these results are incomplete. That's because the results are just one page. You can increase the page_size up to 1,000 if you have less than 1,000 resources, but to properly scale this out, we'll need to use the pagination information in our responses to fetch all the pages of results we need.

Here's an example of how you could write a function to fetch all pages of Sim resources:

from clients.kore_supersim_client.build.lib.supersim_client.models.sim_enum_status import SimEnumStatus
from urllib.parse import urlparse, parse_qs

def fetch_all_sims(
		sim_api_client: SupersimV1SimApi,
		status: SimEnumStatus=None,
		fleet: str=None
):
	accumulated_sims = []
	next_page_url = None

	first_page_response = sim_api_client.list_sim(status=status,fleet=fleet)
	accumulated_sims += first_page_response.sims

	if first_page_response.meta.next_page_url is not None:
		next_page_url = first_page_response.meta.next_page_url

	while next_page_url is not None:
		# Parse the next page URL string so we can pass in the individual properties
		# when fetching the next page.
		parsed_next_page_url = urlparse(next_page_url)
		query_params = parse_qs(parsed_next_page_url.query)
		query_params = {key: value[0] for key, value in query_params.items()}

		next_page_response = sim_api_client.list_sim(
			status=status,
			fleet=fleet,
			page=int(query_params['Page']),
			page_size=int(query_params['PageSize']),
			page_token=query_params['PageToken']
		)
		next_page_sims = next_page_response.sims
		accumulated_sims += next_page_sims

		# Reassign the variable to continue or break the loop.
		next_page_url = next_page_response.meta.next_page_url

	return accumulated_sims

Note that in the example above, the status variable is using a type also imported from our generated code. Finding and importing these types can be much easier if you use an IDE such as PyCharm in our case here. The generated client resource will be expecting specific types for its arguments.

We can now use this function in our main()call to get all of our Sims if we needed to iterate over each one to pull data usage data for each or build CSV export.

def main():
	token_data = get_access_token(CLIENT_ID, CLIENT_SECRET, TOKEN_URL)
	access_token = token_data['access_token']

	config = Configuration(
		access_token=access_token # Set your OAuth2 token here
	)

	# Generate base API client passed to each endpoint client
	api_client = ApiClient(config)

	# Generate clients for each endpoint
	sim_api_client = SupersimV1SimApi(api_client)
	fleet_api_client = SupersimV1FleetApi(api_client)

	all_sims = fetch_all_sims(sim_api_client)
	print(all_sims)
	print(len(all_sims))

Bringing It All Together

Now that we can fetch all of our Sims, we can build upon our script here to build a practical application that you can use easily pull data about all of your SIMs and data usage for the last 30 days.

First, we'll create a similar function to like we did for our Sim resources to fetch all of our Fleet resources.

Next, we're going to generate another endpoint client for the UsageRecords endpoint.

Lastly, we'll iterate over each SIM and pull the SIM's usage and build a CSV report.

import requests
from urllib.parse import urlparse, parse_qs
import csv

from supersim_client import ApiClient, Configuration, SupersimV1SimApi, SupersimV1FleetApi
from clients.kore_supersim_client.build.lib.supersim_client.models.sim_enum_status import SimEnumStatus
from clients.kore_supersim_client.build.lib.supersim_client.models.supersim_v1_fleet import SupersimV1Fleet
from clients.kore_supersim_client.build.lib.supersim_client.models.supersim_v1_sim import SupersimV1Sim
from clients.kore_supersim_client.supersim_client.api.supersim_v1_usage_record_api import SupersimV1UsageRecordApi
from clients.kore_supersim_client.supersim_client.models.usage_record_enum_granularity import UsageRecordEnumGranularity

TOKEN_URL = "https://api.korewireless.com/api-services/v1/auth/token"
CLIENT_ID='<YOUR_CLIENT_ID>'
CLIENT_SECRET='<YOUR_CLIENT_SECRET>'

def get_access_token(client_id, client_secret, token_url):
	response = requests.post(token_url, data={
		'grant_type': 'client_credentials',
		'client_id': client_id,
		'client_secret': client_secret
	})
	token_data = response.json()
	return token_data

def fetch_all_sims(
		sim_api_client: SupersimV1SimApi,
		status: SimEnumStatus=None,
		fleet: str=None
):
	accumulated_sims = []
	next_page_url = None

	first_page_response = sim_api_client.list_sim(status=status,fleet=fleet)
	accumulated_sims += first_page_response.sims

	if first_page_response.meta.next_page_url is not None:
		next_page_url = first_page_response.meta.next_page_url

	while next_page_url is not None:
		# Parse the next page URL string so we can pass in the individual properties
		# when fetching the next page.
		parsed_next_page_url = urlparse(next_page_url)
		query_params = parse_qs(parsed_next_page_url.query)
		query_params = {key: value[0] for key, value in query_params.items()}

		next_page_response = sim_api_client.list_sim(
			status=status,
			fleet=fleet,
			page=int(query_params['Page']),
			page_size=int(query_params['PageSize']),
			page_token=query_params['PageToken']
		)
		next_page_sims = next_page_response.sims
		accumulated_sims += next_page_sims

		# Reassign the variable to continue or break the loop.
		next_page_url = next_page_response.meta.next_page_url

	return accumulated_sims

def fetch_all_fleets(
		fleet_api_client: SupersimV1FleetApi
):
	accumulated_fleets = []
	next_page_url = None

	first_page_response = fleet_api_client.list_fleet()
	accumulated_fleets += first_page_response.fleets

	if first_page_response.meta.next_page_url is not None:
		next_page_url = first_page_response.meta.next_page_url

	while next_page_url is not None:
		# Parse the next page URL string so we can pass in the individual properties
		# when fetching the next page.
		parsed_next_page_url = urlparse(next_page_url)
		query_params = parse_qs(parsed_next_page_url.query)
		query_params = {key: value[0] for key, value in query_params.items()}

		next_page_response = fleet_api_client.list_fleet(
			page=int(query_params['Page']),
			page_size=int(query_params['PageSize']),
			page_token=query_params['PageToken']
		)
		next_page_fleets = next_page_response.fleets
		accumulated_fleets += next_page_fleets

		# Reassign the variable to continue or break the loop.
		next_page_url = next_page_response.meta.next_page_url

	return accumulated_fleets

def main():
	token_data = get_access_token(CLIENT_ID, CLIENT_SECRET, TOKEN_URL)
	access_token = token_data['access_token']

	config = Configuration(
		access_token=access_token # Set your OAuth2 token here
	)

	# Generate base API client passed to each endpoint client
	api_client = ApiClient(config)

	# Generate clients for each endpoint
	sim_api_client = SupersimV1SimApi(api_client)
	fleet_api_client = SupersimV1FleetApi(api_client)
	usage_records_client = SupersimV1UsageRecordApi(api_client)

	all_sims: list[SupersimV1Sim] = fetch_all_sims(sim_api_client)
	all_fleets: list[SupersimV1Fleet] = fetch_all_fleets(fleet_api_client)

	# Build dictionary of Fleets for looking it up later.
	fleets_dict = {fleet.sid: fleet for fleet in all_fleets}

	output_file = "sim_usage_report.csv"
	with open(output_file, mode="w", newline="") as csvfile:
		csvwriter = csv.writer(csvfile)
		csvwriter.writerow(["SIM SID","ICCID", "SIM Unique Name", "SIM Status", "Fleet SID", "Fleet Unique Name", "Fleet Data Limit (MBs)", "Data Used (MBs)"])

		for sim in all_sims:
			fleet_sid = sim.fleet_sid
			fleet = fleets_dict.get(fleet_sid)
			fleet_unique_name = fleet.unique_name if fleet else "Unknown"
			fleet_data_limit = fleet.data_limit if fleet else "Unknown"

			sim_usage_records = usage_records_client.list_usage_record(
				sim=sim.sid,
				granularity=UsageRecordEnumGranularity("all")
			)

			data_used = sim_usage_records.usage_records[0].data_total
			data_used_mb = data_used / (1000 * 1000)

			csvwriter.writerow([
				sim.sid,
				sim.iccid,
				sim.unique_name,
				sim.status,
				fleet_sid,
				fleet_unique_name,
				fleet_data_limit,
				data_used_mb
			])

if __name__ == "__main__":
	main()

If you run your code, you should see the generated CSV in your project directory with information about each SIM and its usage.

KORE Developer Portal
Super SIM OpenAPI
documentation
here
here