Python SDK
We provide a lightweight Python SDK to access the public OKAPI:Astrolabe API in a convenient way.
Installation
You can install the SDK using pip as follows:
pip install astrolabe-sdk
Or add the following dependency to your requirements.txt
:
astrolabe-sdk==1.0.1
Getting set up
In order to use the OKAPI:Astrolabe API, you need to set up an account.
If you don’t have one yet, please get in touch with contact@okapiorbits.com
.
If you already signed up but still look for support to integrate the API
into your automated work flows, please get in touch with support@okapiorbits.com
.
Using the SDK
This section shows how to use the SDK to access API endpoints in Python in a convenient way.
In order to connect, you need to set the following environment variables:
ASTROLABE_AUTH0_USERNAME
ASTROLABE_AUTH0_PASSWORD
ASTROLABE_AUTH0_CLIENT_ID
ASTROLABE_AUTH0_DOMAIN
ASTROLABE_AUTH0_AUDIENCE
You will get those as part of the sign up process.
The easiest way to provide them is to create a .env
file,
for example with the following content:
ASTROLABE_AUTH0_USERNAME=james.t.kirk@starfleet.space
ASTROLABE_AUTH0_PASSWORD=blahblubb
ASTROLABE_AUTH0_CLIENT_ID=dummy
ASTROLABE_AUTH0_DOMAIN=https://alpha-quadrant.eu.auth0.com
ASTROLABE_AUTH0_AUDIENCE=https://api.alpha-quadrant.space
⚠️ Make sure to keep your credentials secret.
Now you can use the SDK as follows:
from astrolabe.api import AstrolabeAPI
astrolabe = AstrolabeAPI()
# Log in, specifying the ID of the organization you are member of.
# If you are not sure where to get this from, get in touch.
astrolabe.login("673db8d8300ddd4625cf90aa")
# Now you can send requests.
⚠️ If you want to test your scripts first, use AstrolabeAPI("staging")
and get in touch for access to the staging instance.
The SDK provides basic methods for GET, POST, PUT, PATCH and DELETE requests. This way, you can access all available endpoints. The methods expect a path, and for POST and PATCH you additionally provide the request body as a dictionary:
astrolabe.get("...")
astrolabe.post("...", { ... })
astrolabe.patch("...", { ... })
astrolabe.delete("...")
These methods take care of setting all necessary headers, and return the parsed response data
(or None
if the response is empty).
If you want them to return the raw response, set the optional parameter return_raw_response
, for example:
astrolabe.get("satellites", return_raw_response=True)
If the response status code is 4xx, the methods raise a ClientError
;
if the response status code is 5xx, they raise a ServerError
.
In addition, the SDK provides convenience methods for the most common functionality you might want to integrate into your own processes. In the following, we show some examples.
Inspecting conjunction events
Each conjunction event of one of your active satellites against another active object leads to the creation of a coordination case. The case is connected to all relevant information, like the involved objects, the received CDMs, data that was uploaded by you or your conjunction partner, chat messages you exchanged, and so on.
You can fetch all open coordination cases as follows, by default including only those with TCA still in the future and with a risk assessment either “critical” or “observe” (i.e. not including uncritical events):
coordination_cases = astrolabe.get_cases()
# In order to include uncritical cases:
astrolabe.get_cases(include_uncritical = True)
# In order to filter for particular objects (primary or secondary):
astrolabe.get_cases(object_name = "TURBOSAT")
# In order to filter for conjunction partner:
astrolabe.get_cases(conjunction_partner = "Starlink")
You can also directly fetch CDMs, specifying relevant filters and the format in which you want to have the CDMs (KVN, XML, or JSON). For example, to get all CDMs from CSpOC with a collision probability greater than or equal to 1e-4 and with TCA in less than one and a half days:
cdms = astrolabe.get_cdms("kvn", filters = {
"originator": "CSpOC",
"collision_probability": {
"operator": ">=",
"value": 1e-4
},
"time_to_tca": {
"operator": "<",
"value": "1d12h"
}
})
The full list of available filters is as follows:
{
"originator": str,
"object1_name": str,
"object2_name": str,
"object1_norad_id": int,
"object2_norad_id": int,
"object1_cospar_id": str,
"object2_cospar_id": str,
"operator2_name": str,
"collision_probability": number | Comparison[number],
"miss_distance": number | Comparison[number],
"radial_distance": number | Comparison[number],
"time_to_tca": str | Comparison[str], # with str being a duration like '1d12h'
"created_after": str # ISO timestamp, e.g. '2025-01-01T09:30Z'
}
Where Comparison[<type>]
is a dictionary of the following form:
{
"operator": "=" | "<" | "<=" | ">" | ">=",
"value": <type>
}
You can also set the optional paramater latest
to get only the latest CDM
that matches the filters, for example:
cdms = astrolabe.get_cdms("kvn", filters = { "object1_norad_id": 12345 }, latest = True)
Similarly, you can download ephemerides (including both OEMs and OPMs):
ephemerides = astrolabe.get_ephemerides("kvn", filters = {
"object_name": "TURBOSAT",
"operational": True,
"uploaded_after": "2025-01-01T09:30Z"
})
The full set of possible filters is as follows:
{
"object_name": str,
"object_id": str | number,
"originator": str,
"operational": bool,
"uploaded_after": str # ISO timestamp, e.g. "2025-01-01T09:30Z"
}
And also here you can set the optional paramater latest = True
to get only the latest
OEM and OPM that match the filters.
Uploading data
Operational ephmerides
In order to upload operational ephemerides, specify the datatype (OEM, OPM, or NDM) and the format (KVN, XML, or JSON), and point to the file you want to upload:
filepath = "path/to/oem.kvn"
upload_ephemerides(self, "oem", "kvn", filepath)
For more details on how data is expected, check the supported dataformats section.
Uploaded ephemerides are forwared to external services for conjunction screening, see the screening section on more details. If data cannot be used for conjunction screening, the API response will let you know.
Tentative maneuver plans
Similarly, you can upload tentative maneuver plans. You need to specify two additional parameters: a human-friendly name for the maneuver plan, and the ID of the coordination case in the context of which you consider the maneuver, for example:
filepath = "path/to/opm.kvn"
case_id = "65a15efc57fd0a469432c3af"
astrolabe.upload_maneuver_plan("opm", "kvn", filepath, "Thrust or bust!", case_id)
The supported dataformats are the same as for operational ephemerides.
⚠️ Note that depending on your subscription plan, you might not be able to upload maneuver plans, or you have a limit on the number of file uploads per coordination case.
Also maneuver plans are forwared to external services for conjunction screening, see the screening section on more details. If data cannot be used for conjunction screening, the API response will let you know.
Defining satellites
You can either create or update a satellite using the set_up_satellite
method, providing
a dictionary with all properties of the satellite that you want to specify.
If the satellite does not exist yet, you need to specify a name and whether it’s active or not. If it is active, you also need to specify either its NORAD ID or its COSPAR ID, ideally both. For example:
astrolabe.set_up_satellite({
"name": "TURBOSAT",
"active": True,
"norad_id": 12345,
"cospar_id": "2030-999X"
})
The response will contain the created satellite, including a satellite_id
field.
⚠️ Note that depending on your subscription plan, you might not be able to set up satellites or have a limit on the number of satellites you can define.
If the satellite already exists and you want to update it, you need to specify its name, NORAD ID, or COSPAR ID for identification, plus the properties you want to add or change. See the section on defining satellites for a complete list of all satellite properties currently defined.
You can inspect all satellites defined for your organization as follows:
satellites = astrolabe.get_satellites()
The response will be a list of satellite dictionaries, each one containing a satellite_id
field.
If you want to delete a satellite, use that ID:
astrolabe.delete_satellite(satellite_id)
All satellite definitions of your organization are only accessible for members of your organization, so other operators are not able to see them.