Planet Tasking API Order Creation


Introduction


This tutorial is an introduction on how to create tasking orders using Planet's Tasking API. It provides code samples on how to write simple Python code to do this.

The API reference documentation can be found at https://developers.planet.com/docs/tasking

Requirements


Software & Modules

This tutorial assumes familiarity with the Python programming language throughout. Familiarity with basic REST API concepts and usage is also assumed.

We'll be using a "Jupyter Notebook" (aka Python Notebook) to run through the examples. To learn more about and get started with using Jupyter, visit: Jupyter and IPython.

For the best experience, download this notebook and run it on your system, and make sure to install the modules listed below first. You can also copy the examples' code to a separate Python files an run them directly with Python on your system if you prefer.

Planet API Key

You should have an account on the Planet Platform to access the Tasking API. You may retrieve your API key from your account page, or from the "API Tab" in Planet Explorer.

Overview


The basic workflow

  1. Create a tasking order
  2. Monitor the tasking order
  3. Download images captured by the tasking order

Examples on how to edit or cancel existing tasking orders can be found in the notebook planet_tasking_api_order_edit_and_cancel.ipynb

API Endpoints

This tutorial will cover the following API endpoint:

Basic Setup


Before interacting with the Planet Tasking API using Python, we will set up our environment with some useful modules and helper functions.

  • We'll configure authentication to the Planet Tasking API
  • We'll use the requests Python module to make HTTP communication easier.
  • We'll use the json Python module to help us work with JSON responses from the API.
  • We'll use the pytz Python module to define the time frame for the order that we will be creating.
  • We'll create a function called p that will print Python dictionaries nicely.

Then we'll be ready to make our first call to the Planet Tasking API by hitting the base endpoint at https://api.planet.com/tasking/v2.

Let's start by configuring authentication:

Authentication

Authentication with the Planet Tasking API can be achieved using a valid Planet API key.

You can export your API Key as an environment variable on your system:

export PL_API_KEY="YOUR API KEY HERE"

Or add the variable to your path, etc.

To start our Python code, we'll setup an API Key variable from an environment variable to use with our requests:


In [ ]:
# Import the os module in order to access environment variables
import os

#If you are running this notebook outside of the docker environment that comes with the repo, you can uncomment the next line to provide your API key
#os.environ['PL_API_KEY']=input('Please provide your API Key')

# Setup the API Key from the `PL_API_KEY` environment variable
PLANET_API_KEY = os.getenv('PL_API_KEY')

Helper Modules and Functions


In [ ]:
# Import helper modules
import json
import requests
import pytz
from time import sleep
from datetime import datetime, timedelta

In [ ]:
# Helper function to printformatted JSON using the json module
def p(data):
    print(json.dumps(data, indent=2))

In [ ]:
# Setup Planet Tasking PLANET_API_HOST
TASKING_API_URL = "https://api.planet.com/tasking/v2"

# Setup the session
session = requests.Session()

# Authenticate
session.headers.update({
    'Authorization': f'api-key {PLANET_API_KEY}',
    'Content-Type': 'application/json'
})

1 | Creating a tasking order

Compose the tasking order

We want to create a tasking order that can return an image to us. To keep things simple we are going to create a Point order, which takes a single latitude/longitude coordinate pair. Since this is your order, you need to provide the details of what the tasing order is called and the coordinates for the tasking order.

To make things easier, we will default the start and end time to start tomorrow and end 7 days from now. Of course, feel free to change this to suit your needs, but if your do, take note that all times should be in UTC format. The start and end times are optional,but we include them in this tutorial to provide a better picture of what can be done.


In [ ]:
# Define the name and coordinates for the order
name=input("Give the order a name")
latitude=float(input("Provide the latitude"))
longitude=float(input("Provide the longitude"))

# Because the geometry is GeoJSON, the coordinates must be longitude,latitude
order = {
    'name': name,
    'geometry': {
        'type': 'Point',
        'coordinates': [
            longitude,
            latitude
        ]
    }
}

# Set a start and end time, giving the order a week to complete
tomorrow = datetime.now(pytz.utc) + timedelta(days=1)
one_week_later = tomorrow + timedelta(days=7)

datetime_parameters = {
    'start_time': tomorrow.isoformat(),
    'end_time': one_week_later.isoformat()
}

# Add use datetime parameters
order.update(datetime_parameters)

In [ ]:
#View the payload before posting
p(order)

In [ ]:
# The creation of an order is a POST request to the /orders endpoint
p(order)
res = session.request('POST', TASKING_API_URL + '/orders/', json=order)

if res.status_code == 403:
    print('Your PLANET_API_KEY is valid, but you are not authorized.')
elif res.status_code == 401:
    print('Your PLANET_API_KEY is incorrect')
elif res.status_code == 201:
    print('Your order was created successfully')
else:
    print(f'Received status code {res.status_code} from the API. Please contact support.')

# View the response
p(res.json())

Congratulations! You just created your first tasking order to the Planet Tasking API. Depending on the start and end time that you provided, a satellite will be attempting to take an image over your given coordinates in the near future.

2 | Monitor the tasking order

To monitor an existing tasking order, the tasking order id is required. Depending on the tasking order, it can take some time for the status of the tasking order to change, and so you may need to come back to this section once some time has elapsed before changes to the tasking order can be seen. It is recommended to run the next part of this notebook to extract the ID of the newly created order and save that for later use.


In [ ]:
# Get the response JSON and extract the ID of the order
response = res.json()
new_order_id = response["id"]
p(new_order_id)

In [ ]:
def monitor_order(order_id):
    # Make a GET request with the order_id concatenated to the end of the /orders url; e.g. https://api.planet.com/tasking/v2/orders/<ORDER_ID>
    res = session.request('GET', TASKING_API_URL + '/orders/' + order_id)

    if res.status_code == 403:
        print('Your PLANET_API_KEYPLANET_API_KEY is valid, but you are not authorized to view this order.')
    elif res.status_code == 401:
        print('Your PLANET_API_KEYPLANET_API_KEY is incorrect')
    elif res.status_code == 404:
        print(f'Your order ({order_id}) does not exist')
    elif res.status_code != 200:
        print(f'Received status code {res.status_code} from the API. Please contact support.')
    else:
        order = res.json()
        p(res.json())
        print(f'Your order is {order["status"]} with {order["capture_status_published_count"]} published captures '
                f'and {order["capture_assessment_success_count"]} successful captures')

In [ ]:
monitor_order(new_order_id)

3 | Download successfully captured images

Once the status of the tasking order has reached "FULFILLED" you can be certain that there are images associated with the tasking order that can be downloaded. To do this we need to use another api, the Planet Data API, to retreive the images. If you want to know more about the Planet Data API,there is Jupyter Notebok 'jupyter-notebooks/data-api-tutorials/planet_data_api_introduction.ipynb' which can provide a more complete tutorial.

As with monitoring the tasking order, the tasking order id is required.


In [ ]:
def download_successful_captures(order_id):

    # Make a GET request to the captures endpoint 
    res = session.request('GET', TASKING_API_URL + '/captures/?order_id' + order_id + '&fulfilling=true')

    if res.status_code == 403:
        print('Your API KEY is valid, but you are not authorized to view this order.')
    elif res.status_code == 401:
        print('Your API KEY is incorrect')
    elif res.status_code != 200:
        print(f'Received status code {res.status_code} from the API. Please contact support.')
    else:
        p(res.json())

        # Retrieve the captures from the response
        captures = res.json()['results']

        # For each capture, take the strip ID and create a payload that will be sent to the Data API
        strip_ids = [capture['strip_id'] for capture in captures]
        search_data = {
            "filter": {
                "config": strip_ids,
                "field_name": "strip_id",
                "type": "StringInFilter"
            },
            "item_types": ["SkySatCollect"]
        }

        # Make a POST requst to the Data API
        data_api_response = session.request('POST', 'https://api.planet.com/data/v1/quick-search',search_data)

        asset_urls = [feature['_links']['assets'] for feature in data_api_response.json()['features']]

        # Activate the ortho_visual asset(s)
        ortho_visual_urls = []
        for asset_url in asset_urls:
            assets = requests.get(asset_url, headers=headers).json()
            activation_url = assets['ortho_visual']['_links']['activate']
            requests.get(activation_url, headers=headers)
            ortho_visual_urls.append(assets['ortho_visual']['_links']['_self'])

        # Wait for activation and print
        for ortho_visual_url in ortho_visual_urls:
            ortho_visual = requests.get(ortho_visual_url, headers=headers).json()
            while 'location' not in ortho_visual:
                sleep(10)
                print('Waiting 10 seconds for asset to unlock...')
                ortho_visual = requests.get(ortho_visual_url, headers=headers).json()
            print(f'Open the following link in a browser or download it to a file:\n{ortho_visual["location"]}')

In [ ]:
download_successful_captures(new_order_id)