API Mechanics: Get Started with Subscriptions

last updated: May 31, 2024

API mechanics

Get Started with Planet APIs explains how to get your API key and how to work with Planet APIs in general. Once you have your API key, you are ready to work with the Subscriptions API. You can test your API key at the command line by doing the following cURL request, where your-API-key is the string you copied from your Accounts > My Settings page.

curl -u your-API-key: https://api.planet.com/subscriptions/v1/

Authentication

The Planet API uses Basic HTTP Authentication and requires that you have a Planet API key. Once you're signed up, you can find your API key in your account settings. Only one value is needed, so instead of using a username and password, you authenticate by setting username to your API key.

You could pass the API key as a variable in your code, but doing so makes it easy for others to see your key--not a good privacy and security practice. So the Python example, below, presumes you've stored your API key in a .env file at the root of your project.

You create a .env file and place your API string there:

PL_API_KEY = "[The API string from the My Settings section of your Planet Account page]"

Now, you are ready to pull your API key into your Python code without exposing it in the code. Assuming your Python file is in the same directory as your .env file, you import the dotenv package and call dotenv_values(".env").

Start by importing the packages used in these examples.

Info

If you get an error, you may need to install Python packages. For example, for dotenv, you might use the command line with pip install python-dotenv, depending on how you set up Python on your system.

# dotenv handles environment variables, such as your API key
from dotenv import dotenv_values

# requests handles sending and receiving requests,
# including authenticating with the server
import requests
from requests.auth import HTTPBasicAuth

# Use json to gather the info for your request
import json

# Get your Planet API Key from an environment variable
DOT_ENV_VALS = dotenv_values(".env")

# Your Planet API Key
API_KEY = DOT_ENV_VALS["PL_API_KEY"]

Next, you want to create a constant for the Planet Subscriptions API base URL. This is the location where the Planet service receives your requests and returns data to you. All requests are additional parameters you append to this base URL.

# Planet's Subscriptions API base URL for making restFUL requests
BASE_URL = "https://api.planet.com/subscriptions/v1"

Now your are ready to make a call to the Subscriptions API.

# Confirm that your API key is valid

# Set an authentication value
auth = HTTPBasicAuth(API_KEY, '')

# Do a GET request and the response
response = requests.get(BASE_URL, auth=auth)
# if you're using a Python notebook, you can just use `response` instead of print(response)
print(response)

You should see the response: <Response [200]>.

Permissions

Depending on your account type, you may have different permissions for different products. For Subscriptions API, you must have access to a particular area of access (AOA). Your area of interest (AOI) must be within your area of access. The person at your organization who has set up your account can provide you with the geometries of the AOAs you have access to. Alternatively, you can confirm this AOA with your Planet CSM.

The following example compares the area of interest with the area of access provisioned for you.

from shapely.geometry import shape

# Area of Interest (AOI) - Phoenix, AZ
AOI = {
    "type": "Polygon",
    "coordinates": [[[-112.448776,33.23932599999999],
                        [-112.448776,33.95612],
                        [-111.72052,33.95612],
                        [-111.72052,33.23932599999999],
                        [-112.448776,33.23932599999999]]]
      }

# Area of Interest (AOI) - US
AOA = {
    "type": "Polygon",
    "coordinates": [[[ -126.9504, 46.5531 ],
                        [ -54.1833, 46.7628 ],
                        [ -77.8798, 24.3246 ],
                        [ -94.6561, 23.9051 ],
                        [ -124.2242, 34.1806 ],
                        [ -126.9504, 46.5531 ]]]
      }

# Determine if the AOI is inside the AOA
def is_inside(AOI, AOA):
    smaller_shape = shape(AOI)
    larger_shape = shape(AOA)

    return smaller_shape.within(larger_shape)

result = is_inside(AOI, AOA)
print(result)  # Expect a True result

Most Planet API responses contain a _links object that contains a list of hyperlinks to itself and related data. You are encouraged to rely on these links rather than constructing the links yourself.

The most common _link is _self, which is a self reference. When an API response is paginated, _links will contain _next and _prev references.

Pagination

The Planet API paginates responses to limit the results, making them easier to work with. The first GET request will yield the first page along with _links representing the location of the _next page. Following the _next link will return another page of results. This process may be repeated until the _next link is no longer returned, which indicates the last page of results.

The following _links are provided in the response to facilitate pagination:

  • _self - The canonical location of the current page.
  • _first - The initial page.
  • _next - The page that logically follows the current page.
  • _prev - The page that logically precedes the current page.

Pagination example

Web services, such as the Planet API, usually limit the amount of data you can pull in one request. The limit for the Subscriptions API is 20. After you've authenticated to the server and gotten a <Response [200]>, as discussed in the Authentication section, you can get an indication if there are likely more than 20 results in any given response. For example, by getting the response object subscriptions field, you can get the length of results. If the number is over 20, you will want to paginate through all of your subscriptions, returning 20 at a time.

# 20 or more subscriptions?
subscriptions = response.json()['subscriptions']
print(len(subscriptions))

You may have more subscriptions, imagery, or Planetary Variables than you can download in one request.

The following example pages through existing subscriptions, gets the first list of subscriptions, and goes on to the next bundle of subscriptions if it exists:

BASE_URL = 'https://api.planet.com/subscriptions/v1/'

def get_subscriptions(url):
    try:
        resp = requests.get(url, auth=auth)
        resp.raise_for_status()  # Raise an exception for non-2xx status codes
        response_data = resp.json()
        subscriptions = response_data['subscriptions']
        subscription_count = len(subscriptions)
        print(f'Available subscriptions: {subscription_count}')
        if '_links' in response_data and 'next' in response_data['_links']:
            next_url = response_data['_links']['next']
            print(f'More subscriptions are available through pagination links: {next_url}')
            return subscriptions + get_subscriptions(next_url)
        else:
            return subscriptions
    except requests.exceptions.RequestException as e:
        print(f'Error occurred during API request: {e}')
    except (KeyError, json.JSONDecodeError) as e:
        print(f'Error occurred while processing JSON response: {e}')
    return []

