Commercial data quotes and orders¶
Description & purpose: This notebook acts as an introduction to obtaining quotes, and ordering commercial data, programatically.
Storing and loading your API key securely¶
To securely store and use your API key in this notebook, follow these steps:
Generate an API key:
- Follow instructions in the Getting Started documentation for Hub APIs to generate a Hub API Key.
Create a
.envFile:In the same directory as this notebook, create a file named
.env.Add the following line to the file, replacing
<your_api_key>with your actual API key:plaintext API_KEY=<your_api_key>Save the file.
Load the Key in the Notebook:
- The following code snippet will load the key securely:
import os
from dotenv import load_dotenv
load_dotenv(".env") # Ensure the path matches your `.env` file location
api_key = os.getenv("API_KEY")
- This will load the
API_KEYfrom your.envfile into thekeyvariable.
- Keep your
.envFile Secure:- Do not share your
.envfile or API key. - If you do accidentally share your key, delete it in the workspaces UI and request a new one.
- Do not share your
By following these steps, you can securely store and use your API key without exposing it in the notebook.
Setting up your Workspace and Environment¶
To ensure the notebook works correctly, you need to configure the workspace and environment variables. Follow these steps:
Ensure your workspace is configured for commercial orders
- Follow instructions in the Hub documentation under
Data - Commercialto link your commercial account to your workspace.
- Follow instructions in the Hub documentation under
Set the
workspaceVariable:- In the following cell, the
workspacevariable should be set to the name of the workspace you wish to order data for. - You can find the workspace name in the site UI.
- In the following cell, the
workspace = "gemmaprodtest" # alter as required
import requests
import pyeodh
import shapely
Ordering Airbus commercial data¶
Search and ordering capabilities are in place for Airbus Optical items. Once an item of interest is found, you may obtain a quote for the item via a POST request to /quote following the item href.
Change the item_href to any valid link to a STAC item in our Airbus commercial catalogue to browse prices. Change the coordinates to an AOI to clip the item if required.
Note: Coordinates are to be provided in longitude/latitude WGS84, and the polygon must be closed. Coordinates follow OGC GeoJSON specification.
Change the licence to another supported licence if required. Supported licences are:
StandardBackground LayerStandard + Background LayerAcademicMedia LicenceStandard Multi End-Users (2-5)Standard Multi End-Users (6-10)Standard Multi End-Users (11-30)Standard Multi End-Users (>30)
The following code blocks provide an example of how to place an order for clipped Airbus Pelides Neo imagery with a Standard Multi End-Users (2-5) licence.
# Find the data
client = pyeodh.Client(
base_url="https://eodatahub.org.uk"
).get_catalog_service()
# We want to use Pleides NEO data
pneo_cat = client.get_catalog("commercial/catalogs/airbus").get_collection('airbus_pneo_data')
print("id: ", pneo_cat.id)
print("title: ", pneo_cat.title)
print("description: ", pneo_cat.description)
# Define the site
lon, lat = (-3.37218324, 51.53536320) # Caerphilly
wf_pnt = shapely.Point(lon, lat)
items = client.search(
collections=['airbus_pneo_data'],
catalog_paths=["commercial/catalogs/airbus"],
intersects = wf_pnt,
)
# We can then count the number of items returned by the search
total_items = sum(1 for _ in items)
print(f"Total items: {total_items}")
If we know that the image we want is ACQ_PNEO4_06029801689587 then we can just pick that out. We would know this by finding the data using the Resource Catalogue front end. Alternatively, the client.search could include other filters that narrow the results to an image a user may want to purchase.
image_id = "ACQ_PNEO4_06029801689587"
for item in items:
if item.id == image_id:
quicklook_href = item.assets["quicklook"].href
item_href = quicklook_href.removesuffix("/quicklook")
print(item.id, item_href)
# Define variables
product_bundle = "Analytic" # "General Use", "Visual", "Basic", "Analytic"
licence_type = "Standard Multi End-Users (2-5)"
countrycode = "GB"
# Bounding box (min_lon, min_lat, max_lon, max_lat)
bbox = (-2.198833134075246, 57.11270465250282,
-2.039788856021223, 57.19006479564655)
# Convert bbox to polygon coordinates
coordinates = [[
[bbox[0], bbox[1]], # bottom-left
[bbox[2], bbox[1]], # bottom-right
[bbox[2], bbox[3]], # top-right
[bbox[0], bbox[3]], # top-left
[bbox[0], bbox[1]] # close polygon
]]
# Request quote for data
url = f"{item_href}/quote" #<--- specifies quote
headers = {
'accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': f'Bearer {api_key}'
}
data = {
"licence": licence_type,
"coordinates": coordinates
}
response = requests.post(url, headers=headers, json=data)
print("Status Code", response.status_code)
print("Response ", response.json())
# Reqest order for data
url = f"{item_href}/order" #<--- places the order
headers = {
'accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': f'Bearer {api_key}'
}
# Final data structure
data = {
"productBundle": product_bundle,
"licence": licence_type,
"endUserCountry": countrycode,
"coordinates": coordinates
}
print("Status Code", response.status_code)
print("Response ", response.json())
location_header = response.headers.get('Location')
print("Item will shortly be available at:", location_header)
Ordering Planet commercial data¶
In the following example, our client is scoped to the Planet catalogue to refine a search for some Planet commercial data. We can use the same pyeodh functions as long as we scope it to the correct STAC collection. The cell below provides an example.
client = pyeodh.Client(
base_url="https://eodatahub.org.uk"
).get_catalog_service()
# We want to use the PlanetScope data
ps_cat = client.get_catalog("commercial/catalogs/planet").get_collection('PSScene')
print("id: ", ps_cat.id)
print("title: ", ps_cat.title)
print("description: ", ps_cat.description)
We can bypass repeating the cells above for the sake of brevity, but a user would be able to undertake the same assessment of the collection. Let us assume that we have our Planet URL for data also over Caerphilly.
item_href = "https://eodatahub.org.uk/api/catalogue/stac/catalogs/commercial/catalogs/planet/collections/PSScene/items/20260325_111721_74_2545"
# Request quote for Planet data
url = f"{item_href}/quote"
headers = {
'accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': f'Bearer {api_key}'
}
data = {
"coordinates": coordinates
}
response = requests.post(url, headers=headers, json=data)
print("Status Code", response.status_code)
print("Response ", response.json())
# Request order for Planet data
url = f"{item_href}/order"
headers = {
'accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': f'Bearer {api_key}'
}
data = {
"productBundle": "General use",
"coordinates": coordinates
}
response = requests.post(url, headers=headers, json=data)
print("Status Code:", response.status_code)
print("Response:", response.json())
location_header = response.headers.get('Location')
print("Item will shortly be available at:", location_header)
You can check your workspace to see when the data has been delivered.
Author(s): Gemma Newbold, Alastair Graham
Date created: 2026-03-25
Date last modified: 2026-03-25
Licence: This notebook is licensed under Creative Commons Attribution-ShareAlike 4.0 International. The code is released using the BSD-2-Clause license.
Copyright © - All rights reserved.Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.