Tasking API - v2.2.1
The Spire Tasking API is the direct interface for scheduling windows in the Spire constellation. It can be used directly for manual scheduling of individual windows or, more commonly, as a service for automated scheduling systems.
Auto-generated OpenAPI specification
Important Notes
Minimum Window Padding
Certain startup and shutdown procedures occur before and after window execution. Windows should not be scheduled too close together or some operations may not complete successfully.
window type | pre-buffer | post-buffer |
---|---|---|
LEASE_ADCS | 420s | 420s |
LEASE_ISL | 60s | 60s |
MAINTENANCE | 0s | 0s |
PAYLOAD_CORAL | 300s | 150s |
PAYLOAD_DEXTER | 220s | 265s |
PAYLOAD_IPI | 120s | 210s |
PAYLOAD_MARSUPIAL | 300s | 150s |
PAYLOAD_MYRIAD | 300s | 150s |
PAYLOAD_NANO | 300s | 150s |
PAYLOAD_SABERTOOTH | 180s | 210s |
PAYLOAD_SDR | 120s | 210s |
Post-Upload Windows
When uploading a file to a payload, the file is held in a queuing area until the first window of a type associated with that payload is executed.
NOTE: This requirement is intended to be removed in a future release.
Minimum Window Duration
window type | minimum duration (seconds) |
---|---|
LEASE_ADCS | 60 |
LEASE_ISL | 60 |
MAINTENANCE | 60 |
PAYLOAD_CORAL | 30 |
PAYLOAD_DEXTER | No minimum |
PAYLOAD_IPI | 30 |
PAYLOAD_MARSUPIAL | 30 |
PAYLOAD_MYRIAD | 30 |
PAYLOAD_NANO | 30 |
PAYLOAD_SABERTOOTH | 30 |
PAYLOAD_SDR | 30 |
Total Daily Download Volume
Users should limit total downloads to less than 100MB/day
Total Daily Upload Volume and Upload Limitations
Users should expect an average upload volume of roughly to 125KB/day (this can be increased by designating a satellite to prioritize uploads, though this may impact download times). The upper limit on individual upload file size is 10MB. There is an option to manually pre-load larger file packages to a satellite prior to launch if the contract involves a satellite in active assembly.
Upload and Download Time Expectations
Upload Times
Please note that uploading a file requires the satellite in question to complete at least one bidirectional contact over a Spire ground station. Depending on a satellite's upcoming contact schedule, even a small file (on the order of kb) can take up to 6 hours from the requested time to successfully upload. As Spire schedules at minimum one bidirectional pass per 6 hour period, upload times will generally be faster than the worst case scenario. The larger the file, the greater the necessary contact time.
Download Times
Depending on the difference in time between the end of a payload window and the next scheduled contact, file download times can range between the order of minutes to several hours. If a contract with Spire has specific latency requirements, Spire's engineers will work to facilitate a means of ensuring consistent download times.
Spire's satellites utilize an Sband Radio for their most efficient downloads.
ADCS Priority
It is possible that multiple windows can be scheduled simultaneously that request certain ADCS modes / orientations. While it is not desirable to do this, it is not explicitly prohibited. As such there are certain priorities associated with windows to determine which one takes effect.
All standard payload windows, that allow for adcs_config
to be specified, have the same priority. This means that, when multiple windows overlap, the one starting latest will ultimately take effect. Non-standard payload windows that command the ADCS system include LEASE_ADCS and LEASE_ISL.
LEASE_ADCS windows have a higher priority than all standard payload windows since a payload can be commanding the mode/orientation continuously throughout the course of the window. LEASE_ISL windows, since they require pointing the satellite towards its paired ISL satellite, is higher priority than both standard payload windows and LEASE_ADCS windows. For satellites that require stationkeeping, drag/propulsion operations may be scheduled by Spire to do so. These operations will always have the highest priority over the ADCS system.
Thus the order of priority, highest to lowest, is as follows:
- Stationkeeping operations
- LEASE_ISL
- LEASE_ADCS
- All standard payload windows (latest one wins)
Overlapping Windows
By default no scheduled window can overlap with another window, whether that is a payload window, or a contact window that Spire uses for maintenance of the satellite.
There are some use cases, however, that involve overlapping two windows. An example of this might be analyzing some signals captured on the SDR payload, which would trigger an image capture on the IPI payload.
In order to allow for certain use cases, some explicit window overlappings are allowed. Also note that, more than two windows can overlap if each window type is allowed to overlap with each of the other window types. For example, PAYLOAD_SDR, PAYLOAD_SABERTOOTH, and PAYLOAD_IPI can all be scheduled at the same time.
The following pairs of windows are allowed to overlap:
- LEASE_ADCS, PAYLOAD_SABERTOOTH
- LEASE_ADCS, PAYLOAD_SDR
- LEASE_ADCS, PAYLOAD_IPI
- LEASE_ADCS, PAYLOAD_FOREST1
- LEASE_ISL, PAYLOAD_SABERTOOTH
- LEASE_ISL, PAYLOAD_SDR
- LEASE_ISL, PAYLOAD_IPI
- PAYLOAD_SABERTOOTH, PAYLOAD_SDR
- PAYLOAD_SABERTOOTH, PAYLOAD_IPI
- PAYLOAD_SDR, PAYLOAD_IPI
- PAYLOAD_FOREST1, PAYLOAD_SDR
- PAYLOAD_FOREST2_MCU, PAYLOAD_FOREST2_SIGNALING
Background
Scheduling
The Spire constellation is controlled via a globally synchronized calendar of fixed-duration operation windows. Each window has a fixed start time, a fixed duration, a type, and additional window-specific parameters that tune its operation.
A single window may consist of multiple steps that are scheduled together e.g. the PAYLOAD_SDR task can orient the satellite, record an IQ file, and perform an analysis of the recorded IQ file in one schedulable unit.
The canonical schedule is stored in Spire-controlled terrestrial infrastructure. Relevant windows are synchronized to each satellite during regular maintenance procedures and executed by each satellite's onboard controller.
Executing User Code
Execution of a window may require execution of user code on the satellite. Each payload maintains a persistent per-user filesystem "sandbox". User-supplied executables are run with this sandbox as the root filesystem.
- Any files generated during pre-user code execution phases will be written to deterministic locations in
/inbox
(see particular window types for details) - Any files written to
/outbox
will be queued for download and delivery to customer at the end of the window /inbox
and/outbox
are cleared between windows. Files written elsewhere will persist between window executions and may be used for staging data for transfer and processing on other payloads e.g. Sabertooth-generated waveforms for transmission on Dexter SDR or for followup operations.- The stdout/stderr from a given executable will not be downloaded automatically, but can be included in the execute logs of a script by using "exec" as shown on the right.
#!/bin/bash
exec > /outbox/a_timestamped_filename
exec 2>&1
# script goes here
...
Note that within the "sandbox" filesystem, system folders cannot be uploaded to, as they mount to system libraries used by Spire. Please refrain from uploading to any "destination_path" starting in the following paths:
- "/bin"
- "/etc"
- "/lib"
- "/lib64" # on some systems
- "/usr"
- "/dev"
- "/sys"
- "/proc"
- "/run"
- "/var"
API Standards
All responses to the API will be returned as JSON.
Successful requests will have a "data" parameter containing the results of the API call.
If the request fails, the returned JSON will have a "fault" parameter containing a dictionary with a "faultstring" parameter pointing to a string description of the error. The dictionary MAY also contain a "detail" key with additional details regarding the error. The contents of the faultstring and detail field(s) are intended for human analysis and should not be used by automated systems.
{ "fault":
{ "faultstring": "Failed to resolve API Key variable token",
"detail": {
"errorcode": "steps.oauth.v2.FailedToResolveAPIKey"
}
}
}
Data Delivery
Spire maintains a minimum retention policy for customer data. All data files generated on behalf of a customer are published directly to the customer's specified S3 bucket and then deleted from Spire systems.
To enable delivery, the customer will need to add cross-account access to the desired S3 bucket for Spire. Spire will provide detailed instructions as part of initial customer signup.
Authentication
API
Before accessing the APIs you will need an API key to authenticate against the API. This will be provided during signup.
The Tasking API uses bearer tokens to authenticate requests. Attempting to make requests to the API without a valid API Key will result in the return of an HTTP 401 "Not Authorized" response with a JSON payload containing an error message.
To ensure transport layer security, all access or communication with the APIs must be made over HTTPS.
Example Usage
In this section we will walk through tasking the constellation to orient towards a target on the ground, record radio frequency from that target, process that recording, and queue the results for download. Once downloaded, files will appear in the customer's S3 bucket.
NOTE: The Python used in these examples uses some f-string types, and thus requires a Python version of 3.6 or higher.
Authenticate
First, we set the authentication token that identifies the user and is passed to every request to the API.
HOST="https://api.orb.spire.com"
AUTH_HEADER="Authorization: Bearer YOUR_AUTH_TOKEN"
# setup for all further examples
import requests
host = 'https://api.orb.spire.com'
your_auth_token = 'EXAMPLEAUTHTOKEN'
auth = { 'Authorization': f'Bearer {your_auth_token}' }
Select satellite
To start the tasking process, we retrieve the list of taskable satellites and their supported window types. This step can be skipped if the desired satellite is already known.
We see here that FM123 has the desired capabilities (PAYLOAD_SDR is supported).
curl -X GET -H "${AUTH_HEADER}" "${HOST}/tasking/satellites"
api = host + '/tasking/satellites'
r = requests.get(api, headers=auth)
r.raise_for_status()
r.json()
{
"data": [{
"id": "FM123",
"norad_id": "12345",
"supported_windows": [
"PAYLOAD_SDR",
"PAYLOAD_SABERTOOTH",
]
}]
}
Upload processing executable
We then upload the desired post-processing binary to the selected satellite. This can be skipped if the binary has previously been uploaded as uploads persist on the satellite.
NOTE: Any stdout/stderr of an executable will not automatically be downloaded. They can, however, be included in the execute logs by using "exec" in a given uploaded script.
The destination path of the uploaded executable will be used later when we reserve our SDR window. The server will respond to the request with a JSON payload containing the ID of the upload request. See the example JSON response to the right.
SATELLITE_ID="satellite_id=FM123"
PAYLOAD="payload=SDR"
DESTINATION_PATH="destination_path=/persist/bin/phase1"
EXECUTABLE="executable=true"
QUERY_PARAMS="${SATELLITE_ID}&${PAYLOAD}&${DESTINATION_PATH}&${EXECUTABLE}"
# Create test file to upload
echo "test" > phase1
curl -X POST "${HOST}/tasking/upload?${QUERY_PARAMS}" \
-H "${AUTH_HEADER}" \
-F "file=@phase1"
api = host + '/tasking/upload'
files = { 'file': open('phase1', 'rb') }
params = {
'satellite_id': 'FM123',
'payload': 'SDR',
'destination_path': '/persist/bin/phase1',
'executable': True
}
r = requests.post(api, headers=auth, params=params, files=files)
r.raise_for_status()
r.json()
{"data": {"id": "8f76a939-609e-4042-8c97-079031af0320"}}
Check upload progress
Once submitted, the constellation will upload the requested file over subsequent contact(s). To check on the status of the upload we can make a GET request on the /upload endpoint.
Once the executable has successfully been uploaded to the satellite the response will have status "UPLOADED". See the example JSON response to the right.
curl -X GET -H "${AUTH_HEADER}" "${HOST}/tasking/uploads"
api = host + '/tasking/uploads'
r = requests.get(api, headers=auth)
r.raise_for_status()
r.json()
{
"data": [
{
"satellite_id": "FM123",
"payload": "SDR",
"destination_path": "/persist/bin/phase1",
"executable": true,
"status": "UPLOADED",
"id": "71c92e3c57bc440ea89d76c94cdf387f",
}
]
}
Look for available time slot
With the desired analysis script on the satellite, the PAYLOAD_SDR window can be scheduled.
To discover when the satellite is available for tasking, the /availability
endpoint is used.
Here we check for times the satellite is available for tasking during a 24 hour period.
This will return a list of periods when the satellite can be tasked for this operation. See the example JSON response to the right.
SATELLITE_ID="satellite_id=FM123"
WINDOW_TYPE="window_type=PAYLOAD_SDR"
START="start=$(date -u +%s)"
DURATION="duration=86400" # One day
QUERY_PARAMS="${SATELLITE_ID}&${WINDOW_TYPE}&${START}&${DURATION}"
curl -X GET -H "${AUTH_HEADER}" "${HOST}/tasking/availability?${QUERY_PARAMS}"
import time
api = host + '/tasking/availability'
params = {
'satellite_id': 'FM123',
'window_type': 'PAYLOAD_SDR',
'start': int(time.time()),
'duration': 24 * 60 * 60
}
r = requests.get(api, headers=auth, params=params)
r.raise_for_status()
r.json()
{
"data": {
"available": [
{ "start": 1599445000, "end": 1599473800 },
{ "start": 1599474400, "end": 1599503200 },
{ "start": 1599503800, "end": 1599531400 }
]
}
}
Schedule window
We now schedule the operation. We create a 10 minute PAYLOAD_SDR window with a 60 second IQ capture over the Bermuda Triangle. This analysis script analyzes this file and outputs a single file results.txt
for download with an estimated file size is 10.5 kb.
The constellation will use the download size estimate to allocate contact time for download. If generated files are larger than the downlink budget, file retrieval latency may be affected.
The server will respond to the request with the ID of the scheduled window in a JSON payload. See the example JSON response to the right.
curl -X POST "${HOST}/tasking/window" \
-H "${AUTH_HEADER}" \
-H "Content-Type: application/json" \
-d @- << EOF
{
"type": "PAYLOAD_SDR",
"satellite_id": "FM123",
"start": 1599445000,
"duration": 600,
"parameters": {
"downlink_budget": 10.5,
"adcs_config": {
"mode": "NADIR",
"aperture": "VHF"
},
"user_command": {
"executable": "/persist/bin/phase1",
"executable_arguments": [
"--cap-time", "60",
"--output", "/outbox/results.txt"
]
}
}
}
EOF
api = host + '/tasking/window'
json = {
'type': 'PAYLOAD_SDR',
'satellite_id': 'FM123',
'start': 1599445000,
'duration': 600,
'parameters': {
'downlink_budget': 10.5,
'adcs_config': {
'mode': 'NADIR',
'aperture': 'VHF',
},
'user_command': {
'executable': '/persist/bin/phase1',
'executable_arguments': [
'--cap-time', '60',
'--output', '/outbox/results.txt'
]
}
}
}
r = requests.post(api, headers=auth, json=json)
r.raise_for_status()
r.json()
{"data": {"id": "3014288"}}
Receive data
After the window successfully completes, the results.txt
file written to /outbox
will be automatically downloaded and, once received, will be pushed directly to the customer's specified S3 bucket.
API Endpoints
GET /satellites
curl -X GET -H "${AUTH_HEADER}" "${HOST}/tasking/satellites"
api = host + '/tasking/satellites'
r = requests.get(api, headers=auth)
r.raise_for_status()
r.json()
{
"data": [{
"id": "FM123",
"norad_id": "12345",
"supported_windows": [
"PAYLOAD_SDR",
"PAYLOAD_SABERTOOTH"
],
"supported_payloads: [
"SDR",
"SABERTOOTH"
]
}]
}
Returns all taskable satellites and their supported window types and payloads. See the example JSON response to the right.
GET /availability
api = host + '/tasking/availability'
params = {
'satellite_id': 'FM123',
'window_type': 'PAYLOAD_SDR',
'start': 1599445000,
'duration': 24 * 60 * 60
}
r = requests.get(api, headers=auth, params=params)
r.raise_for_status()
r.json()
SATELLITE_ID="satellite_id=FM123"
WINDOW_TYPE="window_type=PAYLOAD_SDR"
START="start=$(date -u +%s)"
DURATION="duration=86400" # One day
QUERY_PARAMS="${SATELLITE_ID}&${WINDOW_TYPE}&${START}&${DURATION}"
curl -X GET -H "${AUTH_HEADER}" "${HOST}/tasking/availability?${QUERY_PARAMS}"
{
"data": {
"available": [
{ "start": 1599445000, "end": 1599473800 },
{ "start": 1599474400, "end": 1599503200 },
{ "start": 1599503800, "end": 1599531400 }
]
}
}
Return time ranges between start and end during which the user may schedule a window of the specified type. See the example JSON response to the right.
Arguments
Name | Type | Required | Description |
---|---|---|---|
satellite_id | string | yes | |
window_type | string | yes | See Supported Windows |
start | integer | yes | epoch time |
duration | integer | yes | seconds |
paired_satellite_id | string | no | For window types that involve a pair of satellites (such as LEASE_ISL) this is the other satellite's satellite_id |
Response
Name | Type | Description |
---|---|---|
available | list | list of periods window can be scheduled within |
POST /upload
SATELLITE_ID="satellite_id=FM123"
PAYLOAD="payload=SABERTOOTH"
DESTINATION_PATH="destination_path=/persist/bin/phase1"
EXECUTABLE="executable=true"
QUERY_PARAMS="${SATELLITE_ID}&${PAYLOAD}&${DESTINATION_PATH}&${EXECUTABLE}"
# Create test file to upload
echo "test" > phase1
curl -X POST "${HOST}/tasking/upload?${QUERY_PARAMS}" \
-H "${AUTH_HEADER}" \
-F "file=@phase1"
api = host + '/tasking/upload'
files = { 'file': open('phase1', 'rb') }
params = {
'satellite_id': 'FM123',
'payload': 'SABERTOOTH',
'destination_path': '/persist/bin/phase1',
'executable': True
}
r = requests.post(api, headers=auth, params=params, files=files)
r.raise_for_status()
r.json()
{"data": {"id": "8f76a939-609e-4042-8c97-079031af0320"}}
Submit a file for upload to target satellite. The response is a JSON payload containing the ID of the upload request. See the example JSON response to the right.
No assumptions should be made regarding the structure of the ID.
Arguments
Name | Type | Required | Description |
---|---|---|---|
satellite_id | string | yes | |
payload | string | yes | See Supported Payloads |
destination_path | string | yes | path on payload |
executable | boolean | yes | |
file | multipart-encoded file | yes | |
itar | boolean | no | ITAR-tagged uploads will only be uploaded through US-based ground stations (default: false) |
GET /uploads
Returns information on files previously submitted for uploading. See the example JSON response to the right.
curl -X GET -H "${AUTH_HEADER}" "${HOST}/tasking/uploads"
api = host + '/tasking/uploads'
r = requests.get(api, headers=auth)
r.raise_for_status()
r.json()
{
"data": [
{
"satellite_id": "FM123",
"payload": "SDR",
"destination_path": "/persist/bin/phase1",
"executable": true,
"status": "PENDING",
"id": "71c92e3c57bc440ea89d76c94cdf387f",
"progress": 0,
"last_update": 1659700499.978814
},
{
"satellite_id": "FM123",
"payload": "SABERTOOTH",
"destination_path": "/persist/bin/phase2",
"executable": true,
"status": "UPLOADING",
"id": "796392e80df14f46b07b86e13d3240ec",
"progress": 13.33456773,
"last_update": 1659702459.978814
},
{
"satellite_id": "FM123",
"payload": "SDR",
"destination_path": "/persist/config/fir.txt",
"executable": false,
"status": "UPLOADED",
"id": "45c59b08df97477a84af75ca2882859a",
"progress": 100,
"last_update": 1659730499.938517
}
]
}
Additional Response Fields
Name | Type | Description |
---|---|---|
id | string | identifer for upload |
status | string | "PENDING", "UPLOADING", or "UPLOADED" |
last_update | float | timestamp of the last time the record has been updated (file has started/finished uploading, or a new segment has been uploaded) |
progress | float | Current file progress (in percent) |
POST /window
curl -X POST "${HOST}/tasking/window" \
-H "${AUTH_HEADER}" \
-H "Content-Type: application/json" \
-d @- << EOF
{
"type": "PAYLOAD_SABERTOOTH",
"satellite_id": "FM123",
"start": 1599503800,
"duration": 600,
"parameters": {
"downlink_budget": 0,
"user_command": {
"executable": "/persist/bin/generate_waveform",
"executable_arguments": [
"--period", "100",
"--amplitude", "200"
]
}
}
}
EOF
api = host + '/tasking/window'
json = {
'type': 'PAYLOAD_SABERTOOTH',
'satellite_id': 'FM123',
'start': 1599503800,
'duration': 600,
'parameters': {
'downlink_budget': 0,
'user_command': {
'executable': '/persist/bin/generate_waveform',
'executable_arguments': [
'--period', '100',
'--amplitude', '200'
]
}
}
}
r = requests.post(api, headers=auth, json=json)
r.raise_for_status()
r.json()
{"data": {"id": "3014288"}}
Schedule a new operation window. Each window type supports specific tuning arguments via the parameters
field. The set of available payload window types and their supported parameters can be found at Supported Windows.
The server will respond to the request with the ID of the scheduled window in a JSON payload. See the example JSON response to the right.
No assumptions should be made regarding the structure of the ID.
Note that if a window is meant to have a paired window scheduled on a paired satellite (e.g. LEASE_ISL), it will be automatically scheduled, as well.
Arguments
Name | Type | Required | Description |
---|---|---|---|
type | string | yes | See Supported Windows |
satellite_id | string | yes | |
start | integer | yes | epoch time |
duration | integer | yes | seconds |
parameters | parameters | yes | See parameters |
Additional Response Fields
Name | Type | Description |
---|---|---|
id | string | identifier for window |
GET /contacts
SATELLITE_ID="satellite_id=FM123"
START_LT="start_lt=1648684800" # 2022-03-31 00:00 UTC
QUERY_PARAMS="${SATELLITE_ID}&${START_LT}"
curl -X GET -H "${AUTH_HEADER}" "${HOST}/tasking/contacts?${QUERY_PARAMS}"
api = host + '/tasking/contacts'
params = { 'satellite_id': 'FM123', start_lt: 1648684800} # 2022-03-31 00:00 UTC
r = requests.get(api, headers=auth, params=params)
r.raise_for_status()
r.json()
# If more values are available, `next` will contain the URL to the next page
{
"data": [{
"id": "5f7770a7984c4b30856a3a810c1b3e2f",
"type": "BIDIR",
"satellite_id": "FM123",
"state": "PENDING_SYNC",
"start": 1599503800,
"duration": 600,
},
...
],
"next": "https://api.orb.spire.com/tasking/contacts?satellite_id=FM123&start_lt=1599553800"
}
# If there are no more values available, `next` will be null
{
"data": [{
"id": "5f7770a7984c4b30856a3a810c1b3e2f",
"type": "BIDIR",
"satellite_id": "FM123",
...
}
],
"next": null
}
List the latest contacts for a given satellite. The json object returned has two elements:
- "data": a list of contact windows
- "next": if there are additional contacts available beyond the requested time bounds, a link to the next page will be provided. If no more data is available, this field will have a value of
null
See the example JSON response to the right.
Valid statuses
Status | Description |
---|---|
PENDING_SYNC |
The contact has been accepted by the API but not yet transferred to the satellite |
SYNCED |
The contact has been transferred to the satellite |
Valid types
Status | Description |
---|---|
BIDIR |
The contact involves two-way transmissions between the satellite and a receiver |
TXO |
The contact involves only one-way satellite to receiver transmissions |
RXO |
The contact involves only one-way receiver to satellite transmissions |
Arguments
Name | Type | Required | Description |
---|---|---|---|
satellite_id | string | yes | |
start_lt | float (epoch timestamp) | no | An "upper" bound, returns all contacts with start time less than the provided epoch. May be used with or without the start_gt argument |
start_gt | float (epoch timestamp) | no | A "lower" bound, returns all contacts with start time greater than the provided epoch. May be used with or without the start_lt argument |
Additional Response Fields
Name | Type | Description |
---|---|---|
id | string | identifier for contact |
GET /windows
SATELLITE_ID="satellite_id=FM123"
PLW_START_LT="plw_start_lt=1648684800" # 2022-03-31 00:00 UTC
QUERY_PARAMS="${SATELLITE_ID}&${PLW_START_LT}"
curl -X GET -H "${AUTH_HEADER}" "${HOST}/tasking/windows?${QUERY_PARAMS}"
api = host + '/tasking/windows'
params = { 'satellite_id': 'FM123', plw_start_lt: 1648684800} # 2022-03-31 00:00 UTC
r = requests.get(api, headers=auth, params=params)
r.raise_for_status()
r.json()
# If more values are available, `next` will contain the URL to the next page
{
"data": [{
"id": "5260382",
"type": "PAYLOAD_SABERTOOTH",
"satellite_id": "FM123",
"state": "PENDING_SYNC",
"start": 1599503800,
"duration": 600,
"parameters": {
"user_command": {
"executable": "/persist/bin/generate_waveform.sh",
"executable_arguments": [
"--period", "100",
"--amplitude", "200"
],
}
},
"exit_status": null,
"ran_duration": null,
},
...
],
"next": "https://api.orb.spire.com/tasking/windows?satellite_id=FM123&plw_start_lt=1599553800"
}
# If there are no more values available, `next` will be null
{
"data": [{
"id": "5f7770a7984c4b30856a3a810c1b3e2f",
"type": "PAYLOAD_SABERTOOTH",
"satellite_id": "FM123",
...
}
],
"next": null
}
List the latest windows for a given satellite. The json object returned has two elements:
- "data": a list of payload windows
- "next": if there are additional windows available beyond the requested time bounds, a link to the next page will be provided. If no more data is available, this field will have a value of
null
See the example JSON response to the right.
Valid Synchronization States
Status | Description |
---|---|
PENDING_SYNC |
The window has been accepted by the API but not yet transferred to the satellite |
SYNCED |
The window has been transferred to the satellite |
FAILED_SYNC |
The window has not been transferred to the satellite in time for execution and will not execute |
PENDING_DELETION |
A request to delete the window has been accepted by the API but not yet confirmed |
UNKNOWN |
The window is in an unknown state, contact a Spire representative to resolve |
Once a window is in the PENDING_DELETION
state, its interval is no longer considered unavailable, so it
will be possible to schedule a new window overlapping this interval, provided other conditions for the new window
are met.
Once deletion of the window is confirmed, it is no longer listed in the GET /windows
response.
Arguments
Name | Type | Required | Description |
---|---|---|---|
satellite_id | string | yes | |
plw_start_lt | float (epoch timestamp) | no | An "upper" bound, returns all windows with start time less than the provided epoch. May be used with or without the plw_start_gt argument |
plw_start_gt | float (epoch timestamp) | no | A "lower" bound, returns all windows with start time greater than the provided epoch. May be used with or without the plw_start_lt argument |
Additional Response Fields
Name | Type | Description | Log Time |
---|---|---|---|
id | string | identifier for window | Generated when window POST command is called to create a new window |
exit_status | string | A success indicator for the given window, reading either "FAILED"/"SUCCESSFUL", and null if not yet logged | Updated when associated logged telemetry is downloaded upon window completion |
ran_duration | float | the delta between the observed payload power on and the initiated window end. "null" if not yet logged |
GET /window
ID=5260382
QUERY_PARAMS="${WINDOW_ID}"
curl -X GET -H "${AUTH_HEADER}" "${HOST}/tasking/window?${QUERY_PARAMS}"
api = host + '/tasking/window'
params = { 'id': 5260382}
r = requests.get(api, headers=auth, params=params)
r.raise_for_status()
r.json()
# GET Window Return
{
"data": {
"id": "5260382",
"type": "PAYLOAD_SABERTOOTH",
"satellite_id": "FM123",
"state": "SYNCED",
"start": 1599503800,
"duration": 600,
"parameters": {
"user_command": {
"executable": "/persist/bin/generate_waveform.sh",
"executable_arguments": [
"--period", "100",
"--amplitude", "200"
],
}
},
"exit_status": "SUCCESSFUL",
"ran_duration": 590.026757,
}
}
List the synchronization information for a given satellite window, keyed off the requested window "id". The json object returned has the same structure as a given window element in the GET /windows return.
See the example JSON response to the right.
DELETE /window
ID="id=5f7770a7984c4b30856a3a810c1b3e2f"
QUERY_PARAMS="${ID}"
curl -X DELETE -H "${AUTH_HEADER}" "${HOST}/tasking/window?${QUERY_PARAMS}"
api = host + '/tasking/window'
params = { 'id': '5f7770a7984c4b30856a3a810c1b3e2f' }
r = requests.delete(api, headers=auth, params=params)
r.raise_for_status()
r.json()
{"data": {"id": "3014288"}}
Request for a window to be deleted. If the window is in a PENDING_SYNC
or SYNCED
state this will move it to
the PENDING_DELETION
state. The deletion request may be rejected if there is no opportunity to confirm deletion with
the satellite. Once deletion is confirmed the window will no longer appear in the GET /windows
response. If deletion
cannot be confirmed the window may still execute. If the window has a paired window that was automatically scheduled on a paired satellite, the deletion of the paired window will be attempted during this request, too.
Only both windows will be deleted if they both meet the deletion requirement outlined above.
If the request is successful, the endpoint will return the id of the deleted window.
Arguments
Name | Type | Required | Description |
---|---|---|---|
id | string | yes | identifier for window to delete |
DELETE /upload
ID="id=796392e80df14f46b07b86e13d3240ec"
QUERY_PARAMS="${ID}"
curl -X DELETE -H "${AUTH_HEADER}" "${HOST}/tasking/upload?${QUERY_PARAMS}"
api = host + '/tasking/upload'
params = { 'id': '796392e80df14f46b07b86e13d3240ec' }
r = requests.delete(api, headers=auth, params=params)
r.raise_for_status()
r.json()
{"data": {"id": "796392e80df14f46b07b86e13d3240ec"}}
Remove a previously-requested upload from the upload queue.
If the specified file has already been uploaded to the satellite, an error will be throw.
If the upload is in progress, no further attempts to complete the file will be made.
If the request is successful, the endpoint will return the id of the deleted window.
Arguments
Name | Type | Required | Description |
---|---|---|---|
id | string | yes | identifier of upload to delete |
GET /quota
START="start=1707782400" # 2024-02-13 00:00 UTC
DURATION="duration=10"
QUERY_PARAMS="${START}&${DURATION}"
curl -X GET -H "${AUTH_HEADER}" "${HOST}/tasking/quota?${QUERY_PARAMS}"
api = host + '/tasking/quota'
params = { 'start': 1707782400, 'duration': 10} # 2024-02-13 00:00 UTC
r = requests.get(api, headers=auth, params=params)
r.raise_for_status()
r.json()
{
"data": {
"quotas": [
{
"scope": "PER_SATELLITE",
"resource": "TASKING_DURATION",
"usage": 0.5,
"quota": 1,
"unit": "hour",
"quota_start": 1707782400,
"quota_end": 1707868799,
"basis": "PER_DAY",
"window_type": "PAYLOAD_SDR",
"satellite_id": "FM123"
},
{
"scope": "GLOBAL",
"resource": "TASKING_DURATION",
"usage": 0.5,
"quota": 1,
"unit": "hour",
"quota_start": 1707782400,
"quota_end": 1707868799,
"basis": "PER_DAY",
"window_type": "PAYLOAD_SDR"
},
{
"scope": "PER_SATELLITE",
"resource": "DATA_GENERATION_VOLUME",
"usage": 0.2,
"quota": 1,
"unit": "GB",
"quota_start": 1707782400,
"quota_end": 1707868799,
"basis": "PER_DAY",
"window_type": "PAYLOAD_SDR",
"satellite_id": "FM123"
},
]
}
List the quota usage within an interval. Usage for each individual quota is returned for each quota "period" that overlaps with the request interval. Where a per-satellite quota exists, individual usage is detailed for each satellite. GLOBAL quotas are cummulative across satellites.
See the example JSON response to the right.
Arguments
Name | Type | Required | Description |
---|---|---|---|
start | integer | yes | epoch time |
duration | integer | yes | seconds |
Additional Response Fields
Name | Type | Description |
---|---|---|
scope | string | "PER_SATELLITE", "GLOBAL" |
resource | string | "TASKING_DURATION", "DATA_GENERATION_VOLUME" |
usage | float | quota usage in the associated quota period |
quota | float | quota allowance in the associated quota period |
unit | string | unit of measurement of the usage and quota |
quota_start | string | epoch time of the start of the quota period |
quota_end | string | epoch time of the end of the quota period |
basis | string | quota period basis - only "PER_DAY" is currently supported |
window_type | string | if the quota is specific to a window type |
satellite_id | string | if scope is "PER_SATELLITE" |
Supported Payloads
A variety of payloads with different purposes are available on Spire satellites. A satellite contains a subset of all the possible payloads. The following payloads are available on Spire satellites:
- CORAL
- DEXTER
- IPI
- MARSUPIAL
- MYRIAD
- NANO
- SABERTOOTH
- SDR
Supported Windows
LEASE_ADCS
curl -X POST "${HOST}/tasking/window" \
-H "${AUTH_HEADER}" \
-H "Content-Type: application/json" \
-d @- << EOF
{
"type": "LEASE_ADCS",
"satellite_id": "FM123",
"start": 1599445000,
"duration": 600,
"parameters": {
"adcs_config": {
"mode": "TRACKING",
"aperture": "VHF",
"target_latitude_north": 5.240337,
"target_longitude_east": -52.768472
}
}
}
EOF
api = host + '/tasking/window'
json = {
'type': 'LEASE_ADCS',
'satellite_id': 'FM123',
'start': 1599445000,
'duration': 600,
'parameters': {
'adcs_config': {
'mode': 'TRACKING',
'aperture': 'VHF',
'target_latitude_north': 5.240337,
'target_longitude_east': -52.768472
}
}
}
requests.post(api, headers=auth, json=json)
The window is used to specify that customer applications on the payloads may command the ADCS system via the local Spire Linux Agent, which allows changing the satellites orientation. It can also specify an initial orientation. Documentation about the software interfaces to the on-board ADCS system can be found here.
Type
LEASE_ADCS
parameters
Name | Type | Required | Description |
---|---|---|---|
adcs_config | adcs_config |
yes | See adcs_config |
LEASE_ISL
curl -X POST "${HOST}/tasking/window" \
-H "${AUTH_HEADER}" \
-H "Content-Type: application/json" \
-d @- << EOF
{
"type": "LEASE_ISL",
"satellite_id": "FM123",
"start": 1599445000,
"duration": 600,
"parameters": {
"isl_receive_satellite_id": "FM124"
}
}
EOF
api = host + '/tasking/window'
json = {
'type': 'LEASE_ISL',
'satellite_id': 'FM123',
'start': 1599445000,
'duration': 600,
'parameters': {
'isl_receive_satellite_id': 'FM124'
}
}
requests.post(api, headers=auth, json=json)
{"data": {"id": "3014288", "paired_id": "3014289"}}
The window is used to enable an inter-satellite communication link so that processes on the payloads can use the ISL to send data to, or receive data from, another satellite. This window will be scheduled on the satellite which will be sending data and the satellite to receive those data is specified as a parameter. Documentation about the software interfaces to transmit and receive using the ISL system can be found here.
Type
LEASE_ISL
parameters
Name | Type | Required | Description |
---|---|---|---|
isl_receive_satellite_id | string | yes | The identifier for the satellite which will be receiving data from the satellite that this window is scheduled on. |
Special POST /window Response
In the POST /window section, above, the response is noted as having a single ID returned. Since ISL windows come in pairs (i.e. one for each satellite involved), the POST /window endpoint will return a second ID. This will be the ID of the window created for the paired satellite. This will be found under an additional key, paired_id
. See the example JSON response in this section.
PAYLOAD_DEXTER
curl -X POST "${HOST}/tasking/window" \
-H "${AUTH_HEADER}" \
-H "Content-Type: application/json" \
-d @- << EOF
{
"type": "PAYLOAD_DEXTER",
"satellite_id": "FM123",
"start": 1599445000,
"duration": 240,
"parameters": {
"user_command": {
"executable": "dexter_program",
"executable_arguments": [
"--option1", "197821",
"--option2", "502812"
]
}
}
}
EOF
api = host + '/tasking/window'
json = {
'type': 'PAYLOAD_DEXTER',
'satellite_id': 'FM123',
'start': 1599445000,
'duration': 240,
'parameters': {
'user_command': {
'executable': 'dexter_program',
'executable_arguments': [
'--option1', '197821',
'--option2', '502812'
]
}
}
}
requests.post(api, headers=auth, json=json)
A PAYLOAD_DEXTER window consists of a processing phase where a customer-supplied executable is run with customer supplied arguments.
Type
PAYLOAD_DEXTER
parameters
Name | Type | Required | Description |
---|---|---|---|
user_command | user_command | yes | See user_command |
PAYLOAD_IPI
curl -X POST "${HOST}/tasking/window" \
-H "${AUTH_HEADER}" \
-H "Content-Type: application/json" \
-d @- << EOF
{
"type": "PAYLOAD_IPI",
"satellite_id": "FM123",
"start": 1599445000,
"duration": 600,
"parameters": {
"downlink_budget": 0,
"copy_from": [
{
"src_payload": "SABERTOOTH",
"src_path": "/persist/data/locations1",
"dst_path": "/persist/data/locations1"
}
],
"adcs_config": {
"mode": "TRACKING",
"aperture": "IMAGER_TBD",
"target_latitude_north": 5.240337,
"target_longitude_east": -52.768472
},
"user_command": {
"executable": "/persist/bin/capture",
"executable_arguments": [
"--duration", "60",
"--interval", "10",
"--output-dir-for-download", "/outbox/images/"
]
}
}
}
EOF
api = host + '/tasking/window'
json = {
'type': 'PAYLOAD_IPI',
'satellite_id': 'FM123',
'start': 1599445000,
'duration': 600,
'parameters': {
'downlink_budget': 0,
'copy_from': [
{
'src_payload': 'SABERTOOTH',
'src_path': '/persist/data/locations1',
'dst_path': '/persist/data/locations1'
}
],
'adcs_config': {
'mode': 'TRACKING',
'aperture': 'IMAGER_TBD',
'target_latitude_north': 5.240337,
'target_longitude_east': -52.768472
},
'user_command': {
'executable': '/persist/bin/capture',
'executable_arguments': [
'--duration', '60',
'--interval', '10,
'--output-dir-for-download', '/outbox/images/'
]
}
}
}
requests.post(api, headers=auth, json=json)
This window allows the user to run an executable on the imaging payload interface (IPI) which provides access to imaging/camera hardware. The user's executable can make use of software interfaces to trigger the capture of images on the IPI.
The window consists of two phases:
- A file copy phase during which files needed from other payloads can be copied to the payload.
- A processing phase where a customer-supplied executable is run with customer supplied arguments.
- A data retrieval phase where any files written to
/outbox
are queued for download.
Type
PAYLOAD_IPI
parameters
Name | Type | Required | Description |
---|---|---|---|
adcs_config | adcs_config | no | See adcs_config default: { "mode": "NOOP" }) |
downlink_budget | number | no | kilobytes of data to schedule for download |
copy_from | list of copy_from | no | See copy_from (default: []) |
user_command | user_command | yes | See user_command |
PAYLOAD_SDR
curl -X POST "${HOST}/tasking/window" \
-H "${AUTH_HEADER}" \
-H "Content-Type: application/json" \
-d @- << EOF
{
"type": "PAYLOAD_SDR",
"satellite_id": "FM123",
"start": 1599445000,
"duration": 600,
"parameters": {
"downlink_budget": 0,
"copy_from": [
{
"src_payload": "SABERTOOTH",
"src_path": "/persist/data/waveform1",
"dst_path": "/persist/data/waveform1"
}
],
"adcs_config": {
"mode": "TRACKING",
"aperture": "SBAND_SDR",
"target_latitude_north": 5.240337,
"target_longitude_east": -52.768472
},
"user_command": {
"executable": "/persist/bin/phase1",
"executable_arguments": [
"--input", "/persist/data/waveform1",
"--output", "/output/results.txt"
]
}
}
}
EOF
api = host + '/tasking/window'
json = {
'type': 'PAYLOAD_SDR',
'satellite_id': 'FM123',
'start': 1599445000,
'duration': 600,
'parameters': {
'downlink_budget': 0,
'copy_from': [
{
'src_payload': 'SABERTOOTH',
'src_path': '/persist/data/waveform1',
'dst_path': '/persist/data/waveform1'
}
],
'adcs_config': {
'mode': 'TRACKING',
'aperture': 'SBAND_SDR',
'target_latitude_north': 5.240337,
'target_longitude_east': -52.768472
},
'user_command': {
'executable': '/persist/bin/phase1',
'executable_arguments': [
'--input', '/persist/data/waveform1',
'--output', '/output/results.txt'
]
}
}
}
requests.post(api, headers=auth, json=json)
This is an updated version of the PAYLOAD_SDR window (the old version is no longer supported). It allows the user to run an
executable on the software defined radio (SDR) payload. The supplied executable can make use of software
interfaces to send or receive signals with the SDR payload. The previous version of the window included
a capture_config
, which has been replaced with the following applications, which can be used in a user_command
,
either invoked directly or included in a script etc. Further documentation can be found here.
RFCollect
RFTransmit
IQGenerator
The window consists of three phases:
- A file copy phase during which files needed from other payloads can be copied to the payload. (Noted earlier as "pre-buffer.")
- A processing phase where a customer-supplied executable is run with customer supplied arguments.
- A data retrieval phase where any files written to
/outbox
are queued for download. (Noted earlier as "post-buffer.")
IQ Capture Size Limitations
Captured IQ files in uncompressed form must not exceed 1GB in size due to payload memory constraints.
To calculate the uncompressed file size for a capture, a useful upper bound (in kB) can be found by solving 4 * sample_rate_khz * capture_duration
rounded up to the nearest 16kB.
Note: The compressed file will likely be much smaller though actual compression ratios depend on signal parameters and will need to be determined experimentally.
Type
PAYLOAD_SDR
parameters
Name | Type | Required | Description |
---|---|---|---|
adcs_config | adcs_config | no | See adcs_config default: { "mode": "NOOP" }) |
downlink_budget | number | no | kilobytes of data to schedule for download |
copy_from | list of copy_from | no | See copy_from (default: []) |
user_command | user_command | yes | See user_command |
Compute Boards
curl -X POST "${HOST}/tasking/window" \
-H "${AUTH_HEADER}" \
-H "Content-Type: application/json" \
-d @- << EOF
{
"type": "PAYLOAD_SABERTOOTH",
"satellite_id": "FM123",
"start": 1599445000,
"duration": 600,
"parameters": {
"downlink_budget": 0,
"copy_from": [
{
"src_payload": "SDR",
"src_path": "/persist/data/phase1",
"dst_path": "/persist/data/phase1"
}
],
"user_command": {
"executable": "/persist/bin/phase2",
"executable_arguments": [
"--input", "/persist/data/phase1",
"--save-waveform", "/persist/data/waveform1",
"--output-for-download", "/outbox/phase2.out"
]
}
}
}
EOF
api = host + '/tasking/window'
json = {
'type': 'PAYLOAD_SABERTOOTH',
'satellite_id': 'FM123',
'start': 1599445000,
'duration': 600,
'parameters': {
'downlink_budget': 0,
'copy_from': [
{
'src_payload': 'SDR',
'src_path': '/persist/data/phase1',
'dst_path': '/persist/data/phase1'
}
],
'user_command': {
'executable': '/persist/bin/phase2',
'executable_arguments': [
'--input', '/persist/data/phase1',
'--save-waveform', '/persist/data/waveform1',
'--output-for-download', '/outbox/phase2.out'
]
}
}
}
requests.post(api, headers=auth, json=json)
A PAYLOAD_SABERTOOTH, PAYLOAD_MARSUPIAL, PAYLOAD_CORAL, PAYLOAD_NANO or PAYLOAD_MYRIAD window consists of three phases:
- A file copy phase during which files needed from other payloads, if any, are copied to the compute board.
- A processing phase where a customer-supplied executable is run with customer supplied arguments
- A data retrieval phase where any files written to
/outbox
are queued for download
A common use of phase 1 is to retrieve raw or partially processed IQ files from a previous PAYLOAD_SDR window for further processing. See code example in sidebar.
Type
PAYLOAD_SABERTOOTH
: NVIDIA Tegra TX2iPAYLOAD_MARSUPIAL
: Xilinx UltraScale+ ZU4CGPAYLOAD_CORAL
: Coral dev BoardPAYLOAD_NANO
: NVIDIA Jetson NanoPAYLOAD_MYRIAD
: UP Vision Plus X
parameters
Name | Type | Required | Description |
---|---|---|---|
downlink_budget | number | no | kilobytes of data to schedule for download |
copy_from | list of copy_from | no | See copy_from (default: []) |
user_command | user_command | yes | See user_command |
MAINTENANCE for Brain-in-Space Compute Boards
curl -X POST "${HOST}/tasking/window" \
-H "${AUTH_HEADER}" \
-H "Content-Type: application/json" \
-d @- << EOF
{
"type": "MAINTENANCE",
"satellite_id": "FM123",
"start": 1599445000,
"duration": 600,
"parameters": {
"subsystems": ["SABERTOOTH", "MYRIAD"],
}
}
EOF
api = host + '/tasking/window'
json = {
'type': 'MAINTENANCE',
'satellite_id': 'FM123',
'start': 1599445000,
'duration': 600,
'parameters': {
'subsystems': ['SABERTOOTH', 'MYRIAD'],
}
}
requests.post(api, headers=auth, json=json)
The MAINTENANCE window is currently only allowed for ground-side testbeds. It will power up the specified payload(s), as well as ethernet, for access into that payload. Nothing will be executed for the payload. Near the end of the window, the payload(s) will be shutdown.
Only those payloads that are granted access to the user can be powered on for maintenance.
Note: Ground-side testbeds will have a different naming format to the satellite_id
than FM123
. This information will be provided to you at introduction.
parameters
Name | Type | Required | Description |
---|---|---|---|
subsystems | list | yes | a list of payloads to power on during for access. Choose from "SABERTOOTH", "MARSUPIAL", "CORAL", "NANO", "MYRIAD" |
Schemas
parameters
The parameters
field is a dictionary containing payload window type-specific tuning options. Each payload window type has different parameter sets. See links below.
Windows are configured via the parameters
field. Different payload window types take different parameters.
Window Type | parameters |
---|---|
Compute boards | parameters |
LEASE_ADCS | parameters |
LEASE_ISL | parameters |
PAYLOAD_DEXTER | parameters |
PAYLOAD_IPI | parameters |
PAYLOAD_SDR | parameters |
user_command
Name | Type | Required | Description |
---|---|---|---|
executable | string | yes | path to executable to run |
executable_arguments | list of strings | yes | arguments to pass to executable |
adcs_config
The ADCS can operate in six modes "AUTONOMOUS", "NADIR", "TRACKING", "LINESCAN", "FIXED_PITCH" or "NOOP".
- #. In "AUTONOMOUS", the window has ADCS command control, but allows the ADCS module to autonomously engage in regular activities for power or thermal management activities.
- #. In "NADIR", the satellite points the specified aperture towards the center of the earth.
- #. In "TRACKING", the satellite points the specified aperture at a specific lat/lon coordinate on the surface of the earth.
- #. In "LINESCAN", the satellite points to NADIR, plus a roll angle, left or right from the orbital path
- #. In "FIXED_PITCH", the satellite points to NADIR, plus a pitch angle, forward or backward along the orbital path
- #. In "NOOP", no ADCS request is issued so this window does not compete for ADCS control during its execution.
If no "adcs_config" field is specified, the same behaviour as configuring "NOOP" mode should be expected.
Name | Type | Required |
---|---|---|
mode | string | yes |
target_latitude_north | number | if mode == "TRACKING" |
target_longitude_east | number | if mode == "TRACKING" |
aperture | string | if mode other than "NOOP" or "AUTONOMOUS" |
yaw_deg | number | optional, if mode == "NADIR" |
pitch_deg | number | optional, if mode == "NADIR" |
roll_deg | number | optional, if mode == "NADIR" |
Valid modes are: "AUTONOMOUS", "NADIR", "TRACKING", "LINESCAN", or "FIXED_PITCH", "NOOP". Some valid apertures are: "VHF", "UHF", "ADSB", "GNSS", "SBAND_DEXTER", and "SBAND_SDR"
copy_from
The data needed to complete a window may exist on a different payload, commonly as the output of a previous command. To instruct the satellite controller to retrieve this data before executing the user command, these dependencies are listed a sequence of copy operations. Each copy operation indicates the following:
Name | Type | Required | Description |
---|---|---|---|
src_payload | string | yes | "IPI", "SDR" or "SABERTOOTH" |
src_path | string | yes | path |
dst_path | string | yes | path |