all_subscriptions = get_subscriptions(BASE_URL)

# Process all subscriptions
for subscription in all_subscriptions:
    print(subscription)

Example Subscriptions API request

The following example gets Land Surface Temperature Planetary Variables for Phoenix, AZ, US.

So assuming you have imported the basic packages and authenticated, as shown in the Authentication section, and you have confirmed that your AOI is within your AOA, as discussed in the Permissions section, you are ready to set up your subscription and pass it to the Subscriptions API service.

A note about cloud delivery

For large datasets or for sharing or working online, you probably want to deliver your data to the cloud. Let's start out by defining some variables for cloud delivery.

Warning

Whatever credentials you use for your cloud storage, you want to make sure you are securing those credentials. Make sure the account you use for cloud delivery is secure and is granted the most restrictive permission. In this example, we use a Google Cloud Service Agent with a custom role that grants only three permissions, as in storage.objects.create, storage.objects.get, and storage.objects.delete permissions. Also, we take an additional step of base64-encoding the credentials, as described in Delivery to Google Cloud Storage.

# Your GCS project ID in which your bucket is located
GCS_PROJECT_ID = DOT_ENV_VALS["GCPROJECTID"]

# Your GCS bucket name that resides in the GCS project
GCS_BUCKET_NAME = DOT_ENV_VALS["GCSBUCKET"]

# Your GCS service agent's JSON credentials that you Base64-
# encoded and stored in the .env file
GCS_CREDS_B64 = DOT_ENV_VALS["GCSCREDS"]

Prepare your subscription

The body of the HTTP GET request holds all of the details on what you want from the service. It requires certain information in specific formats or values. So for the source type, you need to provide a value of either catalog for images, or for Planetary Variables, you need to provide the kind of Planetary Variable you want, for example biomass_proxy, land_surface_temperature, or soil_water_content.

You can name your subscription whatever helps you identify it.

The next field you want to supply information for is the source field. You specify that's the product you want in the source parameters id field. For more information on the source types and other values for Planetary Variables, see Planetary Variables types and IDs. If you wanted imagery, you might give a source type of catalog and then provide the values for "item_types": "PSScene" and "asset_typess": "ortho_analytic_4b". For more information on the source types and other values for imagery, see Items and Assets.

In this example subscription, you ask for a Land Surface Temperature Planetary Variable using the AMSR2 instrument, version 1.0, with a spatial resolution of 100 meters. You provide the start and end time of the data you want, and you provide the AOI you validated above.

# Create a new subscription JSON object
subscription_desc = {
   "name": "Phoenix, AZ 1 yr LST-AMSR2_V1.0_100",
   "source": {
       "type": "land_surface_temperature",
       "parameters": {
           "id": "LST-AMSR2_V1.0_100",
           "start_time": "2022-05-15T00:00:00Z",
           "end_time": "2023-05-15T00:00:00Z",
           "geometry": {
               "coordinates": [[[-112.448776,33.23932599999999],
                        [-112.448776,33.95612],
                        [-111.72052,33.95612],
                        [-111.72052,33.23932599999999],
                        [-112.448776,33.23932599999999]]],
               "type": "Polygon"
           }
       }
   },
   "delivery": {
       "type": "google_cloud_storage",
       "parameters": {
                        "bucket":GCS_BUCKET_NAME,
                        "credentials":GCS_CREDS_B64}
    }
}

POST a subscription

Now you create a Subscriptions API POST request and pass it the JSON object you just created to describe your subscription.

# set content type to json
headers = {'content-type': 'application/json'}

# create a subscription
def subscribe_pv(subscription_desc, auth, headers):
    response = requests.post(BASE_URL, data=json.dumps(subscription_desc), auth=auth, headers=headers)
    print(response)
    subscription_id = response.json()['id']
    print(subscription_id)
    subscription_url = BASE_URL + '/' + subscription_id
    return subscription_url

pv_subscription = subscribe_pv(subscription_desc, auth, headers)

You should get back a <Response [200]> and a subscription ID, that looks something like: 518b802e-919f-41c6-a068-b8d740b9e64a. The subscription is prepared, then running, and then it is completed. For all statuses, see Subscription status.

Using your data

Depending on the size of the subscription, it can take awhile to prepare the data and complete the subscription, but you can start working on building your analysis with the data shortly after you see the subscription is running.

There are several ways to retrieve your data. Let's go ahead and begin by placing some data in a data frame:

import pandas as pd

# Retrieve the resulting data in CSV format.
sub_id = requests.get(pv_subscription, auth=auth).json()['id']
resultsCSV = requests.get(f"{BASE_URL}/{sub_id}/results?format=csv", auth=auth)

# Read CSV Data
df = pd.read_csv(StringIO(resultsCSV.text), parse_dates=["item_datetime", "local_solar_time"])

# Filter by valid data only
df = df[df["lst.band-1.valid_percent"].notnull()]
df = df[df["lst.band-1.valid_percent"] > 0]
df = df[df["status"] != 'QUEUED']

df.head()

Subscriptions API Land Surface Temperature CSV Data Frame

You are now ready to begin your analysis.

 

Learning Resources

Get Started with Planet APIs. Checkout Planet notebooks on GitHub, such as the Subscriptions tutorials: subscriptions_api_tutorial. See also: Land Surface Temperature Technical Specification, Soil Water Content Technical Specification, and Crop Biomass Technical Specification. Find a collection of guides and tutorials on Planet University.


Rate this guide: