SDK
The Cecil SDK is an open source Python library that allows you to use the Cecil platform. The SDK integrates with Cecil's internal API using standard HTTP methods, authentication, and response codes. Data resources use RFC 3339 timestamps and universally unique identifiers (UUID v4).
Release notes: https://github.com/cecilearth/sdk/blob/main/CHANGELOG.md
Installation
Install the SDK in your project virtual environment. Python ≥ 3.10 is required.
pip install cecilAuthentication
Configure the SDK by setting the CECIL_API_KEY environment variable. Only store your API key in an encrypted vault or secrets manager, never in code or plain/text files. Don't have an account? Sign up.
# Linux and macOS
export CECIL_API_KEY="my-api-key"
# Windows PowerShell
$env:CECIL_API_KEY = "my-api-key"Usage
All SDK functions require authentication unless otherwise specified.
import cecil
client = cecil.Client()
client.function_name()AOI
The area of interest (AOI) represents a geographic area.
Property | Type | Description |
|---|---|---|
| uuid | Unique identifier. |
| object | GeoJSON geometry object in |
| string | External reference in your system, e.g. AOI ID or name. |
| float | Total size derived from the geometry. This is useful for cost tracking. |
| datetime | Current system time when the AOI was created. |
| uuid | Authenticated user who created the AOI. |
| datetime | Current system time when the AOI was archived, or null. |
| uuid | Authenticated user who archived the AOI, or null. |
The AOI geometry is a GeoJSON geometry object in EPSG:4326 delimiting the AOI boundaries.
Property | Type | Description |
|---|---|---|
| string | Polygon or MultiPolygon. |
| array | Nested array of coordinates according to the geometry |
Create AOI
This function allows you to create an AOI.
Input
client.create_aoi(
external_ref="123",
geometry={
"type": "Polygon",
"coordinates": [[
[132.52934211276073, -12.721072673008706],
[132.52934211276073, -12.730063400794094],
[132.54027735328083, -12.730063400794094],
[132.54027735328083, -12.721072673008706],
[132.52934211276073, -12.721072673008706],
]],
},
)Output
AOI(
id="fa200894-4e13-456c-872a-ba8efcda0812",
external_ref="123",
geometry={
"type": "Polygon",
"coordinates": [[
[132.52934211276073, -12.721072673008706],
[132.52934211276073, -12.730063400794094],
[132.54027735328083, -12.730063400794094],
[132.54027735328083, -12.721072673008706],
[132.52934211276073, -12.721072673008706],
]],
},
hectares=118.12168458669186,
created_at=datetime.datetime(2000, 1, 1, 0, 0, 0, 0, tzinfo=TzInfo(UTC)),
created_by="51f9cf7c-78f5-49e0-b6fd-ba281346ae3f",
archived_at=None,
archived_by=None,
)List AOIs
This function allows you to list all AOIs that are currently active (not archived) in your organisation. You can optionally pass in archived=True to list all archived AOIs.
Input
client.list_aois(archived=False)Output
[
AOI(
id="fa200894-4e13-456c-872a-ba8efcda0812",
external_ref="123",
hectares=118.12168458669186,
created_at=datetime.datetime(2000, 1, 1, 0, 0, 0, 0, tzinfo=TzInfo(UTC)),
created_by="51f9cf7c-78f5-49e0-b6fd-ba281346ae3f",
archived_at=None,
archived_by=None,
),
]Get AOI
This function allows you to get an AOI by ID, regardless of being archived.
Input
client.get_aoi("fa200894-4e13-456c-872a-ba8efcda0812")Output
AOI(
id="fa200894-4e13-456c-872a-ba8efcda0812",
external_ref="123",
geometry={
"type": "Polygon",
"coordinates": [[
[132.52934211276073, -12.721072673008706],
[132.52934211276073, -12.730063400794094],
[132.54027735328083, -12.730063400794094],
[132.54027735328083, -12.721072673008706],
[132.52934211276073, -12.721072673008706],
]],
},
hectares=118.12168458669186,
created_at=datetime.datetime(2000, 1, 1, 0, 0, 0, 0, tzinfo=TzInfo(UTC)),
created_by="51f9cf7c-78f5-49e0-b6fd-ba281346ae3f",
archived_at=None,
archived_by=None,
)Archive AOI
This function allows you to archive an AOI by ID. When you archive an AOI, associated subscriptions remain available, but new subscriptions can no longer be created for the archived AOI.
Input
client.archive_aoi("fa200894-4e13-456c-872a-ba8efcda0812")Output
No contentRestore AOI
This function allows you to restore an AOI by ID. You can restore an AOI from the archive at any time.
Input
client.restore_aoi("fa200894-4e13-456c-872a-ba8efcda0812")Output
No contentDataset
The dataset represents a product offering by a data provider. All dataset information available in the SDK uses the same source of truth as the list of datasets in the documentation.
Property | Type | Description |
|---|---|---|
| uuid | Unique identifier. |
| string | Dataset name. |
| string | Data provider name. |
| string | Category as specified in the Cecil dataset documentation. |
| string | Data type: |
| string | CRS as specified in the Cecil dataset documentation. |
| string | Version number as published by the data provider. |
| string | Release date for the corresponding version number. |
List datasets
This function allows you to list all datasets available in the Cecil platform.
Input
client.list_datasets()Output
[
Dataset(
id="f42f8f48-6cf9-48af-8453-be6cca46acb8",
name="Protected Species",
provider_name="Acme Earth",
category="Biodiversity integrity",
type="Raster",
crs="EPSG:4326",
version_number="1.0",
version_date="2025",
),
]Subscription
The subscription represents a dataset acquisition for your AOI.
Property | Type | Description |
|---|---|---|
| uuid | Unique identifier. |
| string | Unique identifier of the AOI associated with this subscription. |
| string | Unique identifier of the dataset associated with this subscription. You can find this information on the details page of available datasets. |
| string | External reference in your system, e.g. data subscription ID, use case ID, or description of the use case. |
| datetime | Current system time when the subscription was created. |
| uuid | Authenticated user who created the subscription. |
| datetime | Current system time when the subscription was archived, or null. |
| uuid | Authenticated user who archived the subscription, or null. |
Create subscription
This function allows you to acquire datasets for your AOI. This process runs in the background and may take from a few minutes to a few business days depending on the data provider.
Input
client.create_subscription(
aoi_id="fa200894-4e13-456c-872a-ba8efcda0812",
dataset_id="f42f8f48-6cf9-48af-8453-be6cca46acb8",
external_ref="123",
)Output
Subscription(
id="f644efb3-8ba4-4bc4-8333-1ace54a3f111",
aoi_id="fa200894-4e13-456c-872a-ba8efcda0812",
dataset_id="f42f8f48-6cf9-48af-8453-be6cca46acb8",
external_ref="123",
created_at=datetime.datetime(2000, 1, 1, 0, 0, 0, 0, tzinfo=TzInfo(UTC)),
created_by="51f9cf7c-78f5-49e0-b6fd-ba281346ae3f",
archived_at=None,
archived_by=None,
)List subscriptions
This function allows you to list all subscriptions that are currently active (not archived) in your organisation. You can optionally pass in archived=True to list all archived subscriptions.
Input
client.list_subscriptions(archived=False)Output
[
Subscription(
id="f644efb3-8ba4-4bc4-8333-1ace54a3f111",
aoi_id="fa200894-4e13-456c-872a-ba8efcda0812",
dataset_id="f42f8f48-6cf9-48af-8453-be6cca46acb8",
external_ref="123",
created_at=datetime.datetime(2000, 1, 1, 0, 0, 0, 0, tzinfo=TzInfo(UTC)),
created_by="51f9cf7c-78f5-49e0-b6fd-ba281346ae3f",
archived_at=None,
archived_by=None,
),
]Get subscription
This function allows you to get a subscription by ID, regardless of being archived.
Input
client.get_subscription("f644efb3-8ba4-4bc4-8333-1ace54a3f111")Output
Subscription(
id="f644efb3-8ba4-4bc4-8333-1ace54a3f111",
aoi_id="fa200894-4e13-456c-872a-ba8efcda0812",
dataset_id="f42f8f48-6cf9-48af-8453-be6cca46acb8",
external_ref="123",
created_at=datetime.datetime(2000, 1, 1, 0, 0, 0, 0, tzinfo=TzInfo(UTC)),
created_by="51f9cf7c-78f5-49e0-b6fd-ba281346ae3f",
archived_at=None,
archived_by=None,
)Archive subscription
This function allows you to archive a subscription by ID. When you archive a subscription, you have a grace period of 30 days to restore the subscription. Once the grace period is over, the subscription can no longer be restored from the archive, and the subscription data is permanently deleted.
Input
client.archive_subscription("f644efb3-8ba4-4bc4-8333-1ace54a3f111")Output
No contentRestore subscription
This function allows you to restore a subscription by ID within the archive grace period.
Input
client.restore_subscription("f644efb3-8ba4-4bc4-8333-1ace54a3f111")Output
No contentData access
You can access Cecil datasets with the following functions. Additionally, you can develop interactive data visualisations with the Earthscale integration.
Function | Dataset type |
|---|---|
Load xarray |
|
Load dataframe |
|
Load xarray
This function loads a raster dataset into an xarray.Dataset for an active subscription. Raster datasets always have x, y dimensions and most times a time dimension. The following metadata is available in dataset-level attributes. See datasets for usage notes.
Dimension | Type | Units |
|---|---|---|
| Per dataset variable | Per CRS. |
| Per dataset variable | Per CRS. |
| datetime | Per dataset, when a time dimension is available. |
Metadata |
|---|
|
|
|
|
|
Input
client.load_xarray(
subscription_id="f644efb3-8ba4-4bc4-8333-1ace54a3f111",
)Output
<xarray.Dataset> Size: 3MB
Dimensions: (x: 50, y: 50, time: 20)
Coordinates:
* x (x) float64 512B 68.57 68.57 68.57 ... 68.56 68.56
* y (y) float64 512B 45.78 45.78 45.78 ... 45.76 45.76 45.76
* time (time) datetime64[ns] 2kB 2021-03-21 ... 2025-12-21
Data variables:
canopy_cover (x, y, time) float64 3MB dask.array<chunksize=(50, 50, 1), meta=np.ndarray>
canopy_height (x, y, time) float64 3MB dask.array<chunksize=(50, 50, 1), meta=np.ndarray>
Attributes:
provider_name: Planet
dataset_name: Forest Carbon Monitoring
dataset_id: f42f8f48-6cf9-48af-8453-be6cca46acb8
aoi_id: fa200894-4e13-456c-872a-ba8efcda0812
subscription_id: f644efb3-8ba4-4bc4-8333-1ace54a3f111Load dataframe
This function loads a vector dataset into a pandas.DataFrame for an active subscription. Vector datasets have the following metadata in dataframe columns. See datasets for usage notes.
Metadata |
|---|
|
|
Input
client.load_dataframe(
subscription_id="f644efb3-8ba4-4bc4-8333-1ace54a3f111",
)Output
canopy_cover timestamp
0 0.73 datetime.datetime(2021, 1, 1, 0, 0, 0, 0, tzinfo=TzInfo(UTC))
1 0.79 datetime.datetime(2022, 1, 1, 0, 0, 0, 0, tzinfo=TzInfo(UTC))
2 0.87 datetime.datetime(2023, 1, 1, 0, 0, 0, 0, tzinfo=TzInfo(UTC))
[3 rows x 2 columns]Webhooks
Webhooks allow you to receive real-time notifications from the Cecil platform. The webhook url must use https, handle POST requests, and return a successful status (200-299) within 10 seconds. Failed requests will be retried 3 times at an interval of approximately 12 hours.
Property | Type | Description |
|---|---|---|
| uuid | Unique identifier. |
| string | Your application URL to receive webhook events. |
| string | Optional secret for signature validation. |
| datetime | Current system time when the webhook was created. |
| uuid | Authenticated user who created the webhook. |
Create webhook
This function allows you to create a webhook.
Input
client.create_webhook(
url="https://api.example.com/cecil-webhook",
secret="YT5MzU9xk3dhMDjZ",
)Output
Webhook(
id="fc9dbf41-a44c-4f13-8bac-1920dd98c39f",
url="https://api.example.com/cecil-webhook",
created_at=datetime.datetime(2000, 1, 1, 0, 0, 0, 0, tzinfo=TzInfo(UTC)),
created_by="51f9cf7c-78f5-49e0-b6fd-ba281346ae3f",
)List webhooks
This function allows you to list all webhooks in your organisation.
Input
client.list_webhooks()Output
[
Webhook(
id="fc9dbf41-a44c-4f13-8bac-1920dd98c39f",
url="https://api.example.com/cecil-webhook",
created_at=datetime.datetime(2000, 1, 1, 0, 0, 0, 0, tzinfo=TzInfo(UTC)),
created_by="51f9cf7c-78f5-49e0-b6fd-ba281346ae3f",
),
]Get webhook
This function allows you to get a webhook by ID.
Input
client.get_webhook("fc9dbf41-a44c-4f13-8bac-1920dd98c39f")Output
Webhook(
id="fc9dbf41-a44c-4f13-8bac-1920dd98c39f",
url="https://api.example.com/cecil-webhook",
created_at=datetime.datetime(2000, 1, 1, 0, 0, 0, 0, tzinfo=TzInfo(UTC)),
created_by="51f9cf7c-78f5-49e0-b6fd-ba281346ae3f",
)Delete webhook
This function allows you to delete a webhook by ID, stopping notifications immediately.
Input
client.delete_webhook("fc9dbf41-a44c-4f13-8bac-1920dd98c39f")Output
No contentSignature validation
We recommend you to use the Cecil-Signature header to validate the authenticity and integrity of webhook events. Below is a code example in Python.
import hashlib
import hmac
body = "raw request body received in the http request"
signature = "raw value from the Cecil-Signature header"
secret = "your-webhook-secret"
digest = hmac.new(
digestmod=hashlib.sha256
key=secret.encode("utf-8"),
msg=body.encode("utf-8"),
).hexdigest()
if hmac.compare_digest(digest, signature):
print("valid")Events
Webhook notifications include the following events.
Event name | Event type |
|---|---|
Subscription delivered |
|
Subscription failed |
|
Subscription delivered
This event notifies that a data chunk has been delivered for a Subscription.
For datasets with a time dimension, this includes data for a specific variable and time step.
For datasets without a time dimension, this includes data for a specific variable and an explicit
nullvalue for thepayload.timeproperty.
Example
{
"event_id": "f309e366-13dc-5f6c-8cad-c0c3c34bb548",
"event_type": "subscription.delivered",
"payload": {
"aoi_id": "fa200894-4e13-456c-872a-ba8efcda0812",
"subscription_id": "f644efb3-8ba4-4bc4-8333-1ace54a3f111",
"dataset_id": "f42f8f48-6cf9-48af-8453-be6cca46acb8",
"dataset_type": "raster",
"time": "2026-01-09T00:00:00Z",
"variable": "x_value"
},
"recorded_at": "2026-01-01T15:30:09.033Z"
}Subscription failed
This event notifies that a Subscription has failed to process. Possible failures are data not found for the specified AOI, or due to technical constraints from data providers, in which case, the payload.error_message contains the original error message from the data provider.
Example
{
"event_id": "f309e366-13dc-5f6c-8cad-c0c3c34bb548",
"event_type": "subscription.failed",
"payload": {
"aoi_id": "fa200894-4e13-456c-872a-ba8efcda0812",
"subscription_id": "f644efb3-8ba4-4bc4-8333-1ace54a3f111",
"dataset_id": "f42f8f48-6cf9-48af-8453-be6cca46acb8",
"dataset_type": "vector",
"error_message": "Data not found."
},
"recorded_at": "2026-01-01T15:30:09.033Z"
}Organisation settings
Organisation settings allow you to configure the following organisation-wide settings.
Property | Type | Description |
|---|---|---|
| integer | Number of hectares across subscriptions that can be created per month. This value can only be configured for verified organisations. Please contact us to verify your organisation. Default: 50,000. |
Get organisation settings
This function allows you to view your organisation settings.
Input
client.get_organisation_settings()Output
OrganisationSettings(
monthly_subscription_limit=50_000,
)Update organisation settings
This function allows you to update your organisation settings.
Input
client.update_organisation_settings(
monthly_subscription_limit=50_000,
)Output
OrganisationSettings(
monthly_subscription_limit=50_000,
)User management
User management allows creating and viewing users in your organisation.
Property | Type | Description |
|---|---|---|
| uuid | Unique identifier. |
| string | First name. |
| string | Last name. |
| string | Email address. |
| datetime | Current system time when the user was created. |
| uuid | Authenticated user who created the user. |
Create user
This function allows you to create an organisation user. The new user will receive an email with instructions to generate their API key. The link sent via email expires in 7 days. If the link expires, the recover function can be used to generate their API key.
Input
client.create_user(
first_name="John",
last_name="Smith",
email="john.smith@greenfield.com",
)Output
User(
id="624e5cc3-aaf3-4b35-a92b-352f0d102daf",
first_name="John",
last_name="Smith",
email="john.smith@greenfield.com",
created_at=datetime.datetime(2000, 1, 1, 0, 0, 0, 0, tzinfo=TzInfo(UTC)),
created_by="51f9cf7c-78f5-49e0-b6fd-ba281346ae3f",
)List users
This function allows you to list all users in your organisation.
Input
client.list_users()Output
[
User(
id="624e5cc3-aaf3-4b35-a92b-352f0d102daf",
first_name="John",
last_name="Smith",
email="john.smith@greenfield.com",
created_at=datetime.datetime(2000, 1, 1, 0, 0, 0, 0, tzinfo=TzInfo(UTC)),
created_by="51f9cf7c-78f5-49e0-b6fd-ba281346ae3f",
),
]Get user
This function allows you to get a user by ID.
Input
client.get_user("624e5cc3-aaf3-4b35-a92b-352f0d102daf")Output
User(
id="624e5cc3-aaf3-4b35-a92b-352f0d102daf",
first_name="John",
last_name="Smith",
email="john.smith@greenfield.com",
created_at=datetime.datetime(2000, 1, 1, 0, 0, 0, 0, tzinfo=TzInfo(UTC)),
created_by="51f9cf7c-78f5-49e0-b6fd-ba281346ae3f",
)API key management
We recommend all users to automatically rotate their API keys on a regular basis. Users can also recover their API key via email.
Rotate API key
This function allows users to rotate their API key. This is useful to improve your organisation security by implementing an automated process that rotates API keys on a regular basis.
Input
client.rotate_api_key()Output
RotateAPIKey(
new_api_key="NzhjMWQwNjE1OGRhZDYxZDkxMWZlZjU1MWI1OTVlMmIK",
)Recover API key
This function allows users to recover their API key via email. If we find a user with the email address provided, the user will receive an email with instructions to recover their API key. The link sent via email expires in 7 days. This function doesn’t require authentication.
Input
client.recover_api_key("jane.doe@foo.com")Output
RecoverAPIKey(
message="Please follow the instructions sent via email.",
)