# The Spexi Portal

Your hub for accessing, integrating, and building with Spexi’s high-resolution drone imagery&#x20;

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-cover data-type="image">Cover image</th><th data-hidden></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><strong>Spexi World Viewer</strong></td><td>Explore our interactive platform to browse ultra-detailed panoramas and aerial imagery. No setup needed.</td><td><a href="/files/dikfLzL3E1eKe2S8Vrny">/files/dikfLzL3E1eKe2S8Vrny</a></td><td></td><td><a href="/pages/7aUFmnCMx9m4smGncsXL">/pages/7aUFmnCMx9m4smGncsXL</a></td></tr><tr><td><strong>Use Our APIs</strong></td><td>Generate keys, access data, and start building with our developer-friendly documentation.</td><td><a href="/files/5cih4hzX7ZcGOldcvh0e">/files/5cih4hzX7ZcGOldcvh0e</a></td><td></td><td><a href="/pages/jqRMl4pzh59ynn6WJSkf">/pages/jqRMl4pzh59ynn6WJSkf</a></td></tr><tr><td><strong>Integrations</strong></td><td>Connect Spexi imagery to your existing GIS tools and workflows</td><td><a href="/files/ypCX4NdCkBVK8OS9QBkt">/files/ypCX4NdCkBVK8OS9QBkt</a></td><td></td><td><a href="/pages/e7CylNsS9G1bJRlJjZwM">/pages/e7CylNsS9G1bJRlJjZwM</a></td></tr></tbody></table>


# Overview

The Spexi World Viewer is your central hub for exploring drone imagery, managing your team, and configuring your organization's integrations.

From the Viewer you can browse panoramic and orthomosaic imagery across your areas of interest, request new data captures, manage API keys and integrations, and control team access and permissions.


# Navigating the Map

### Data Products

Data products are the types of imagery Spexi captures and delivers through the Viewer. Each product type has its own visual representation on the map and its own viewing experience.

The Viewer currently supports the following data products:

<table><thead><tr><th width="100" align="center">Icon</th><th>Product</th><th>Description</th></tr></thead><tbody><tr><td align="center"><img src="/files/96EMRclH4ok6VfW54K4q" alt=""></td><td><strong>Panoramas</strong></td><td>360° imagery that lets you explore a location from every angle</td></tr><tr><td align="center"><img src="/files/2SCZtZUI0YvMfIsJEuN5" alt="" data-size="original"></td><td><strong>Orthomosaics</strong></td><td>Geometrically corrected aerial images stitched together to form an accurate, top-down map layer</td></tr></tbody></table>

### Navigating the map

When you first open the viewer, imagery coverage is shown as a layer of hexagonal tiles. As you zoom in, the tiles become progressively smaller and more detailed until your organization's data products appear on the map.

Each data product has its own visual representation:

* <mark style="color:blue;">**Panorama**</mark> locations appear as pink dots called <mark style="color:pink;">**places**</mark>. Click any place to open the panorama for that location.
* <mark style="color:violet;">**Orthomosaics**</mark> appear as an image layer directly on the map.

Both can be toggled on and off in the [Layers](/spexi-world-viewer/interactive-blocks) panel.

### Searching for a location

Type a place name or address into the search bar and suggestions will appear as you type.&#x20;

Select a result to zoom the map to that location. If Spexi imagery is available, the viewer will open the panorama directly.&#x20;

A pin on the mini-map marks the exact position for reference.


# Layer Management

The layers panel lets you control which products/datasets are visible on the map.

### Opening the layers panel

Click the **Layers** button (<img src="/files/peY0McVKIoix2tsEVqBK" alt="" data-size="line">) in the viewer toolbar to open the layers panel. The panel lists all products and data available to your organization.

### Showing and hiding layers

Toggle any layer on or off using the visibility control next to its name. Turning off a layer hides its coverage tiles and capture locations from the map without removing access to the data.

### Filtering

The Layers panel includes a filter section (<img src="/files/TfuIknplrqIFcMJX3XQX" alt="" data-size="line">) where you can set a month-to-month date range. This filter applies to both panoramas and orthomosaics:

* <mark style="color:blue;">**Panoramas**</mark>: only [<mark style="color:pink;">**places**</mark>](#user-content-fn-1)[^1] captured within the selected range are shown
* <mark style="color:violet;">**Orthomosaics**</mark>: the most recent orthomosaic capture within the selected range is shown

[^1]: Places are the pink dots on the map that mark panorama capture locations.


# Exploring Imagery

Once you've found a location on the map, dive in to explore the imagery available for it. The Spexi World Viewer supports two data products, each with its own viewing experience.

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-cover data-type="image">Cover image</th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><img src="/files/2SCZtZUI0YvMfIsJEuN5" alt="" data-size="line"> <strong>Orthomosaics</strong></td><td>View a scaled, top-down aerial map layer of the area</td><td data-object-fit="cover"><a href="/files/8JYaxOpm2FJacIpgeQfR">/files/8JYaxOpm2FJacIpgeQfR</a></td><td><a href="/pages/omvp7rESexI6FbnSlWTQ">/pages/omvp7rESexI6FbnSlWTQ</a></td></tr><tr><td><img src="/files/96EMRclH4ok6VfW54K4q" alt="" data-size="line"> <strong>Panoramas</strong></td><td>Explore a 360° aerial view of a location from every angle</td><td><a href="/files/fgFiCiyoZFLQph2p37Ts">/files/fgFiCiyoZFLQph2p37Ts</a></td><td><a href="/pages/EuBwOWnqaJysNZ6m7kOj">/pages/EuBwOWnqaJysNZ6m7kOj</a></td></tr></tbody></table>


# Panoramas

### Viewing panoramas

{% columns %}
{% column width="58.333333333333336%" %}
Hovering over a [<mark style="color:pink;">**place**</mark>](#user-content-fn-1)[^1] shows the available capture dates.&#x20;

If multiple panoramas exist for that location, all capture dates are listed. Click a specific date to open that version directly.
{% endcolumn %}

{% column width="41.666666666666664%" %}
![](/files/UxKh2JwoX5Q4DRSs0q20)
{% endcolumn %}
{% endcolumns %}

Click any <mark style="color:pink;">**place**</mark> to open the <mark style="color:blue;">**panorama**</mark> for that location. The panorama viewer will open full screen, replacing the map.

To return to the main map, click the back button (<img src="/files/DRZJeG1tKQ4Vbu0Bqsrp" alt="" data-size="line">)

{% hint style="info" icon="lightbulb" %}
To navigate to another panorama without leaving the viewer, use the mini-map. It displays nearby places and lets you click directly into any of them.

<p align="center"><img src="/files/4AEJ8a6ZVtfUHccV9llI" alt="" data-size="original"></p>
{% endhint %}

### Compare Capture Dates Over Time

Time series comparison lets you review the same location across different capture dates.

If multiple captures exist for a location, a time button (<img src="/files/RmonLk0UJGBJPYvMkta6" alt="" data-size="line">) will appear in the panorama viewer. Click it to see all available capture dates alongside a preview of each.

<figure><img src="/files/rhjhXFoXZEVPgiKYwQPJ" alt=""><figcaption></figcaption></figure>

Select any date to switch to that capture. The viewer preserves your current position and zoom level, so you can compare the same view across different points in time without any manual adjustment.

[^1]: Places are the pink dots on the map that mark panorama capture locations.


# Orthomosaics

Orthomosaics are geometrically corrected aerial images stitched together into an accurate, scaled map layer.&#x20;

### Viewing an orthomosaic

As you zoom into an area with orthomosaic coverage, the image layer appears directly on the map, replacing the hexagonal coverage tiles.

### Multiple capture dates

The orthomosaic layer always shows the most recent capture available for an area. To view an older capture instead, use the date range filter in the Layers panel to narrow the window; see [Layer Management](/spexi-world-viewer/interactive-blocks).


# Bookmarks

Bookmarks let you save panorama locations and return to them without navigating through the map again.

To save a location, click the bookmark icon (<img src="/files/5dM57Eiz5XQT4gzZmrel" alt="" data-size="line">) while a panorama is open. The location is saved to your account and persists across sessions.

To view your saved locations, open the Bookmarks section. Bookmarks are organized by **places** and **specific addresses** and each entry is labeled for easy scanning. Click any bookmark to jump directly into that panorama.

To remove a bookmark, either open the Bookmarks section and delete it from the list, or remove it directly from the panorama viewer using the bookmark icon.


# Requesting New Imagery

{% hint style="warning" %}
This feature is only accessible to users with the **Org Owner** or **Administrator** role. If you don't see **Request Capture** in the viewer toolbar, your account does not have the required permissions.
{% endhint %}

The ability to request updated imagery is typically linked to your service agreement with Spexi. Users with access to refresh options can request updates directly through the Spexi World Viewer.

{% hint style="info" %}
Certain areas may have drone flight restrictions due to regulatory, safety, or privacy concerns. Users are advised to check local drone regulations before submitting an imaging request.

If a request falls within a restricted area, Spexi can explore alternative solutions such as:

* Coordinating with authorized pilots.
* Applying for flight exemptions.
* Utilizing pre-existing imagery where available.
  {% endhint %}

### Defining your area

<table><thead><tr><th width="100">Icon</th><th>Tool</th><th>What it does</th></tr></thead><tbody><tr><td><img src="/files/mHaZAvXCiOK7uwXMFB3E" alt=""></td><td><strong>Draw Polygon</strong></td><td>Trace your area of interest on the map</td></tr><tr><td><img src="/files/Xs5PwFif8egO75SEG5iA" alt=""></td><td><strong>Edit Selection</strong></td><td>Drag vertices to reshape the polygon, click a midpoint to add a vertex, or drag the whole shape to move it</td></tr><tr><td><img src="/files/z7akjJxYaJLkUVPkyTXD" alt=""></td><td><strong>Add or Remove Hexes</strong></td><td>Click a hex to select it, click again to deselect it</td></tr></tbody></table>

Click **Request Capture** in the viewer toolbar, then use the **draw polygon** tool to trace your area of interest on the map. Once you close the polygon, Spexi resolves it into the hexagonal zones it intersects, and two additional tools become active:

* **Edit selection**: drag any vertex to reshape the polygon. Click the midpoint between two vertices to add a new vertex there. You can also drag the polygon as a whole to move it.
* **Add or remove hexes**: click a hex to select it, or click a selected hex again to deselect it, letting you fine-tune exactly which zones are included beyond what the polygon alone resolved to.

Alternatively, you can upload a boundary file instead of drawing one, which resolves into zones the same way.

{% hint style="warning" %}
Each order must cover a single contiguous area. Multipart features (multiple separate shapes in one file, or disconnected sets of hexes) aren't supported in a single order; split these into separate orders instead.
{% endhint %}

### Choosing products

Select which imagery product(s) you need for this request: <mark style="color:blue;">**panoramas**</mark>, <mark style="color:violet;">**orthomosaic**</mark>, or <mark style="color:orange;">**images**</mark>. You can request more than one product for the same area; each is tracked and delivered independently.

If you select **orthomosaic**, you'll also choose a subtype:

* **Standard**: maintains precise relative accuracy, with overall position accurate within 5 meters of true ground coordinates. Suitable for projects focused on measuring distances or areas within a site, tracking progress, or performing volume calculations, where absolute global alignment is less critical.
* **Aligned**: maintains precise relative accuracy and is aligned to an uploaded reference file. Final positional alignment accuracy depends on the positional accuracy of the reference file you provide.

### Optional details

You can optionally specify:

* A preferred capture window (start and end date)
* Notes for the Spexi team
* An external reference ID for your own records

{% hint style="warning" %}
Providing preferred capture dates help us prioritize scheduling, but cannot be guaranteed due to weather and operational conditions.
{% endhint %}

### Confirming and submitting

Before submitting, you'll see a confirmation screen summarizing your area, selected products, and any optional details you've entered. Review and submit.

Once submitted, you'll receive a **Spexi order ID**. Use this to look up your order status at any time (see [Order History](/spexi-world-viewer/order-history)).


# Order History

{% hint style="warning" %}
This feature is only accessible to users with the **Org Owner** or **Administrator** role. If you don't see **Request Capture** in the viewer header, your account does not have the required permissions.
{% endhint %}

Order History lets you track every imagery request you've submitted, and the status of each product within it.

To submit a new request, see [Requesting New Imagery](/spexi-world-viewer/requesting-new-imagery).

### Finding your orders

Open **Order History** (<img src="/files/Zy7YrsZ1v3rRVm8Tipcn" alt="" data-size="line">) from the viewer toolbar. Orders are listed newest first, showing the Spexi order ID, submission date, zone count and products requested.

{% hint style="info" %}
Order History is accessed from the floating toolbar on the left side of the **Request Captures** page, alongside the **Request Capture** tool. Opening Request Captures defaults to the request flow; click **Order History** in the toolbar to switch views.
{% endhint %}

### Filtering and search

* Search by Spexi order ID or your own external order ID
* Filter to **Current** (still in progress) or **Past** (completed) orders

### Checking product status

Each product in the order is tracked independently and shows its own status:

<table data-search="false"><thead><tr><th>Status</th><th>Definition</th></tr></thead><tbody><tr><td><mark style="background-color:$info;"><strong>Submitted</strong></mark></td><td>Order received, not yet reviewed</td></tr><tr><td><mark style="background-color:cyan;"><strong>In review</strong></mark></td><td>Spexi is reviewing the request</td></tr><tr><td><mark style="background-color:orange;"><strong>Feasibility check</strong></mark></td><td>Assessing whether the capture is achievable (site access, airspace, terrain, etc.)</td></tr><tr><td><mark style="background-color:orange;"><strong>Pending confirmation</strong></mark></td><td>Awaiting customer confirmation before mission planning begins</td></tr><tr><td><mark style="background-color:orange;"><strong>In planning</strong></mark></td><td>Mission planning in progress</td></tr><tr><td><mark style="background-color:blue;"><strong>Data collection</strong></mark></td><td>Pilots are actively capturing the area</td></tr><tr><td><mark style="background-color:violet;"><strong>Data processing</strong></mark></td><td>Captured data is being stitched/processed into the final product</td></tr><tr><td><mark style="background-color:violet;"><strong>Quality assurance</strong></mark></td><td>Product is in quality review before delivery</td></tr><tr><td><mark style="background-color:green;"><strong>Delivered</strong></mark></td><td>Product delivered</td></tr><tr><td><mark style="background-color:$info;"><strong>Cancelled</strong></mark></td><td>Order product was cancelled</td></tr><tr><td><mark style="background-color:$info;"><strong>Unfulfillable</strong></mark></td><td>Spexi determined the product can't be completed (e.g. failed feasibility)</td></tr></tbody></table>


# Account Settings

Account settings let you update your display name and change your password.

### Opening account settings

Click your user icon in the top-right corner of the viewer, then select **Account settings** from the dropdown.

### Updating your name

Enter your updated name in the name fields and save. The change will be reflected across the viewer immediately.

### Changing your password

If your organization uses username and password login, a password change option will appear in account settings. Enter your current password, then your new password, and confirm.

{% hint style="info" %}
If your organization uses single sign-on (SSO), the password field will not appear. Password changes must be made through your identity provider.
{% endhint %}


# Administration

{% hint style="warning" %}
This section is only accessible to users with the **Administrator** or **Org Owner** role. If you do not see the Settings section in the viewer, your account does not have the required permissions.
{% endhint %}

The Settings section of the viewer provides tools for managing your organization's API access, geospatial integrations and team members.

To access administration, click the **Settings** icon (<img src="/files/EU120Vfojcf75BAK3NM7" alt="" data-size="line">) in the viewer header.

Use the pages below to access/configure your organization's settings. If you are unsure which section you need, API keys and tile services are typically used by developers and GIS teams, while Members is for managing user access.

<table data-view="cards"><thead><tr><th></th><th data-hidden data-card-cover data-type="image">Cover image</th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><strong>API Keys</strong></td><td><a href="/files/LBvV2tIDVOybHdsnj6pT">/files/LBvV2tIDVOybHdsnj6pT</a></td><td><a href="/pages/M2tLucs6Zqgrtl76eiS5#creating-an-api-key">/pages/M2tLucs6Zqgrtl76eiS5#creating-an-api-key</a></td></tr><tr><td><strong>Tile Services</strong></td><td><a href="/files/9XZOgowJSUTLqAhdrBt9">/files/9XZOgowJSUTLqAhdrBt9</a></td><td><a href="/pages/0fPdVgbxCg7KUw7SKyru">/pages/0fPdVgbxCg7KUw7SKyru</a></td></tr><tr><td><strong>Members</strong></td><td data-object-fit="cover"><a href="/files/t0ojaBKQoAHcst3SPNJY">/files/t0ojaBKQoAHcst3SPNJY</a></td><td><a href="/pages/gesKImjBr4DfHdhaCwtN">/pages/gesKImjBr4DfHdhaCwtN</a></td></tr></tbody></table>


# Members

The members page lets you invite new users to your organization and manage the roles of existing members.

### Inviting a member

1. Go to **Settings > Members**.
2. Click **Invite member**.
3. Enter the user's name, email address and select their role.
4. Click **Send invite** - the user will receive an email with a link to join.

Invite links expire after 5 days. If an invite lapses, you can resend it from the Members tab.

{% hint style="warning" %}
Your organization may have a user seat limit based on your contract. If you are unsure of your limit or need additional seats, contact your Spexi account manager.
{% endhint %}

### Roles

| Role          | Access                                                    |
| ------------- | --------------------------------------------------------- |
| Member        | Access platform resources (no administrative permissions) |
| Administrator | Full access including settings                            |
| Org Owner     | Manage all users and organization settings                |

### Editing a member

Click the edit icon next to any member to change their name/role. Changes take effect immediately.

{% hint style="info" %}
You cannot edit a user's email address. To correct an email, remove the user and send a new invitation with the correct email address.
{% endhint %}

### Removing a member

To remove someone from your organization, click the remove icon next to their name. They will lose access immediately.

{% hint style="info" %}
You cannot remove the Org Owner through the members page. Ownership transfer must be handled by contacting Spexi support.
{% endhint %}


# Configure SSO/SAML for your organization

This guide provides step-by-step instructions for configuring Single Sign-On (SSO) using SAML in your organization. Follow these instructions to ensure a secure and seamless setup, regardless of your Identity Provider (IdP).

{% stepper %}
{% step %}

### Open the SSO/SAML configuration page

From Spexi World, navigate to **Settings** \[⚙️], then **SSO/SAML Configuration.**
{% endstep %}

{% step %}

### Configure SSO/SAML configuration detials

* Create a new SAML application in your IdP (e.g., Microsoft Entra, Google Workspace, Okta, OneLogin, Ping Identity, etc.).
* Enter the following details from your IdP:
  * Entity ID: Copy and paste the Entity ID from your IdP.
    * Example: `https://accounts.google.com/o/saml2?idpid=C02so64kf`
  * Entry Point URL: Enter the authentication request URL provided by your IdP.
    * Example: `https://accounts.google.com/o/saml2/idp?idpid=C02so64kf`
  * Certificate: Upload the X.509 certificate provided by your IdP (leave blank to retain the current one).
    * Certificates are used for secure authentication between your application and the IdP.
      {% endstep %}

{% step %}

### Configure attribute mappings

Map user attributes from your IdP to the corresponding fields in Spexi:

* First Name → firstName
* Last Name → lastName

Click Add Attribute Mapping for additional attributes.
{% endstep %}

{% step %}

### Add authorized domains

Enter the domains allowed to use SSO:

* `spexi.com`
* `spexigeo.com`

To remove a domain, click Remove next to it.
{% endstep %}

{% step %}

### Enable and test configuration

Test things out before enabling SSO for all users:

* Enable Test Mode.
* Use a test email: `sso://your-email@example.com`
* Attempt to login and verify SSO is working.

{% hint style="warning" %}
If Test Mode is disabled without a valid setup, users may lose access!
{% endhint %}
{% endstep %}

{% step %}

### Configure your identity provider (IdP)

* Configure the following settings in your IdP:
  * Assertion Consumer Service (ACS) URL
  * Entity ID
* Follow your IdP’s setup guide to configure a new SAML application using the provided ACS URL and Entity ID.

{% endstep %}

{% step %}

### Finalize your configuration

* Click Update SSO Config to save changes.
* Disable Test Mode once setup is confirmed to apply SSO to all users.
  {% endstep %}
  {% endstepper %}

#### Troubleshooting Guide

**Login Issues**

* Verify that ACS URL and Entity ID match the IdP settings.
* Check that the certificate is correctly uploaded.

**Attribute Mapping Errors**

* Ensure attribute names match exactly between IdP and Spexi.

**Domain Authorization Errors**

* Ensure all required domains are listed in the Domains section.

#### Need help? If you encounter issues, refer to your Identity Provider documentation or contact Spexi Support for assistance.


# Role-based access guide

This guide explains how to manage team roles within the platform to control access and permissions effectively.

## Understanding user roles

Roles determine the level of access and permissions users have within the platform.

| Role   | Permissions                                               |
| ------ | --------------------------------------------------------- |
| Owner  | Manage all users                                          |
| Admin  | Add/remove users, resend invites                          |
| Member | Access platform resources (no administrative permissions) |

Only `Owners` and `Admins` can access the Settings section.

### Managing users

#### Inviting new users

1. Go to Settings > Members.
2. Click Invite Member.
3. Enter the user’s email address and assign their role (Owner, Admin, or Member).
4. Click Send Invite – the user will receive an invite email.

#### Viewing and editing users

* In the Members tab, view each member’s invite date, role, and status (Active, Pending).
* To change a user’s role, select their name, modify their role, and save the changes.

{% hint style="info" %}
To **update** a user’s email address, you must remove them and send a new invitation with the correct email.=
{% endhint %}

### Frequently Asked Questions

#### Who can access the Settings section?

Only `Owners` and `Admins` can access the Settings section to manage users. Users can only manage other users who have lower-access levels.

#### What happens if an invitation is not accepted?

* Invitation links expire after 10 days.
* If expired, you can resend the invite from the Users tab.

#### Can I limit the number of users my team invites?

There is currently no limit on the number of users an Owner or Admin can invite.

#### Can I edit a user’s email address?

No, you must delete the user and send a new invitation with the correct email.


# FAQs

<details>

<summary>How does Spexi approach privacy compliance?</summary>

**Privacy Safeguards:**\
Spexi’s imagery is captured from an altitude that prevents the identification of individual faces and personal details. This approach ensures that no personally identifiable information (PII) is captured.

\
**Regulatory Adherence:**\
Spexi complies with all applicable privacy laws and follows industry best practices. For region-specific privacy concerns, users are encouraged to review local guidelines or consult with legal experts.

</details>

<details>

<summary>Can I share Spexi imagery publicly?</summary>

Public sharing of imagery depends on the terms of your contract with Spexi and the specific licensing agreements.

**Sharing Guidelines:**

* Some contracts may restrict public sharing, while others may allow distribution for presentations, reports, or social media.
* Users are advised to review their agreement terms or consult with their Spexi representative to confirm their rights regarding public sharing

</details>

<details>

<summary>Which drone models are used to capture imagery?</summary>

Spexi primarily uses DJI Mini drones.

* **Reasons for Selection:**
  * **Widespread Availability:** DJI Mini drones are widely available.
  * **Regulatory Compliance:** These drones comply with current regulations.
  * **Operational Efficiency:** Their accessibility allows a large network of pilots to capture high-resolution imagery.
* **Limitations:**
  * While well-suited for most scenarios, DJI Mini drones have limitations in specialized applications such as thermal imaging.

</details>

<details>

<summary>What quality control procedures exist to ensure high quality data?</summary>

* **Optimal Lighting:** Images are captured under lighting conditions that minimize shadows and distortions.
* **Flight Regulation Compliance:** Flight times are carefully restricted to meet drone regulations, ensuring clear and high-resolution images.
* **Demand-Based Updates:** Areas of high demand are prioritized for frequent updates rather than indiscriminate coverage.
* **Upcoming Features:** A side-by-side comparison feature is in development to allow users to compare images across different timeframes easily.

</details>

<details>

<summary>How accurate is your imagery?</summary>

* **Ground Sample Distance (GSD):**
  * Spexi imagery offers a GSD of approximately 2.8 centimeters per meter at nadir (directly beneath the drone).
  * This metric implies that for every 1 meter on the ground, the potential positioning error is 2.8 centimeters.
* **Overall Accuracy:**
  * Typical imagery accuracy falls within a 5–10 centimeter range.
  * These values make Spexi’s imagery comparable to high-resolution satellite imagery for most mapping and analysis applications.

</details>

<details>

<summary>Do you support ortho imagery?</summary>

Currently, Spexi primarily supports oblique imagery due to its operational efficiency and cost-effectiveness.

* **Ortho Imagery Considerations:**
  * Ortho images require additional flight time and processing.
  * These factors increase overall operational costs.
  * Spexi is evaluating the possibility of introducing ortho imagery support in the future, and updates will be provided as developments occur.

</details>


# Introduction

Welcome to the Spexi API documentation. Spexi is a drone imagery platform providing high-resolution aerial coverage across North America. This guide provides everything you need to integrate with our platform and access drone imagery programmatically.

### Prerequisites

Before making your first API call you will need:

* A valid Spexi account
* An [API key](/api-reference/authentication) generated from your Spexi account

### How the API Works

The Spexi API provides programmatic access to drone imagery and geospatial data. The API is organized into focused modules, each covering a distinct part of the platform:

* [**Coverage API**](/api-reference/coverage-api) - check where drone imagery is available, by map tiles, coverage queries, or zone lookups
* [**Image API**](/api-reference/image-api) **-** search, filter, and download drone imagery by location and camera parameters
* [**Tasking API**](/api-reference/tasking-api) - request new drone captures for an area of interest and track orders through delivery


# Quick Start

This guide demonstrates the basic Spexi Image API workflow, from authentication through image retrieval. Complete the following steps to make your first successful API request.

### Prerequisites

An active API key is required for all requests. If you have not yet generated an API key, refer to the [Authentication](/api-reference/authentication) section for detailed instructions.

### Basic Workflow

The standard API workflow consists of two primary steps: discovering available collections and querying specific imagery within those collections.

#### Step 1: Discover Available Collections

Begin by retrieving a list of imagery collections accessible through your account:

```bash
curl -X GET "https://api-world.spexi.com/api/ogc/v1/collections" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

The response contains collection metadata including:

* **id** - unique identifier required for subsequent queries
* **name** - descriptive collection title
* **extent** - geographic boundaries and temporal coverage

#### Step 2: Query Collection Items

Select a collection ID from the previous response and retrieve imagery from that collection:

```bash
curl -X GET "https://api-world.spexi.com/api/ogc/v1/collections/COLLECTION_ID/items?p=-123.103865,49.27332,25" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

Replace `COLLECTION_ID` with the appropriate identifier from your collections response.

### Filtering Results

Basic queries may return extensive result sets. Apply query parameters to refine results based on your requirements.

#### Spatial Filtering

Filter images by geographic location using point queries:

```bash
curl -X GET "https://api-world.spexi.com/api/ogc/v1/collections/COLLECTION_ID/items?p=-123.103865,49.27332,25" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

This query returns images containing the specified coordinate (longitude -122.4194, latitude 37.7749) with a 100-meter buffer radius.

#### Intelligent Filtering

Apply the focused parameter to retrieve only the most relevant imagery for your area of interest:

```bash
curl -X GET "https://api-world.spexi.com/api/ogc/v1/collections/COLLECTION_ID/items?p=-123.103865,49.27332,25&focused=focused" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

The focused parameter applies advanced filtering algorithms to select optimal imagery from potentially large datasets.

### Response Format

The API returns data in GeoJSON format. Each image appears as a feature containing:

* **geometry** - geographic footprint representing the ground area captured
* **properties** - comprehensive metadata including flight parameters and capture information
* **links** - array of related resources, including direct download URLs

Locate the download link by identifying the object with `"title": "Raw Image"` and `"type": "image/jpeg"`.

### Pagination

Large result sets are delivered using cursor-based pagination. When additional results are available, the response includes a next link:

json

```json
{
  "links": [
    {
      "rel": "next",
      "href": "https://api-world.spexi.com/api/ogc/v1/collections/COLLECTION_ID/items?cursor=pagination_token"
    }
  ]
}
```

Use the provided href URL to retrieve subsequent result pages.

### Next Steps

After completing these basic operations, explore additional functionality:

* [**Core Concepts**](/api-reference/core-concepts) - detailed explanation of collections and filtering mechanisms
* [**Use Cases and Examples**](/api-reference/code-examples) - practical implementation scenarios
* [**Standard Images API**](/api-reference/standard-images-api) - comprehensive parameter reference and advanced query options


# Authentication

The Spexi API uses API key authentication. All requests require a valid API key included in the request header to ensure proper access control and usage tracking.

### Creating an API Key

API keys are generated through the Spexi World settings page. Each key provides access to imagery collections based on your account permissions.

{% stepper %}
{% step %}

#### Access Account Settings

* Log in to [Spexi World](https://world.spexi.com)
* Navigate to the **Settings** page using the cog icon in the bottom-left sidebar navigation
  {% endstep %}

{% step %}

#### Generate an API Key

* Locate the [**API Keys**](https://world.spexi.com/settings/keys) section within Settings
* Click **Create New Key**
* Provide a descriptive name for your API key to distinguish it from other keys in your account
* Click **Create Key**
  {% endstep %}

{% step %}

#### Secure your API Key

After generation, your API key will be displayed once. Copy it immediately and store it securely - the complete key will not be displayed again.
{% endstep %}
{% endstepper %}

### Using Your API Key

Include your API key in the `x-api-key` header of every request:

```
x-api-key: YOUR_API_KEY
```

#### Example Request

```bash
curl -H "x-api-key: YOUR_API_KEY" \
  "https://world.spexi.com/developer-api/api/v1/image?p=-123.1216,49.2827,100"
```

Replace `YOUR_API_KEY` with your actual API key value.

### Security Best Practices

Proper API key management is essential for maintaining account security and preventing unauthorized access.

#### Key Storage

* Store API keys in environment variables or secure credential management systems
* Never commit API keys to version control repositories
* Avoid embedding keys directly in client-side code or public applications

#### Key Management

* Use descriptive names to identify the purpose of each key
* Rotate keys periodically to enhance security

#### Key Compromise

If an API key is compromised or accidentally exposed:

1. Return to the API Keys section in Settings
2. Delete the compromised key immediately
3. Generate a new replacement key
4. Update all applications using the previous key

#### Key Limitations

API keys inherit the access permissions of your Spexi World account. Available imagery collections and usage limits are determined by your account tier and geographic access rights.

### Troubleshooting

#### Common Authentication Errors

**401 Unauthorized**: Indicates an invalid or missing API key

* Verify the `x-api-key` header is included in your request
* Confirm the key has not been deleted or deactivated
* Check for extra spaces or characters in the key value

**403 Forbidden**: API key is valid but lacks permission for the requested resource

* Verify your account has access to the specified collection
* Contact support if you believe you should have access to the requested data


# Core Concepts

This section explains the fundamental concepts required to effectively use Spexi APIs. Understanding these concepts will enable you to structure queries efficiently and interpret API responses.

## Understanding Collections

Collections represent organized datasets of related imagery within the Spexi platform. The OGC Features standard defines collections as containers that group similar geospatial features based on shared characteristics or logical relationships.

#### What Collections Represent

In the Spexi context, collections typically organize imagery by:

* **Geographic region** - imagery from specific areas or administrative boundaries
* **Product type** - different categories of imagery products as they become available

#### Collection Metadata

Each collection includes descriptive metadata that helps determine its relevance for your use case:

* **id** - unique identifier used in all API requests for that collection
* **title** - human-readable name describing the collection contents
* **description** - detailed information about the imagery
* **extent** - geographic boundaries of the imagery within the collection
* **links** - related resources including the items endpoint for querying collection imagery

#### Working with Collections

The collections endpoint serves as the entry point for all API interactions:

```bash
curl -X GET "https://api-world.spexi.com/api/ogc/v1/collections" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

Review collection metadata to identify datasets relevant to your requirements before querying specific imagery. Collection IDs remain stable over time, enabling reliable programmatic access to specific datasets.

## Standard Images

Standard images represent the core imagery product available through the Spexi APIs. These images are captured directly by drones and serve as the foundation for derived products such as panoramas and orthomosaics.

#### Image Characteristics

Standard images contain the following key attributes:

**Spatial Properties:**

* **Latitude and longitude** - precise GPS coordinates of the camera position at capture time
* **Altitude** - height above ground level during image capture
* **Footprint geometry** - geographic area visible in each image

**Camera Parameters:**

* **Pitch** - camera angle relative to horizontal plane (typically -90° to -30°)
* **Heading** - compass direction the camera was facing (0° to 360°, where 0° represents north)

**Metadata:**

* **Capture timestamp** - precise date and time of image acquisition
* **EXIF data** - comprehensive technical metadata embedded in image files
* **File format** - images are delivered as high-resolution JPEG files

#### Image Coverage and Overlap

Drone surveys typically capture images with significant overlap to ensure complete area coverage. This approach results in multiple images containing the same geographic features, often from different angles and perspectives. While comprehensive, this overlap can complicate workflows that require specific imagery for particular locations.

### The Focused Parameter

The focused parameter addresses the challenge of selecting relevant imagery from datasets with extensive overlap. This feature applies intelligent filtering algorithms to identify the most appropriate images for your specified area of interest.

**Filtering Modes**

The focused parameter supports three distinct modes:

**none** (default)

* Returns all images that meet the specified query parameters
* No additional filtering applied
* Useful for comprehensive analysis requiring all available perspectives

**focused**

* Applies advanced filtering to select images where the specified point or area is prominently featured
* Reduces result sets to the most relevant imagery for the query location
* **Recommended for most practical applications**

**5-view**

* Returns up to five representative images from different perspectives (cardinal directions plus nadir)
* Provides comprehensive coverage while maintaining manageable result sets
* Ideal for applications requiring multiple viewpoints of the same location

**Usage Examples**

Basic query without filtering:

```bash
curl -X GET "https://api-world.spexi.com/api/ogc/v1/collections/COLLECTION_ID/items?p=-123.103865,49.27332,25"
```

Apply focused filtering:

```bash
curl -X GET "https://api-world.spexi.com/api/ogc/v1/collections/COLLECTION_ID/items?p=-123.103865,49.27332,25&focused=focused"
```

Request representative views:

```bash
curl -X GET "https://api-world.spexi.com/api/ogc/v1/collections/COLLECTION_ID/items?p=-123.103865,49.27332,25&focused=5-view"
```

**When to Use Focused Filtering**

The focused parameter is particularly valuable when:

* Working with point or small bounding box queries where you need imagery of a specific location
* Developing applications that display imagery to end users
* Processing large datasets where computational efficiency is important
* Creating visualizations or analyses that require the best available imagery for each location

Note that focused filtering is only effective when combined with spatial query parameters such as point or bounding box queries. The filtering algorithms require geographic context to determine image relevance.


# Standard Images API

## Collections

The `collections` endpoint returns all imagery datasets accessible through your account. This endpoint serves as the discovery mechanism for available imagery and must be called before querying specific images. Usually, you'll have access to only one or two collections that cover the full extent of the geographic area available to your account.

### Common Use Cases

* **Application initialization** - retrieve and cache available collections
* **Geographic discovery** - identify which collections cover your areas of interest
* **Permission validation** - confirm access to specific datasets before building user interfaces

### Response Highlights

Each collection in the response includes:

* **`id`** - unique identifier required for all subsequent image queries
* **`extent`** - geographic boundaries for the collection
* **`title` and `description`** - human-readable metadata for user interfaces
* **`links`** - includes the items endpoint URL for querying images within this collection

### Implementation Notes

💡 **Cache collections data** - this endpoint returns relatively static information that changes infrequently. Cache the response to avoid unnecessary API calls. Collection IDs are stable over time, so once you have it saved, you may not need to revisit this endpoint.

💡 **Check extent data** - use the spatial extent information to verify the collection's region aligns with your project location.

## Retrieve a list of all collections

> Access and browse available feature collections accessible to the authenticated user.

```json
{"openapi":"3.1.0","info":{"title":"Spexi API","version":"1.0"},"servers":[{"url":"https://world.spexi.com","description":"API URL"}],"security":[{"bearer-token":[]}],"components":{"securitySchemes":{"bearer-token":{"scheme":"bearer","bearerFormat":"JWT","type":"http","name":"Authorization","description":"Enter your Bearer token","in":"header"}},"schemas":{"CollectionsListResponse":{"type":"object","properties":{"links":{"type":"array","items":{"type":"object","properties":{"href":{"type":"string","description":"Supplies the URI to a remote resource (or resource fragment)."},"rel":{"description":"The type or semantics of the relation.","type":"string","enum":["alternate","https://www.opengis.net/def/rel/ogc/1.0/data-meta","https://www.opengis.net/def/rel/ogc/1.0/conformance","https://www.opengis.net/def/rel/ogc/1.0/tiling-schemes","https://www.opengis.net/def/rel/ogc/1.0/tiling-scheme","https://www.opengis.net/def/rel/ogc/1.0/tilesets-vector","describedby","license","self","item","items","next","service-desc","service-doc","service-meta","https://www.opengis.net/def/ogc/image","https://www.spexi.com/def/image/oriented","https://www.spexi.com/def/image/panorama"]},"type":{"type":"string","enum":["application/json","application/geo+json","text/html","application/openapi+json;version=3.0","application/vnd.mapbox-vector-tile","application/vnd.mapbox.tile+json"],"description":"A hint indicating what the media type of the result of dereferencing the link should be."},"templated":{"type":"boolean","description":"This flag set to true if the link is a URL template."},"varBase":{"type":"string","description":"A base path to retrieve semantic information about the variables used in URL template."},"hreflang":{"type":"string","description":"A hint indicating what the language of the result of dereferencing the link should be."},"title":{"type":"string","description":"Used to label the destination of a link such that it can be used as a human-readable identifier."},"length":{"type":"number"}},"required":["href","rel"]}},"collections":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"title":{"type":"string"},"description":{"type":"string"},"links":{"type":"array","items":{"type":"object","properties":{"href":{"type":"string","description":"Supplies the URI to a remote resource (or resource fragment)."},"rel":{"description":"The type or semantics of the relation.","type":"string","enum":["alternate","https://www.opengis.net/def/rel/ogc/1.0/data-meta","https://www.opengis.net/def/rel/ogc/1.0/conformance","https://www.opengis.net/def/rel/ogc/1.0/tiling-schemes","https://www.opengis.net/def/rel/ogc/1.0/tiling-scheme","https://www.opengis.net/def/rel/ogc/1.0/tilesets-vector","describedby","license","self","item","items","next","service-desc","service-doc","service-meta","https://www.opengis.net/def/ogc/image","https://www.spexi.com/def/image/oriented","https://www.spexi.com/def/image/panorama"]},"type":{"type":"string","enum":["application/json","application/geo+json","text/html","application/openapi+json;version=3.0","application/vnd.mapbox-vector-tile","application/vnd.mapbox.tile+json"],"description":"A hint indicating what the media type of the result of dereferencing the link should be."},"templated":{"type":"boolean","description":"This flag set to true if the link is a URL template."},"varBase":{"type":"string","description":"A base path to retrieve semantic information about the variables used in URL template."},"hreflang":{"type":"string","description":"A hint indicating what the language of the result of dereferencing the link should be."},"title":{"type":"string","description":"Used to label the destination of a link such that it can be used as a human-readable identifier."},"length":{"type":"number"}},"required":["href","rel"]}},"extent":{"type":"object","properties":{"spatial":{"type":"object","properties":{"bbox":{"type":"array","items":{},"minItems":1},"crs":{"type":"string","enum":["https://www.opengis.net/def/crs/OGC/1.3/CRS84"]}},"required":["bbox","crs"]},"temporal":{"type":"object","properties":{"interval":{"type":"array","items":{"type":"array","items":{"type":"string","format":"date-time","nullable":true},"minItems":2,"maxItems":2},"minItems":1},"trs":{"type":"string","enum":["https://www.opengis.net/def/uom/ISO-8601/0/Gregorian"]}},"required":["interval","trs"]}},"required":["spatial","temporal"]},"crs":{"type":"array","items":{"type":"string"}},"storageCrs":{"type":"string","format":"uri"}},"required":["id","name","title","description","links","extent","crs","storageCrs"]}}},"required":["links","collections"]},"ErrorDto":{"type":"object","properties":{"type":{"type":"string","description":"A URI reference that identifies the problem type"},"title":{"type":"string","description":"A short, human-readable summary of the problem type"},"status":{"type":"integer","description":"The HTTP status code for this occurrence of the problem"},"detail":{"type":"string","description":"A human-readable explanation specific to this occurrence of the problem"},"instance":{"type":"string","description":"A URI reference that identifies the specific occurrence of the problem"}},"required":["type"],"title":"Exception Schema","description":"JSON schema for exceptions based on RFC 7807"}}},"paths":{"/api/ogc/v1/collections":{"get":{"description":"Access and browse available feature collections accessible to the authenticated user.","operationId":"CollectionsController_getCollections","parameters":[{"name":"f","required":false,"in":"path","description":"Response format type","schema":{"enum":["application/json","text/html"],"type":"string"}},{"name":"Accept","in":"header","description":"Response format (unless specified by the `f` parameter)","required":false,"schema":{"type":"string","enum":["application/json","text/html","*/*"]}},{"name":"Authorization","in":"header","description":"Bearer token for authenticated requests","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionsListResponse"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDto"}}}},"401":{"description":"Unauthorized"},"406":{"description":"Not Acceptable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDto"}}}},"500":{"description":"Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDto"}}}}},"summary":"Retrieve a list of all collections","tags":["OGC API"]}}}}
```

## Items

The items endpoint retrieves imagery from a specific collection. This endpoint supports extensive filtering capabilities to find precisely the images you need based on location, camera parameters, and capture attributes.

### Common Use Cases

* **Location-based queries** - find all images containing a specific point or area
* **Camera angle filtering** - retrieve images captured at specific pitch or heading angles
* **Temporal searches** - get images captured within date ranges
* **Quality filtering** - use focused parameter to get the best images for your area of interest
* **Systematic processing** - iterate through large datasets with pagination

### Key Parameters

While this endpoint supports many parameters, these handle the majority of use cases:

**Spatial Filtering:**

* **`p`** - find images containing a specific point (with optional buffer radius)
* **`bbox`** - retrieve images within a rectangular geographic area

**Smart Filtering:**

* **`focused`** - apply intelligent filtering to get the most relevant images
  * Use `focused=focused` for most practical applications
  * Use `focused=5-view` when you need multiple perspectives of the same location

**Camera Parameters:**

* **`pitch`** - filter by camera angle (-90° for straight down, -60° for oblique views)
* **`heading`** - filter by compass direction the camera was facing
* **`altitude`** - filter by flight height above ground level
* **`captured_at`** - filter by image capture date

### Response Highlights

Each image feature includes:

* **`geometry`** - precise geographic footprint showing the area captured in the image
* **`properties`** - comprehensive metadata including flight parameters and capture information
* **`links`** - download URLs for the actual image file (look for `"title": "Raw Image"`)

### Implementation Notes

💡 **Always use focused filtering** - unless you specifically need all overlapping images, add `&focused=focused` to all queries. This dramatically improves response relevance and reduces processing overhead.

💡 **Extract download URLs from links** - to download the actual image file, iterate through the `links` array in each feature and find the object with `"title": "Raw Image"` and `"type": "image/jpeg"`. The `href` field contains the direct download URL.

💡 **Handle pagination** - large queries return paginated results. Check for `"rel": "next"` links in the response and follow them to retrieve complete datasets.

💡 **Combine parameters wisely** - all filter parameters use AND logic. For example, `?pitch=-90&heading=0&focused=focused` returns only nadir images facing north that prominently feature your query area.

## Retrieve image features from a collection

> Discover and download high-quality drone imagery based on geographic location and camera parameters. This endpoint allows you to find precise aerial views of specific points or regions of interest, with filters for camera orientation, angle, and coverage area.

```json
{"openapi":"3.1.0","info":{"title":"Spexi API","version":"1.0"},"servers":[{"url":"https://world.spexi.com","description":"API URL"}],"security":[{"bearer-token":[]}],"components":{"securitySchemes":{"bearer-token":{"scheme":"bearer","bearerFormat":"JWT","type":"http","name":"Authorization","description":"Enter your Bearer token","in":"header"}},"schemas":{"OrientedImageCollectionItemsResponse":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"type":{"type":"string","enum":["FeatureCollection"]},"features":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["Feature"]},"geometry":{"type":"object","properties":{"type":{"type":"string","enum":["Polygon"]},"coordinates":{"type":"array","items":{"type":"array","items":{}}}},"required":["type","coordinates"],"description":"Geographic area captured within the image."},"properties":{"type":"object","properties":{"id":{"type":"string","description":"Identifier of the image."},"pitch":{"type":"number","description":"Camera angle below horizontal in degrees. Range: [-135, 45], where -90 is directly downward (nadir), -60 is oblique, and -30 is more horizontal."},"roll":{"type":"number","description":"Camera roll angle in degrees."},"altitude":{"type":"number","description":"Altitude of the camera above ground level in meters."},"heading":{"type":"number","description":"Camera heading in degrees. Range: [0, 360), where 0 is North, 90 is East, etc."},"cameraPosition":{"type":"object","properties":{"type":{"type":"string","enum":["Point"]},"coordinates":{}},"required":["type","coordinates"],"description":"Point location of the camera at time of capture."},"distance":{"type":"number","description":"Distance from the query point to the camera position in meters."},"capturedAt":{"type":"string","format":"date-time","description":"Timestamp when the image was captured."},"captureType":{"type":"string","description":"Type of image capture: 'panorama', 'oblique', or 'orthomosaic'."}},"required":["id","pitch","roll","altitude","heading","cameraPosition","capturedAt","captureType"]},"links":{"type":"array","items":{"type":"object","properties":{"href":{"type":"string","description":"Supplies the URI to a remote resource (or resource fragment)."},"rel":{"description":"The type or semantics of the relation.","type":"string","enum":["alternate","https://www.opengis.net/def/rel/ogc/1.0/data-meta","https://www.opengis.net/def/rel/ogc/1.0/conformance","https://www.opengis.net/def/rel/ogc/1.0/tiling-schemes","https://www.opengis.net/def/rel/ogc/1.0/tiling-scheme","https://www.opengis.net/def/rel/ogc/1.0/tilesets-vector","describedby","license","self","item","items","next","service-desc","service-doc","service-meta","https://www.opengis.net/def/ogc/image","https://www.spexi.com/def/image/oriented","https://www.spexi.com/def/image/panorama"]},"type":{"type":"string","enum":["application/json","application/geo+json","text/html","application/openapi+json;version=3.0","application/vnd.mapbox-vector-tile","application/vnd.mapbox.tile+json"],"description":"A hint indicating what the media type of the result of dereferencing the link should be."},"templated":{"type":"boolean","description":"This flag set to true if the link is a URL template."},"varBase":{"type":"string","description":"A base path to retrieve semantic information about the variables used in URL template."},"hreflang":{"type":"string","description":"A hint indicating what the language of the result of dereferencing the link should be."},"title":{"type":"string","description":"Used to label the destination of a link such that it can be used as a human-readable identifier."},"length":{"type":"number"}},"required":["href","rel"]}}},"required":["id","type","geometry","properties","links"]}},"numberReturned":{"type":"number","description":"The number of features in the response."},"links":{"type":"array","items":{"type":"object","properties":{"href":{"type":"string","description":"Supplies the URI to a remote resource (or resource fragment)."},"rel":{"description":"The type or semantics of the relation.","type":"string","enum":["alternate","https://www.opengis.net/def/rel/ogc/1.0/data-meta","https://www.opengis.net/def/rel/ogc/1.0/conformance","https://www.opengis.net/def/rel/ogc/1.0/tiling-schemes","https://www.opengis.net/def/rel/ogc/1.0/tiling-scheme","https://www.opengis.net/def/rel/ogc/1.0/tilesets-vector","describedby","license","self","item","items","next","service-desc","service-doc","service-meta","https://www.opengis.net/def/ogc/image","https://www.spexi.com/def/image/oriented","https://www.spexi.com/def/image/panorama"]},"type":{"type":"string","enum":["application/json","application/geo+json","text/html","application/openapi+json;version=3.0","application/vnd.mapbox-vector-tile","application/vnd.mapbox.tile+json"],"description":"A hint indicating what the media type of the result of dereferencing the link should be."},"templated":{"type":"boolean","description":"This flag set to true if the link is a URL template."},"varBase":{"type":"string","description":"A base path to retrieve semantic information about the variables used in URL template."},"hreflang":{"type":"string","description":"A hint indicating what the language of the result of dereferencing the link should be."},"title":{"type":"string","description":"Used to label the destination of a link such that it can be used as a human-readable identifier."},"length":{"type":"number"}},"required":["href","rel"]}}},"required":["id","title","type","features","numberReturned","links"]},"ErrorDto":{"type":"object","properties":{"type":{"type":"string","description":"A URI reference that identifies the problem type"},"title":{"type":"string","description":"A short, human-readable summary of the problem type"},"status":{"type":"integer","description":"The HTTP status code for this occurrence of the problem"},"detail":{"type":"string","description":"A human-readable explanation specific to this occurrence of the problem"},"instance":{"type":"string","description":"A URI reference that identifies the specific occurrence of the problem"}},"required":["type"],"title":"Exception Schema","description":"JSON schema for exceptions based on RFC 7807"}}},"paths":{"/api/ogc/v1/collections/{collectionId}+standard-images/items":{"get":{"description":"Discover and download high-quality drone imagery based on geographic location and camera parameters. This endpoint allows you to find precise aerial views of specific points or regions of interest, with filters for camera orientation, angle, and coverage area.","operationId":"OrientedImageCollectionController_getFeatures","parameters":[{"name":"collectionId","required":true,"in":"path","description":"Collection identifier, discoverable from the `/api/ogc/v1/collections` endpoint","schema":{"pattern":"^[a-z0-9]+$","type":"string"}},{"name":"bbox","required":false,"in":"query","description":"An area of interest to query in the format `minLon,minLat,maxLon,maxLat`. Returns images that view any portion of the specified area.","schema":{"type":"string"}},{"name":"p","required":false,"in":"query","description":"A point of interest to query with an optional radius search parameter in the format `longitude,latitude[,radiusMeters]`. Returns images that view any portion of the specified point or radius area.","schema":{"type":"string"}},{"name":"heading","required":false,"in":"query","description":"Camera heading in degrees, expressed as an inclusive range [hmin, hmax], or as a single value.\nRange: [0, 360), where 0 is north, 90 is east, etc.\nBy default, no filter is applied.\nNote that a slight margin is applied to the edges to avoid filtering images at the edges of the range.","schema":{"type":"string"}},{"name":"pitch","required":false,"in":"query","description":"Camera angle below horizontal in degrees, expressed as an inclusive range [pmin, pmax], or as a single value.\nRange: [-135, 45], where -90 is directly downward (nadir), -60 is oblique, and -30 is more horizontal.\nBy default, no filter is applied.\nNote that a slight margin is applied to the edges to avoid missing images at the edges of the range.","schema":{"type":"string"}},{"name":"altitude","required":false,"in":"query","description":"Camera altitude above ground level in meters, expressed as an inclusive range [amin, amax], or as a single value.\nRange: [0, 10000], where 0 is ground level and 10000m is the practical maximum.\nBy default, no filter is applied.\nNote that a slight margin is applied to the edges to avoid missing images at the edges of the range.","schema":{"type":"string"}},{"name":"captured_at","required":false,"in":"query","description":"Image capture timestamp, expressed as an inclusive range [start, end], or as a single value.\nFormat: Any valid JavaScript date format (e.g., \"2023-01-01T00:00:00Z\", \"2023-01-01\", \"Jan 1, 2023\").\nBy default, no filter is applied.","schema":{"type":"string"}},{"name":"capture_type","required":false,"in":"query","description":"Filter by image capture type(s). Can be a single type or comma-separated list.\nValid values: panorama, orthomosaic, oblique.\nExample: \"panorama\" or \"panorama,oblique\".\nBy default, no filter is applied.","schema":{"type":"string"}},{"name":"focused","required":false,"in":"query","description":"Filtering mode: 'none' (no filtering), 'focused' (prioritize images where the point/area of interest is prominently featured), or '5-view' (return up to 5 images representing different viewing angles: nadir, north, east, south, west). Note: pagination is not supported for 'focused' and '5-view' modes.","schema":{"default":"none","enum":["none","focused","5-view"],"type":"string"}},{"name":"limit","required":false,"in":"query","description":"Maximum number of features to return. The default is 50, the maximum is 100.","schema":{"minimum":1,"type":"integer"}},{"name":"cursor","required":false,"in":"query","description":"Pagination token for retrieving subsequent result sets. Obtained from previous response when additional results exist.","schema":{"pattern":"^[aV64kbEPFOzgpjAGnN710Bvw8sucxrIQyXtdRJfMqK39CZUhoiLS2DWeH5mYlT]+$","type":"string"}},{"name":"f","required":false,"in":"path","description":"Response format type","schema":{"enum":["application/geo+json","application/json","text/html"],"type":"string"}},{"name":"Accept","in":"header","description":"Response format (unless specified by the `f` parameter)","required":false,"schema":{"type":"string","enum":["application/geo+json","application/json","text/html","*/*"]}},{"name":"Authorization","in":"header","description":"Bearer token for authenticated requests","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrientedImageCollectionItemsResponse"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDto"}}}},"401":{"description":"Unauthorized"},"406":{"description":"Not Acceptable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDto"}}}},"500":{"description":"Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDto"}}}}},"summary":"Retrieve image features from a collection","tags":["OGC API"]}}}}
```


# Coverage API

The Coverage API lets you check where Spexi has drone imagery available, expressed as H3 hexagonal cells. Use it to render a coverage map, query coverage for an area, or look up detail on a specific zone before placing a tasking order.

### Endpoints

* [Get Coverage Tiles](/api-reference/coverage-api/get-coverage-tiles) - fetch MVT vector tiles of coverage for map rendering, by zoom/x/y
* [Query Coverage](/api-reference/coverage-api/query-coverage) - query aggregated coverage zones by bounding box or point
* [Get Zone Details](/api-reference/coverage-api/zone-details) - fetch full coverage detail for a single H3 cell, including missions and latest capture

### Choosing an Endpoint

**Get Coverage Tiles** returns vector tiles (MVT) meant for rendering a coverage layer on a map at a given zoom level. Use this to visualize coverage across an area.

**Query Coverage** returns aggregated zone data for a bounding box or point. Useful when you need the underlying coverage data itself rather than a map layer, for example, to check coverage programmatically before deciding whether to place a tasking order.

**Get Zone Details** returns full detail for one H3 cell (mission list, mission count, latest capture date). Use this once you've identified a specific zone, for example, after retrieving a response from Query Coverage.

### Filtering

All three endpoints support the same capture type and date filters, and the same entitlement filter.

### Entitlement Filtering

Pass **`entitled=true`** to restrict results to coverage the authenticated caller is entitled to, rather than all coverage that exists. This requires authentication; passing `entitled=true` without valid auth returns a 401. Omit it (or leave it `false`) to see all coverage regardless of entitlement.


# GET Coverage tiles

## Get coverage tiles

> Returns MVT tiles showing coverage as H3 hexagonal cells. Supports filtering by capture type and date range. Pass ?entitled=true to return only coverage the authenticated user is entitled to.

```json
{"openapi":"3.0.3","info":{"title":"Spexi Developer API","version":"1.0.0"},"servers":[{"url":"https://world.spexi.com","description":"Production"}],"security":[{"ApiKeyHeader":[]},{"ApiKeyQuery":[]}],"components":{"securitySchemes":{"ApiKeyHeader":{"type":"apiKey","in":"header","name":"x-api-key","description":"API key passed via request header. Either this or the `api_key` query parameter is required."},"ApiKeyQuery":{"type":"apiKey","in":"query","name":"api_key","description":"API key passed as a query parameter. Either this or the `x-api-key` header is required."}}},"paths":{"/developer-api/coverage-map/tiles/{z}/{x}/{y}.mvt":{"get":{"description":"Returns MVT tiles showing coverage as H3 hexagonal cells. Supports filtering by capture type and date range. Pass ?entitled=true to return only coverage the authenticated user is entitled to.","operationId":"CoverageController_getCoverageTiles","parameters":[{"name":"z","required":true,"in":"path","description":"Zoom level (0-20)","schema":{"minimum":0,"maximum":20,"type":"number"}},{"name":"x","required":true,"in":"path","description":"Tile X coordinate","schema":{"minimum":0,"type":"number"}},{"name":"y","required":true,"in":"path","description":"Tile Y coordinate","schema":{"minimum":0,"type":"number"}},{"name":"captureTypes","required":false,"in":"query","description":"Comma-separated list of capture types to filter by. Valid values: panorama, orthomosaic, image. Unrecognized values are ignored. Example: panorama,orthomosaic","schema":{"type":"string"}},{"name":"startDate","required":false,"in":"query","description":"Inclusive lower bound on capture date (ISO 8601). Coverage captured before this is excluded. Example: 2024-01-01T00:00:00.000Z","schema":{"format":"date-time","type":"string"}},{"name":"endDate","required":false,"in":"query","description":"Inclusive upper bound on capture date (ISO 8601). Coverage captured after this is excluded. Example: 2024-12-31T23:59:59.000Z","schema":{"format":"date-time","type":"string"}},{"name":"entitled","required":false,"in":"query","description":"Filter by user entitlements (requires auth)","schema":{"default":false,"type":"boolean"}}],"responses":{"200":{"description":"MVT tile data","content":{"application/vnd.mapbox-vector-tile":{}}},"401":{"description":"Unauthorized - entitled=true requires authentication"}},"summary":"Get coverage tiles","tags":["Coverage"]}}}}
```


# GET Query coverage

## Query coverage

> Query coverage data by bounding box or point. Returns aggregated zones with coverage information. Pass ?entitled=true to return only data the authenticated user is entitled to.

```json
{"openapi":"3.0.3","info":{"title":"Spexi Developer API","version":"1.0.0"},"servers":[{"url":"https://world.spexi.com","description":"Production"}],"security":[{"ApiKeyHeader":[]},{"ApiKeyQuery":[]}],"components":{"securitySchemes":{"ApiKeyHeader":{"type":"apiKey","in":"header","name":"x-api-key","description":"API key passed via request header. Either this or the `api_key` query parameter is required."},"ApiKeyQuery":{"type":"apiKey","in":"query","name":"api_key","description":"API key passed as a query parameter. Either this or the `x-api-key` header is required."}},"schemas":{"CoverageQueryResponse":{"type":"object","properties":{"zones":{"type":"array","items":{"type":"object","properties":{"h3Id":{"type":"string","description":"H3 cell identifier (zone hash)."},"captureTypes":{"type":"array","items":{"type":"string","enum":["panorama","orthomosaic","image"]},"description":"Capture types available in this zone."},"latestCapture":{"type":"string","format":"date-time","nullable":true,"description":"Most recent capture date in this zone (ISO 8601)."},"missionCount":{"type":"integer","description":"Number of missions contributing coverage to this zone."}},"required":["h3Id","captureTypes","latestCapture","missionCount"]},"description":"Matching zones, each aggregating coverage for one H3 cell."},"total":{"type":"integer","description":"Number of zones returned after applying the query limit."}},"required":["zones","total"]}}},"paths":{"/developer-api/coverage-map/query":{"get":{"description":"Query coverage data by bounding box or point. Returns aggregated zones with coverage information. Pass ?entitled=true to return only data the authenticated user is entitled to.","operationId":"CoverageController_queryCoverage","parameters":[{"name":"bbox","required":false,"in":"query","description":"Bounding box to query, in format minLon,minLat,maxLon,maxLat. Provide at least one of `bbox` or `point`; if both are supplied, `bbox` is used. Example: -123.2,49.1,-122.9,49.3","schema":{"type":"string"}},{"name":"point","required":false,"in":"query","description":"Point to query, in format lon,lat. Provide at least one of `bbox` or `point`; ignored when `bbox` is also supplied. Example: -123.1,49.25","schema":{"type":"string"}},{"name":"captureTypes","required":false,"in":"query","description":"Comma-separated list of capture types to filter by. Valid values: panorama, orthomosaic, image. Unrecognized values are ignored. Example: panorama,orthomosaic","schema":{"type":"string"}},{"name":"startDate","required":false,"in":"query","description":"Inclusive lower bound on capture date (ISO 8601). Example: 2024-01-01T00:00:00.000Z","schema":{"format":"date-time","type":"string"}},{"name":"endDate","required":false,"in":"query","description":"Inclusive upper bound on capture date (ISO 8601). Example: 2024-12-31T23:59:59.000Z","schema":{"format":"date-time","type":"string"}},{"name":"limit","required":false,"in":"query","description":"Maximum number of zones to return. Must be between 1 and 1000. The default is 100.","schema":{"minimum":1,"maximum":1000,"default":100,"type":"integer"}},{"name":"entitled","required":false,"in":"query","description":"Filter by user entitlements (requires auth)","schema":{"default":false,"type":"boolean"}}],"responses":{"200":{"description":"Coverage query results","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CoverageQueryResponse"}}}},"400":{"description":"Invalid query: missing bbox/point, malformed bbox/point format, or coordinates out of range"},"401":{"description":"Unauthorized - entitled=true requires authentication"}},"summary":"Query coverage","tags":["Coverage"]}}}}
```


# GET Zone details

## Get zone details

> Returns detailed information about a specific zone (H3 cell), including available capture types and mission dates. Pass ?entitled=true to return only data the authenticated user is entitled to.

```json
{"openapi":"3.0.3","info":{"title":"Spexi Developer API","version":"1.0.0"},"servers":[{"url":"https://world.spexi.com","description":"Production"}],"security":[{"ApiKeyHeader":[]},{"ApiKeyQuery":[]}],"components":{"securitySchemes":{"ApiKeyHeader":{"type":"apiKey","in":"header","name":"x-api-key","description":"API key passed via request header. Either this or the `api_key` query parameter is required."},"ApiKeyQuery":{"type":"apiKey","in":"query","name":"api_key","description":"API key passed as a query parameter. Either this or the `x-api-key` header is required."}},"schemas":{"ZoneDetailResponse":{"type":"object","properties":{"h3Id":{"type":"string","description":"H3 cell identifier"},"captureTypes":{"type":"array","items":{"type":"string","enum":["panorama","orthomosaic","image"]},"description":"Capture types available in this cell"},"missions":{"type":"array","items":{"type":"object","properties":{"missionId":{"type":"number","description":"Mission ID"},"captureTypes":{"type":"array","items":{"type":"string","enum":["panorama","orthomosaic","image"]},"description":"Capture types in this mission"},"captureDate":{"type":"string","format":"date-time","description":"When the mission was executed"}},"required":["missionId","captureTypes","captureDate"]},"description":"Missions within this zone"},"latestCapture":{"type":"string","format":"date-time","nullable":true,"description":"Most recent capture date"},"missionCount":{"type":"integer","description":"Total number of missions"},"previewUrl":{"type":"string","nullable":true,"description":"Relative URL path for preview image"}},"required":["h3Id","captureTypes","missions","latestCapture","missionCount"]}}},"paths":{"/developer-api/coverage-map/zone/{h3Id}":{"get":{"description":"Returns detailed information about a specific zone (H3 cell), including available capture types and mission dates. Pass ?entitled=true to return only data the authenticated user is entitled to.","operationId":"CoverageController_getZoneDetail","parameters":[{"name":"h3Id","required":true,"in":"path","description":"H3 cell identifier (zone hash)","schema":{"pattern":"^[0-9a-fA-F]+$","type":"string"}},{"name":"captureTypes","required":false,"in":"query","description":"Comma-separated list of capture types to filter by. Valid values: panorama, orthomosaic, image. Unrecognized values are ignored. Example: panorama,orthomosaic","schema":{"type":"string"}},{"name":"startDate","required":false,"in":"query","description":"Inclusive lower bound on capture date (ISO 8601). Coverage captured before this is excluded. Example: 2024-01-01T00:00:00.000Z","schema":{"format":"date-time","type":"string"}},{"name":"endDate","required":false,"in":"query","description":"Inclusive upper bound on capture date (ISO 8601). Coverage captured after this is excluded. Example: 2024-12-31T23:59:59.000Z","schema":{"format":"date-time","type":"string"}},{"name":"entitled","required":false,"in":"query","description":"Filter by user entitlements (requires auth)","schema":{"default":false,"type":"boolean"}}],"responses":{"200":{"description":"Zone details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ZoneDetailResponse"}}}},"401":{"description":"Unauthorized - entitled=true requires authentication"},"404":{"description":"Zone not found"}},"summary":"Get zone details","tags":["Coverage"]}}}}
```


# Image API

The Image API provides direct access to Spexi's drone imagery library, allowing you to search, filter, and download full resolution images available to your account.

### Endpoints

* [Search Images](/api-reference/image-api/search-images) - search by location and camera parameters, with pagination
* [Search Multi-View Images](/api-reference/image-api/search-multi-view-images) - get up to 5 curated images of a location from diverse angles in one call
* [Download Image File](#downloading-images) - download a single image by id, with optional zoom and crop

### Spatial Filtering

Every search endpoint requires at least one way to describe where you're looking: a point (`p`), a bounding box (`bbox`), or a polygon (`polygon`).

**Search Images** supports full filtering on top of this, including camera angle, altitude, capture date, and capture type, combined with AND logic, plus focused filtering (see below).

**Search Multi-View Images** only adds capture date (`captured_at`) filtering. Instead of manual filtering, it automatically curates up to 5 images (nadir plus each cardinal direction, when available) for the location.

### Focused Filtering (Search Images only)

By default, **Search Images** results are filtered and ranked so the most relevant, well-framed images surface first; this is what `focused` controls. It works in three steps:

1. **Spatial filtering** - start with all images whose footprint contains your point or area of interest
2. **Edge filtering** - remove images where that point or area sits too close to the frame's edge
3. **Focus scoring** - rank the remainder by how prominently the point or area is featured, returning only images above a quality threshold

{% hint style="info" %}
Set **`focused=false`** to skip this and get all spatially intersecting images regardless of framing. This is useful for systematic processing or full coverage extraction.
{% endhint %}

### Downloading Images

Every image feature's `links` array includes two download options:

* **`rel: "original"`** - full resolution image as captured
* **`rel: "zoomed"`** - automatically cropped and zoomed to your area of interest

Download URLs require the same `x-api-key` authentication as the search requests. Images are delivered as high-resolution JPEGs with EXIF and XMP metadata embedded.


# GET Search images

## GET /developer-api/api/v1/image

> Search images

```json
{"openapi":"3.0.3","info":{"title":"Spexi Developer API","version":"1.0.0"},"servers":[{"url":"https://world.spexi.com","description":"Production"}],"security":[{"ApiKeyHeader":[]},{"ApiKeyQuery":[]}],"components":{"securitySchemes":{"ApiKeyHeader":{"type":"apiKey","in":"header","name":"x-api-key","description":"API key passed via request header. Either this or the `api_key` query parameter is required."},"ApiKeyQuery":{"type":"apiKey","in":"query","name":"api_key","description":"API key passed as a query parameter. Either this or the `x-api-key` header is required."}},"schemas":{"ImageSearchResponse":{"type":"object","properties":{"type":{"type":"string","enum":["FeatureCollection"]},"features":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["Feature"]},"geometry":{"type":"object","properties":{"type":{"type":"string","enum":["Polygon"]},"coordinates":{"type":"array","items":{"type":"array","items":{}}}},"required":["type","coordinates"],"description":"Geographic area captured within the image (footprint)."},"properties":{"type":"object","properties":{"id":{"type":"string","description":"Encoded image identifier (SID)."},"key":{"type":"string","description":"Unique identifier for the image."},"url":{"type":"string","format":"uri","description":"S3 URL to the image."},"captureType":{"type":"string","description":"Type of image capture (e.g., panorama, orthomosaic, oblique)."},"heading":{"type":"number","description":"Camera heading in degrees [0, 360), 0 is north."},"pitch":{"type":"number","description":"Camera angle below horizontal in degrees [-135, 45], -90 is nadir."},"roll":{"type":"number","description":"Camera roll in degrees."},"altitude":{"type":"number","description":"Altitude above ground level in meters."},"tag":{"type":"string","description":"Optional tag for grouping images."},"attributes":{"type":"object","additionalProperties":{},"description":"Additional metadata stored as JSON."},"capturedAt":{"type":"string","description":"Timestamp when image was captured."},"processedAt":{"type":"string","description":"Timestamp when image was processed."},"cameraPosition":{"type":"object","properties":{"type":{"type":"string","enum":["Point"]},"coordinates":{}},"required":["type","coordinates"],"description":"2D point location of the camera at time of capture."},"distance":{"type":"number","description":"Distance in meters from the query point (only present when querying by point)."},"aoiPixelBounds":{"nullable":true,"description":"Pixel bounds of the area of interest within the original image, as [left, top, right, bottom] with the origin at the top-left. Always present when 'pixel_bounds' is requested, and null when there are no bounds."},"aoiPixelBoundsUnavailable":{"type":"boolean","description":"Always present when 'pixel_bounds' is requested. True when the bounds could not be computed for this image and False when the area of interest is not visible in this image."}},"required":["id","key","url","captureType","heading","pitch","roll","altitude","capturedAt","processedAt","cameraPosition"]},"links":{"type":"array","items":{"type":"object","properties":{"rel":{"type":"string","description":"Link relation type."},"href":{"type":"string","format":"uri","description":"URL of the linked resource."},"type":{"type":"string","description":"Media type of the linked resource."},"title":{"type":"string","description":"Human-readable title for the link."}},"required":["rel","href"]},"description":"Links to image variants."}},"required":["id","type","geometry","properties"]}},"next":{"type":"string","format":"uri","description":"URL to fetch the next page of results, if more exist."},"numberReturned":{"type":"number","description":"The number of features in the response."}},"required":["type","features","numberReturned"]}}},"paths":{"/developer-api/api/v1/image":{"get":{"operationId":"ImageController_searchImages","parameters":[{"name":"p","required":false,"in":"query","description":"A point of interest to query with an optional radius search parameter in the format longitude,latitude[,radiusMeters]. Returns images that view any portion of the specified point or radius area.","schema":{"type":"string"}},{"name":"bbox","required":false,"in":"query","description":"An area of interest to query in the format `minLon,minLat,maxLon,maxLat`.","schema":{"type":"string"}},{"name":"polygon","required":false,"in":"query","description":"Polygon coordinates to query, in WKT format. Maximum polygon bounding box area: 1 km².","schema":{"type":"string"}},{"name":"heading","required":false,"in":"query","description":"Camera heading in degrees, expressed as an inclusive range [hmin, hmax], or as a single value.\nRange: [0, 360), where 0 is north, 90 is east, etc.\nBy default, no filter is applied.\nNote that a slight margin is applied to the edges to avoid filtering images at the edges of the range.","schema":{"type":"string"}},{"name":"pitch","required":false,"in":"query","description":"Camera angle below horizontal in degrees, expressed as an inclusive range [pmin, pmax], or as a single value.\nRange: [-135, 45], where -90 is directly downward (nadir), -60 is oblique, and -30 is more horizontal.\nBy default, no filter is applied.\nNote that a slight margin is applied to the edges to avoid missing images at the edges of the range.","schema":{"type":"string"}},{"name":"altitude","required":false,"in":"query","description":"Camera altitude above ground level in meters, expressed as an inclusive range [amin, amax], or as a single value.\nRange: [0, 10000], where 0 is ground level and 10000m is the practical maximum.\nBy default, no filter is applied.\nNote that a slight margin is applied to the edges to avoid missing images at the edges of the range.","schema":{"type":"string"}},{"name":"captured_at","required":false,"in":"query","description":"Image capture timestamp, expressed as an inclusive range [start, end], or as a single value.\nFormat: Any valid JavaScript date format (e.g., \"2023-01-01T00:00:00Z\", \"2023-01-01\", \"Jan 1, 2023\").\nBy default, no filter is applied.","schema":{"type":"string"}},{"name":"capture_type","required":false,"in":"query","description":"Filter by image capture type(s). Can be a single type or comma-separated list.\nValid values: panorama, orthomosaic, oblique.\nExample: \"panorama\" or \"panorama,oblique\".\nBy default, no filter is applied.","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","description":"Maximum number of images to return. The default is 100.","schema":{"minimum":1,"maximum":1000,"default":100,"type":"integer"}},{"name":"cursor","required":false,"in":"query","description":"Pagination token for retrieving subsequent result sets. Obtained from previous response when additional results exist.","schema":{"pattern":"^[aV64kbEPFOzgpjAGnN710Bvw8sucxrIQyXtdRJfMqK39CZUhoiLS2DWeH5mYlT]+$","type":"string"}},{"name":"focused","required":false,"in":"query","description":"Apply advanced filtering to prioritize images where the point/area of interest is prominently featured.","schema":{"default":true,"oneOf":[{"type":"boolean"},{"type":"string"}]}},{"name":"pixel_bounds","required":false,"in":"query","description":"Include 'aoiPixelBounds' on each feature, locating the area of interest within the original image. Adds latency, as each image is projected.","schema":{"default":false,"oneOf":[{"type":"boolean"},{"type":"string"}]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImageSearchResponse"}}}}},"summary":"Search images","tags":["Image"]}}}}
```


# GET Search multi-view images

## GET /developer-api/api/v1/image/multi-view

> Search multi-view images

```json
{"openapi":"3.0.3","info":{"title":"Spexi Developer API","version":"1.0.0"},"servers":[{"url":"https://world.spexi.com","description":"Production"}],"security":[{"ApiKeyHeader":[]},{"ApiKeyQuery":[]}],"components":{"securitySchemes":{"ApiKeyHeader":{"type":"apiKey","in":"header","name":"x-api-key","description":"API key passed via request header. Either this or the `api_key` query parameter is required."},"ApiKeyQuery":{"type":"apiKey","in":"query","name":"api_key","description":"API key passed as a query parameter. Either this or the `x-api-key` header is required."}},"schemas":{"ImageSearchResponse":{"type":"object","properties":{"type":{"type":"string","enum":["FeatureCollection"]},"features":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["Feature"]},"geometry":{"type":"object","properties":{"type":{"type":"string","enum":["Polygon"]},"coordinates":{"type":"array","items":{"type":"array","items":{}}}},"required":["type","coordinates"],"description":"Geographic area captured within the image (footprint)."},"properties":{"type":"object","properties":{"id":{"type":"string","description":"Encoded image identifier (SID)."},"key":{"type":"string","description":"Unique identifier for the image."},"url":{"type":"string","format":"uri","description":"S3 URL to the image."},"captureType":{"type":"string","description":"Type of image capture (e.g., panorama, orthomosaic, oblique)."},"heading":{"type":"number","description":"Camera heading in degrees [0, 360), 0 is north."},"pitch":{"type":"number","description":"Camera angle below horizontal in degrees [-135, 45], -90 is nadir."},"roll":{"type":"number","description":"Camera roll in degrees."},"altitude":{"type":"number","description":"Altitude above ground level in meters."},"tag":{"type":"string","description":"Optional tag for grouping images."},"attributes":{"type":"object","additionalProperties":{},"description":"Additional metadata stored as JSON."},"capturedAt":{"type":"string","description":"Timestamp when image was captured."},"processedAt":{"type":"string","description":"Timestamp when image was processed."},"cameraPosition":{"type":"object","properties":{"type":{"type":"string","enum":["Point"]},"coordinates":{}},"required":["type","coordinates"],"description":"2D point location of the camera at time of capture."},"distance":{"type":"number","description":"Distance in meters from the query point (only present when querying by point)."},"aoiPixelBounds":{"nullable":true,"description":"Pixel bounds of the area of interest within the original image, as [left, top, right, bottom] with the origin at the top-left. Always present when 'pixel_bounds' is requested, and null when there are no bounds."},"aoiPixelBoundsUnavailable":{"type":"boolean","description":"Always present when 'pixel_bounds' is requested. True when the bounds could not be computed for this image and False when the area of interest is not visible in this image."}},"required":["id","key","url","captureType","heading","pitch","roll","altitude","capturedAt","processedAt","cameraPosition"]},"links":{"type":"array","items":{"type":"object","properties":{"rel":{"type":"string","description":"Link relation type."},"href":{"type":"string","format":"uri","description":"URL of the linked resource."},"type":{"type":"string","description":"Media type of the linked resource."},"title":{"type":"string","description":"Human-readable title for the link."}},"required":["rel","href"]},"description":"Links to image variants."}},"required":["id","type","geometry","properties"]}},"next":{"type":"string","format":"uri","description":"URL to fetch the next page of results, if more exist."},"numberReturned":{"type":"number","description":"The number of features in the response."}},"required":["type","features","numberReturned"]}}},"paths":{"/developer-api/api/v1/image/multi-view":{"get":{"operationId":"ImageController_searchMultiViewImages","parameters":[{"name":"p","required":false,"in":"query","description":"A point of interest to query with an optional radius search parameter in the format longitude,latitude[,radiusMeters]. Returns images representing diverse viewing angles of the specified point.","schema":{"type":"string"}},{"name":"bbox","required":false,"in":"query","description":"An area of interest to query in the format `minLon,minLat,maxLon,maxLat`.","schema":{"type":"string"}},{"name":"polygon","required":false,"in":"query","description":"WKT POLYGON to query. Converted to bounding box for search, but original polygon used for highlighting. Maximum bbox area: 1 km².","schema":{"type":"string"}},{"name":"captured_at","required":false,"in":"query","description":"Image capture timestamp, expressed as an inclusive range [start, end], or as a single value.\nFormat: Any valid JavaScript date format (e.g., \"2023-01-01T00:00:00Z\", \"2023-01-01\", \"Jan 1, 2023\").\nBy default, no filter is applied.","schema":{"type":"string"}},{"name":"pixel_bounds","required":false,"in":"query","description":"Include 'aoiPixelBounds' on each feature, locating the area of interest within the original image. Adds latency, as each image is projected.","schema":{"default":false,"oneOf":[{"type":"boolean"},{"type":"string"}]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImageSearchResponse"}}}}},"summary":"Search multi-view images","tags":["Image"]}}}}
```


# GET Download image

## Download image file

> Downloads an image with optional processing. Set 'zoom=true' to crop to the AOI. Requires 'aoi' parameter when zoom is enabled.

```json
{"openapi":"3.0.3","info":{"title":"Spexi Developer API","version":"1.0.0"},"servers":[{"url":"https://world.spexi.com","description":"Production"}],"security":[{"ApiKeyHeader":[]},{"ApiKeyQuery":[]}],"components":{"securitySchemes":{"ApiKeyHeader":{"type":"apiKey","in":"header","name":"x-api-key","description":"API key passed via request header. Either this or the `api_key` query parameter is required."},"ApiKeyQuery":{"type":"apiKey","in":"query","name":"api_key","description":"API key passed as a query parameter. Either this or the `x-api-key` header is required."}}},"paths":{"/developer-api/api/v1/image/{imageId}/download":{"get":{"description":"Downloads an image with optional processing. Set 'zoom=true' to crop to the AOI. Requires 'aoi' parameter when zoom is enabled.","operationId":"ImageController_downloadImage","parameters":[{"name":"imageId","required":true,"in":"path","description":"Image identifier (SID format)","schema":{"minLength":1,"type":"string"}},{"name":"zoom","required":false,"in":"query","description":"Crop and zoom the image to the area of interest.","schema":{"default":false,"oneOf":[{"type":"boolean"},{"type":"string"}]}},{"name":"highlight","required":false,"in":"query","description":"Draw the AOI outline (or marker) on the image.","schema":{"default":false,"oneOf":[{"type":"boolean"},{"type":"string"}]}},{"name":"aoi","required":false,"in":"query","description":"Area of interest polygon in WKT format. Required if zoom is true.","schema":{"type":"string"}},{"name":"marker","required":false,"in":"query","description":"Point to mark instead of polygon outline. Format: lon,lat.","schema":{"pattern":"^-?\\d+(?:\\.\\d+)?,-?\\d+(?:\\.\\d+)?$","type":"string"}},{"name":"padding","required":false,"in":"query","description":"Zoom padding as a fraction (0.0 - 1.0). Default is 1.0 (100%).","schema":{"minimum":0,"maximum":1,"type":"number"}}],"responses":{"200":{"description":"Image file (JPEG)","content":{"image/jpeg":{}}},"422":{"description":"AOI does not intersect image footprint"}},"summary":"Download image file","tags":["Image"]}}}}
```


# Tasking API

The Tasking API lets you request new drone captures of an area of interest and track their progress from submission through delivery. Submit an order specifying the area, the products you need, and your customer details - then follow each product through its lifecycle.

### Endpoints

* [Submit Tasking Order](/api-reference/tasking-api/submit-tasking-order) - create a new capture request
* [Get Tasking Order Details](/api-reference/tasking-api/list-tasking-order-details) - fetch full details for a single order
* [List Tasking Orders](/api-reference/tasking-api/list-all-tasking-orders) - list and filter orders for your organization

### Area of Interest

An order's area is defined one of two ways, never both: a list of H3 **`zones`**, or a GeoJSON **`geometry`** polygon.

### Products

Each order requests one or more products. Every product on an order is tracked independently and moves through its own status lifecycle.

### Order Product Status Lifecycle

Each product on an order moves independently through this lifecycle:

<table data-search="false"><thead><tr><th>Status</th><th>Definition</th></tr></thead><tbody><tr><td><mark style="background-color:$info;"><code>submitted</code></mark></td><td>Order received, not yet reviewed</td></tr><tr><td><mark style="background-color:cyan;"><code>in_review</code></mark></td><td>Spexi is reviewing the request</td></tr><tr><td><mark style="background-color:orange;"><code>feasibility_check</code></mark></td><td>Assessing whether the capture is achievable (site access, airspace, terrain, etc.)</td></tr><tr><td><mark style="background-color:orange;"><code>pending_confirmation</code></mark></td><td>Awaiting customer confirmation before mission planning begins</td></tr><tr><td><mark style="background-color:orange;"><code>in_planning</code></mark></td><td>Mission planning in progress</td></tr><tr><td><mark style="background-color:blue;"><code>capture_in_progress</code></mark></td><td>Pilots are actively capturing the area</td></tr><tr><td><mark style="background-color:violet;"><code>processing</code></mark></td><td>Captured data is being stitched/processed into the final product</td></tr><tr><td><mark style="background-color:violet;"><code>qa</code></mark></td><td>Product is in quality review before delivery</td></tr><tr><td><mark style="background-color:green;"><code>delivered</code></mark></td><td>Product delivered</td></tr><tr><td><mark style="background-color:$info;"><code>cancelled</code></mark></td><td>Order product was cancelled</td></tr><tr><td><mark style="background-color:$info;"><code>unfulfillable</code></mark></td><td>Spexi determined the product can't be completed (e.g. failed feasibility)</td></tr></tbody></table>

The `status` filter on [**List Tasking Orders**](/api-reference/tasking-api/list-all-tasking-orders) uses this lifecycle: `current` matches orders with at least one product not yet in a terminal state, `past` matches orders where every product has reached `delivered`, `cancelled`, or `unfulfillable`.

### Authentication

All tasking endpoints accept an API key via the `x-api-key` header or the `api_key` query parameter.&#x20;


# POST Submit tasking request

## Submit tasking order

> Creates a tasking order for a new capture request. The area of interest can be provided as H3 zones or a GeoJSON polygon, and each requested product is tracked independently.

```json
{"openapi":"3.0.3","info":{"title":"Spexi Developer API","version":"1.0.0"},"servers":[{"url":"https://world.spexi.com","description":"Production"}],"security":[{"ApiKeyHeader":[]},{"ApiKeyQuery":[]}],"components":{"securitySchemes":{"ApiKeyHeader":{"type":"apiKey","in":"header","name":"x-api-key","description":"API key passed via request header. Either this or the `api_key` query parameter is required."},"ApiKeyQuery":{"type":"apiKey","in":"query","name":"api_key","description":"API key passed as a query parameter. Either this or the `x-api-key` header is required."}},"schemas":{"CreateOrderRequest":{"type":"object","properties":{"zones":{"type":"array","items":{"type":"string"},"minItems":1,"description":"Area of interest expressed as a list of H3 cell identifiers. Provide this OR `geometry`, never both. Must contain at least one zone."},"geometry":{"type":"object","properties":{"type":{"type":"string","enum":["Feature"]},"geometry":{"type":"object","properties":{"type":{"type":"string","enum":["Polygon"]},"coordinates":{"type":"array","items":{"type":"array","items":{}}}},"required":["type","coordinates"],"description":"GeoJSON Polygon describing the capture area of interest, in [longitude, latitude] coordinate order."},"properties":{"type":"object","additionalProperties":{},"nullable":true,"description":"Optional GeoJSON feature properties. Ignored by the API."}},"required":["type","geometry"],"description":"GeoJSON Feature wrapping a Polygon area of interest. Provide this OR `zones`, never both."},"intent":{"type":"string","enum":["new_capture"],"description":"Purpose of the order. Currently only `new_capture` (request a fresh capture of the area) is supported."},"products":{"type":"array","items":{"type":"object","properties":{"product_type":{"type":"string","enum":["panorama","orthomosaic","image"],"description":"Type of deliverable product requested."},"product_sub_type":{"type":"string","enum":["standard","aligned"],"description":"Product variant. Required when `product_type` is `orthomosaic`; must be omitted otherwise."}},"required":["product_type"]},"minItems":1,"description":"Products requested for this order. At least one is required; each is tracked and progresses through its lifecycle independently."},"customer_org_name":{"type":"string","minLength":1,"description":"Name of the customer organization placing the order."},"customer_first_name":{"type":"string","minLength":1,"description":"First name of the primary customer contact."},"customer_last_name":{"type":"string","minLength":1,"description":"Last name of the primary customer contact."},"customer_email":{"type":"string","format":"email","description":"Email address of the primary customer contact."},"preferred_capture_start":{"type":"string","format":"date-time","description":"Preferred start of the capture window (ISO-8601). When both bounds are supplied, must be before `preferred_capture_end`."},"preferred_capture_end":{"type":"string","format":"date-time","description":"Preferred end of the capture window (ISO-8601). When both bounds are supplied, must be after `preferred_capture_start`."},"external_order_id":{"type":"string","description":"Caller-supplied identifier for the order in an external system. Echoed back on read endpoints for reconciliation."},"control_data_url":{"type":"string","format":"uri","description":"URL to ground control or reference data to use for this capture."},"notes":{"type":"string","description":"Free-form notes or special instructions for the order."}},"required":["intent","products","customer_org_name","customer_first_name","customer_last_name","customer_email"]},"CreateOrderResponse":{"type":"object","properties":{"spexi_order_id":{"type":"string","description":"Spexi-assigned identifier for the newly created order."},"submitted_by_org_id":{"type":"string","format":"uuid","description":"UUID of the organization that submitted the order."},"external_order_id":{"type":"string","description":"Echoed `external_order_id` from the request, if one was sent."},"control_data_url":{"type":"string","format":"uri","description":"Echoed `control_data_url` from the request, if one was sent."},"status":{"type":"string","enum":["submitted"],"description":"Initial order status. Always `submitted` on creation."},"created_at":{"type":"string","format":"date-time","description":"ISO-8601 timestamp when the order was created."}},"required":["spexi_order_id","submitted_by_org_id","status","created_at"]}}},"paths":{"/developer-api/api/v1/order/tasking":{"post":{"description":"Creates a tasking order for a new capture request. The area of interest can be provided as H3 zones or a GeoJSON polygon, and each requested product is tracked independently.","operationId":"OrderController_submitOrder","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOrderRequest"}}}},"responses":{"201":{"description":"Tasking order accepted and persisted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOrderResponse"}}}},"400":{"description":"Invalid payload: failed validation, both/neither of `zones` and `geometry` supplied, missing `product_sub_type` for an orthomosaic, or `preferred_capture_start` not before `preferred_capture_end`."},"401":{"description":"Missing or invalid authentication credentials."},"403":{"description":"Caller lacks permission to submit orders. Only org_owner and org_admin roles (or a Developer API key) may submit."}},"summary":"Submit tasking order","tags":["Order"]}}}}
```


# GET List tasking order details

## Get tasking order details

> Returns detailed tasking order information, including customer fields, capture preferences, notes, and per-product status details.

```json
{"openapi":"3.0.3","info":{"title":"Spexi Developer API","version":"1.0.0"},"servers":[{"url":"https://world.spexi.com","description":"Production"}],"security":[{"ApiKeyHeader":[]},{"ApiKeyQuery":[]}],"components":{"securitySchemes":{"ApiKeyHeader":{"type":"apiKey","in":"header","name":"x-api-key","description":"API key passed via request header. Either this or the `api_key` query parameter is required."},"ApiKeyQuery":{"type":"apiKey","in":"query","name":"api_key","description":"API key passed as a query parameter. Either this or the `x-api-key` header is required."}},"schemas":{"GetOrderBySpexiOrderIdResponse":{"type":"object","properties":{"spexi_order_id":{"type":"string","description":"Spexi-assigned order identifier."},"external_order_id":{"type":"string","nullable":true,"description":"Caller-supplied external order id, or null if none was set."},"customer_org_name":{"type":"string","description":"Name of the customer organization that placed the order."},"customer_first_name":{"type":"string","description":"First name of the primary customer contact."},"customer_last_name":{"type":"string","description":"Last name of the primary customer contact."},"customer_email":{"type":"string","format":"email","description":"Email of the primary customer contact."},"submitted_at":{"type":"string","format":"date-time","description":"ISO-8601 timestamp when the order was submitted."},"preferred_capture_start":{"type":"string","format":"date-time","nullable":true,"description":"Preferred capture window start (ISO-8601), or null if unset."},"preferred_capture_end":{"type":"string","format":"date-time","nullable":true,"description":"Preferred capture window end (ISO-8601), or null if unset."},"notes":{"type":"string","nullable":true,"description":"Free-form notes supplied with the order, or null if none."},"order_products":{"type":"array","items":{"type":"object","properties":{"product_type":{"type":"string","enum":["panorama","orthomosaic","image"],"description":"Product type requested for this order product."},"product_sub_type":{"type":"string","enum":["standard","aligned"],"nullable":true,"description":"Only set when product_type is 'orthomosaic'; null otherwise."},"status":{"type":"string","enum":["submitted","in_review","feasibility_check","pending_confirmation","in_planning","capture_in_progress","processing","qa","delivered","cancelled","unfulfillable"],"description":"Current order_product status."},"updated_at":{"type":"string","format":"date-time","nullable":true,"description":"ISO-8601 timestamp of the most recent entry in order_product_status_log for this order_product."},"zones":{"type":"array","items":{"type":"object","properties":{"index":{"type":"string","description":"H3 cell identifier of an ordered zone."},"status":{"type":"string","enum":["uncaptured","captured","delivered"],"description":"Capture/delivery status of this zone for the order product. Precedence is delivered > captured > uncaptured."}},"required":["index","status"]},"description":"Per-zone status for every effective zone of this order product (ordered zones minus any removed). Always present; empty when no zone status resolves."}},"required":["product_type","product_sub_type","status","updated_at","zones"]},"description":"Per-product status detail for every product in the order."}},"required":["spexi_order_id","external_order_id","customer_org_name","customer_first_name","customer_last_name","customer_email","submitted_at","preferred_capture_start","preferred_capture_end","notes","order_products"]}}},"paths":{"/developer-api/api/v1/order/tasking/{spexi_order_id}":{"get":{"description":"Returns detailed tasking order information, including customer fields, capture preferences, notes, and per-product status details.","operationId":"OrderController_getOrderBySpexiOrderId","parameters":[{"name":"spexi_order_id","required":true,"in":"path","description":"Spexi-assigned order identifier to look up.","schema":{"minLength":1,"type":"string"}}],"responses":{"200":{"description":"Tasking order details.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetOrderBySpexiOrderIdResponse"}}}},"401":{"description":"Missing or invalid authentication credentials."},"403":{"description":"Caller lacks permission to access tasking orders."},"404":{"description":"No order matches the given `spexi_order_id` for the caller's organization."}},"summary":"Get tasking order details","tags":["Order"]}}}}
```


# GET List all tasking orders

## List tasking orders

> Returns tasking orders for the caller's organization, ordered by submitted\_at according to the \`sort\` query parameter (newest-first by default). Each row includes customer information, ordered products with statuses, ordered zone count, and pagination/count metadata.

```json
{"openapi":"3.0.3","info":{"title":"Spexi Developer API","version":"1.0.0"},"servers":[{"url":"https://world.spexi.com","description":"Production"}],"security":[{"ApiKeyHeader":[]},{"ApiKeyQuery":[]}],"components":{"securitySchemes":{"ApiKeyHeader":{"type":"apiKey","in":"header","name":"x-api-key","description":"API key passed via request header. Either this or the `api_key` query parameter is required."},"ApiKeyQuery":{"type":"apiKey","in":"query","name":"api_key","description":"API key passed as a query parameter. Either this or the `x-api-key` header is required."}},"schemas":{"GetOrdersResponse":{"type":"object","properties":{"orders":{"type":"array","items":{"type":"object","properties":{"spexi_order_id":{"type":"string","description":"Order identifier."},"external_order_id":{"type":"string","nullable":true,"description":"Echoed external order id if supplied at submission."},"customer":{"type":"object","properties":{"org_name":{"type":"string","description":"Organization that placed the order."},"first_name":{"type":"string","description":"First name of the primary customer contact."},"last_name":{"type":"string","description":"Last name of the primary customer contact."},"email":{"type":"string","format":"email","description":"Email of the primary customer contact."}},"required":["org_name","first_name","last_name","email"],"description":"Customer organization and primary contact information."},"products":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","enum":["panorama","orthomosaic","image"],"description":"Product type requested for this order product."},"subtype":{"type":"string","enum":["standard","aligned"],"nullable":true,"description":"Product subtype for orthomosaic products; null otherwise."},"status":{"type":"string","enum":["submitted","in_review","feasibility_check","pending_confirmation","in_planning","capture_in_progress","processing","qa","delivered","cancelled","unfulfillable"],"description":"Current status of this order product."}},"required":["type","subtype","status"]},"description":"Products included in the order, with per-product status."},"ordered_zone_count":{"type":"integer","minimum":0,"description":"Number of H3 zones ordered."},"submitted_at":{"type":"string","format":"date-time","description":"ISO-8601 timestamp when the order was submitted."}},"required":["spexi_order_id","external_order_id","customer","products","ordered_zone_count","submitted_at"]}},"metadata":{"type":"object","properties":{"page_size":{"type":"integer","minimum":0,"description":"Number of orders returned in this page."},"counts":{"type":"object","properties":{"all":{"type":"integer","minimum":0,"description":"Total order count. When `search` is active, only orders matching the search term are counted."},"current":{"type":"integer","minimum":0,"description":"Count of orders with at least one current product. When `search` is active, only matching orders are counted."},"past":{"type":"integer","minimum":0,"description":"Count of orders where every product is terminal. When `search` is active, only matching orders are counted."}},"required":["all","current","past"],"description":"Order counts for all, current, and past views. Counts respect the active `search` filter but not the `status` filter, so tab totals stay visible while browsing a filtered list."}},"required":["page_size","counts"]},"cursor":{"type":"string","description":"Opaque next-page token. Present only when more pages are available; pass as the `cursor` query param to fetch the next page."},"next":{"type":"string","format":"uri","description":"Absolute URL for the next page, carrying the current filters. Present only when more results exist."},"prev":{"type":"string","format":"uri","description":"Absolute URL for the previous page, carrying the current filters. Present only when a previous page exists."}},"required":["orders","metadata"]}}},"paths":{"/developer-api/api/v1/order/tasking":{"get":{"description":"Returns tasking orders for the caller's organization, ordered by submitted_at according to the `sort` query parameter (newest-first by default). Each row includes customer information, ordered products with statuses, ordered zone count, and pagination/count metadata.","operationId":"OrderController_getOrders","parameters":[{"name":"limit","required":false,"in":"query","description":"Maximum number of orders to return. Defaults to 100 and cannot exceed 100.","schema":{"minimum":1,"maximum":100,"default":100,"type":"integer"}},{"name":"cursor","required":false,"in":"query","description":"Opaque keyset pagination token. Follow the `next`/`prev` URLs rather than constructing it by hand.","schema":{"pattern":"^[aV64kbEPFOzgpjAGnN710Bvw8sucxrIQyXtdRJfMqK39CZUhoiLS2DWeH5mYlT]+$","type":"string"}},{"name":"search","required":false,"in":"query","description":"Case-insensitive partial match against spexi_order_id and external_order_id. Minimum 3 characters.","schema":{"minLength":3,"type":"string"}},{"name":"status","required":false,"in":"query","description":"`current` returns orders with at least one product in any non-terminal status, including submitted, feasibility_check, pending_confirmation, in_review, in_planning, capture_in_progress, processing, or qa. `past` returns orders where every product is delivered, cancelled, or unfulfillable. Omit for all.","schema":{"enum":["current","past"],"type":"string"}},{"name":"sort","required":false,"in":"query","description":"Sort direction on the `sort_by` field. `desc` (default) is newest-first.","schema":{"default":"desc","enum":["asc","desc"],"type":"string"}},{"name":"sort_by","required":false,"in":"query","description":"Field to sort by. Currently only `submitted_at` is supported.","schema":{"default":"submitted_at","enum":["submitted_at"],"type":"string"}}],"responses":{"200":{"description":"Tasking orders for the caller's organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetOrdersResponse"}}}},"401":{"description":"Missing or invalid authentication credentials."},"403":{"description":"Caller lacks permission to access tasking orders."}},"summary":"List tasking orders","tags":["Order"]}}}}
```


# Code Examples

Practical tutorials that demonstrate how to integrate the Spexi Image API into real-world applications. Each example includes working code and step-by-step explanations.

### Available Examples

**🏠** [**Address-Based Image Lookup:**](/api-reference/code-examples/address-lookup) Convert street addresses to aerial imagery using geocoding. Perfect for property assessment, real estate applications, and location-based analysis. Includes setup for geocoding services and querying images by geographic coordinates.


# House Damage Assessment

### The Scenario

We are insurance agents at **Hometown Insurance Company**. We have received a claim from a business owner whose business was damaged in a recent severe storm.

**The Claim:**

* **Address**: 1337 Bayard Ave, St Louis, MO
* **Claim**: Exterior damage from tornado - need immediate assessment

### The Problem

We need to know:

* How bad is the damage?

Normally, this would require sending an adjuster to visit the property. But with aerial imagery, we can assess the damage remotely before scheduling an on-site visit.

### The Solution

Instead, we'll use **aerial imagery** to assess the damage remotely:

1. **Get "before" images** - how the building looked before the storm
2. **Get "after" images** - recent imagery showing current conditions
3. **Compare the images** - identify what's damaged
4. **Make an informed assessment** - determine if immediate action is needed

### The Process

Using aerial imagery, we can objectively determine:

* **Is the damage real?** (verify the claim)
* **How severe is it?** (cosmetic vs. major structural)
* **Is immediate action needed?** (emergency repairs, safety concerns)
* **Next steps?** (prioritize adjuster visit, approve emergency funds)

This remote assessment helps us make informed decisions about claim handling and resource allocation.

## Code Walkthrough

Let's begin setting up the code by importing key libraries and configuring our environment variables. This code imports the necessary Python libraries for API requests, geocoding, and image display, then establishes our connection to the Spexi Image API using authentication headers. We're targeting a single address for our damage assessment analysis.

```python
import requests
import json
from geopy.geocoders import Nominatim
import os
from IPython.display import display, Image

# Configuration
API_KEY = "your-api-key"
BASE_URL = "https://api-world.spexi.com/api/ogc/v1"
HEADERS = {"Authorization": f"Bearer {API_KEY}"}

# Target addresses
addresses = [
    "1337 Bayard Ave, St Louis, MO"
]
```

### Retrieve collection ID

Now let's retrieve the collection ID of the imagery collection we have access to. This code queries the Spexi API to retrieve all accessible collections, displays the results so we can see what's available, then automatically selects the first collection for our analysis.

```python
print("🔍 Discovering available collections...")
collections_response = requests.get(f"{BASE_URL}/collections", headers=HEADERS)
collections = collections_response.json()
collection_id = collections['collections'][0]['id']  # Use first available collection
```

### Geocode address

Next, we'll convert our street address into the geographic coordinates needed for the API query. This code uses OpenStreetMap's free geocoding service to transform "4769 Dr Martin Luther King Dr, St. Louis, MO" into precise latitude and longitude coordinates, then stores those coordinates for use in our imagery requests.

```python
print("\n📍 Geocoding addresses...")
geolocator = Nominatim(user_agent="spexi_demo")
locations = []

for address in addresses:
    location = geolocator.geocode(address)
    if location:
        locations.append({
            'address': address,
            'lat': location.latitude,
            'lon': location.longitude
        })
        print(f"✓ {address} → {location.latitude:.6f}, {location.longitude:.6f}")
```

### Query before and after images

Next, we'll retrieve the before and after aerial imagery for our damage assessment. This code queries the same location twice - once for images captured before May 16th (pre-storm condition) and once for images captured after May 16th (post-storm damage), allowing us to compare the property's condition and identify any visible damage from the severe weather event.

```python
print(f"\n🖼️ Querying images from collection: {collection_id}")

for location in locations:
    # Get BEFORE images (before May 16th)
    print(f"\n📅 Getting BEFORE images for {location['address']}...")
    before_params = {
        'p': f"{location['lon']},{location['lat']}",
        'focused': 'focused',
        'captured_at': '2025-01-01,2025-05-16',
    }
    
    before_response = requests.get(
        f"{BASE_URL}/collections/{collection_id}/items",
        headers=HEADERS,
        params=before_params
    )
    
    before_images = before_response.json().get('features', [])
    print(f"Found {len(before_images)} images before the storm")
    
    # Get AFTER images (after May 16th) 
    print(f"\n📅 Getting AFTER images for {location['address']}...")
    after_params = {
        'p': f"{location['lon']},{location['lat']}",
        'focused': 'focused', 
        'captured_at': '2025-05-16,2025-12-31',
    }
    
    after_response = requests.get(
        f"{BASE_URL}/collections/{collection_id}/items",
        headers=HEADERS,
        params=after_params
    )
    
    after_images = after_response.json().get('features', [])
    print(f"Found {len(after_images)} images after the storm")
```

### Display images

Lastly, let's inspect the before and after images side-by-side for easy visual comparison. The aerial imagery clearly shows the extent of roof damage and validates the homeowner's claim, allowing the insurance agent to quickly determine next steps without requiring an immediate site visit.

```python
# Display before and after images for comparison
print(f"\n🏠 DAMAGE ASSESSMENT: {location['address']}")
print("\n📅 BEFORE STORM (Pre-May 16th):")
for i, image_data in enumerate(before_images[:1]):
    for link in image_data.get('links', []):
        if link.get('title') == 'Raw Image':
            print(f"Before Image #{i+1}:")
            display(Image(url=link['href']))
            break

print("\n📅 AFTER STORM (Post-May 16th):")
for i, image_data in enumerate(after_images[:1/]):
    for link in image_data.get('links', []):
        if link.get('title') == 'Raw Image':
            print(f"After Image #{i+1}:")
            display(Image(url=link['href']))
            break
```


# Address Lookup

The Spexi Standard Images API uses geographic coordinates (latitude/longitude) for spatial queries rather than street addresses. To work with addresses, you'll need to convert them to coordinates first using a geocoding service.

### Prerequisites

Before running the geocoding example, install the required Python library:

```bash
pip install geopy
```

### Geocoding service

While many geocoding services are available (Google Maps, Mapbox, HERE, etc.), we'll use **Nominatim** - OpenStreetMap's free geocoding service that requires no API key. Nominatim has usage limits (1 request/second) and may be less accurate than commercial services, but it's ideal for demos and moderate usage.

```python
from geopy.geocoders import Nominatim

# Initialize the geocoder
geolocator = Nominatim(user_agent="your_app_name")

# Spexi API configuration
BASE_URL = "https://api-world.spexi.com/api/ogc/v1"
COLLECTION_ID = "your_collection_id"  # Replace with actual collection ID

# Sample addresses to geocode
addresses = [
    "Science World, Vancouver, BC",
    "Palace of Fine Arts, San Francisco, CA", 
    "68 Bluenose Drive, Lunenburg, NS"
]

# Geocode each address
locations = []
for address in addresses:
    location = geolocator.geocode(address)
    if location:
        locations.append({
            "address": address,
            "latitude": location.latitude,
            "longitude": location.longitude
        })
        print(f"✓ {address}")
        print(f"  → {location.latitude:.6f}, {location.longitude:.6f}")
        print(f"  → {BASE_URL}/collections/{COLLECTION_ID}/items?p={location.longitude},{location.latitude},20&focused=focused")
    else:
        print(f"✗ Could not geocode: {address}")
```

### Output

```
✓ Science World, Vancouver, BC
  → 49.273454, -123.103674
  → https://api-world.spexi.com/api/ogc/v1/collections/your_collection_id/items?p=-123.1036739,49.2734536,50&focused=focused
✓ Palace of Fine Arts, San Francisco, CA
  → 37.802919, -122.448403
  → https://api-world.spexi.com/api/ogc/v1/collections/your_collection_id/items?p=-122.4484029,37.8029186,50&focused=focused
✓ 68 Bluenose Drive, Lunenburg, NS
  → 44.376126, -64.312429
  → https://api-world.spexi.com/api/ogc/v1/collections/your_collection_id/items?p=-64.3124287,44.3761265,50&focused=focused
```

The generated URLs can be used directly to query the items endpoint and retrieve aerial imagery for each location:

#### Science World, Vancouver, BC

<figure><img src="/files/yME3aVHhcnyyiVk4235P" alt=""><figcaption></figcaption></figure>

#### Palace of Fine Arts, San Francisco, CA

<figure><img src="/files/OkCeC52boHkThW4X0k7o" alt=""><figcaption></figcaption></figure>

#### 68 Bluenose Drive, Lunenburg, NS

<figure><img src="/files/bkm2DtPYVtMZZljipF21" alt=""><figcaption></figcaption></figure>


# Getting Started

Spexi integrations let you bring our high-quality aerial imagery into the tools your team already uses.

### Product Types

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-cover data-type="files"></th><th data-hidden></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><strong>Orthomosaics</strong></td><td>Add Spexi orthomosaic tile layers (WMTS/XYZ) into common GIS tools.</td><td><a href="/files/iH9tfwSiRzkcgR6Qbbcl">/files/iH9tfwSiRzkcgR6Qbbcl</a></td><td></td><td><a href="/pages/0fPdVgbxCg7KUw7SKyru">/pages/0fPdVgbxCg7KUw7SKyru</a></td></tr><tr><td><strong>Panoramas</strong></td><td>Add panorama markers to your map using GeoJSON, each linked to the Spexi Viewer for full 360° imagery.</td><td><a href="/files/60RsLtjVqd2YcQKHW0qY">/files/60RsLtjVqd2YcQKHW0qY</a></td><td></td><td><a href="/pages/IvT1MtKQhcqWVz1YCAWu">/pages/IvT1MtKQhcqWVz1YCAWu</a></td></tr></tbody></table>


# ArcGIS Pro

### Orthomosaics

Spexi provides [**WMTS**](#add-spexi-orthomosaics-as-a-wmts-layer) and [**XYZ**](#add-spexi-orthomosaics-as-an-xyz-tile-layer) tile service URLs that allow you to stream orthomosaics directly into ArcGIS Pro.

* **WMTS** (recommended for users familiar with WMS/WMTS workflows)
* **XYZ tiles** (fast, simple, and works with “Add Data From Path”)

### Add Spexi Orthomosaics as a WMTS Layer

Use this method if you are working with the **WMTS URL** provided in the Spexi Integrations page.

{% stepper %}
{% step %}

#### Copy Your WMTS URL&#x20;

Use the standard WMTS Capabilities URL like this:

```
https://world.spexi.com/developer-api/mapi/v1/org/ORG_ID/layer/LAYER_ID/raster-tile/WebMercatorQuad/WMTSCapabilities.xml

```

{% endstep %}

{% step %}

#### Create a WMTS Server Connection

* Open **ArcGIS Pro**
* Open an existing project or create a new one
* In the top ribbon, go to the **Insert** tab
* Click **Connections**
* Select **New WMTS Server**

A configuration window will appear.
{% endstep %}

{% step %}

#### Enter Your Spexi WMTS URL + Custom Authorization

* In the **Server URL** field, paste your WMTS URL
* Click **Add Custom Parameter**
* Set:
  * **Parameter:** `api_key`
  * **Value:** *(paste your API key)*
* Click **OK**

Your new WMTS connection will now appear under **Catalog → Servers**.
{% endstep %}

{% step %}

#### Add the Orthomosaic to the Map

* Open the **Catalog** pane (View → Catalog Pane if needed)
* Expand **Servers**
* Find your newly created WMTS connection
* Expand it to reveal your Spexi orthomosaic layer
* Drag the layer into your map
  {% endstep %}

{% step %}

#### Zoom to the Layer

If the map is blank:

* In the **Contents** pane, right-click the Spexi layer
* Select **Zoom To Layer** to view the imagery
  {% endstep %}
  {% endstepper %}

### Add Spexi Orthomosaics as an XYZ Tile Layer

ArcGIS Pro can load XYZ tiles directly using **Add Data From Path**.

This method is simple and works well for users who prefer XYZ URLs.

{% stepper %}
{% step %}

#### Build Your XYZ URL With API Key

From the Spexi Integrations page, copy your XYZ URL and append your API key:

```
https://world.spexi.com/developer-api/mapi/v1/org/ORG_ID/layer/LAYER_ID/raster-tile/WebMercatorQuad/{z}/{x}/{y}.png?api_key=YOUR_API_KEY

```

Keep `{z}`, `{x}`, and `{y}` exactly as provided.
{% endstep %}

{% step %}

#### Add XYZ Tiles Using “Add Data From Path”

* In **ArcGIS Pro**, open your project
* Go to the **Map** tab
* Click **Add Data**
* From the dropdown, select **Add Data From Path**
* Paste your full XYZ URL (including `?api_key=`)
* Click **Add**

ArcGIS Pro will detect the URL as a valid Web Tiled Layer and display it
{% endstep %}

{% step %}

#### Zoom to the Layer

If the imagery is not immediately visible:

* In the **Contents** pane, right-click the Spexi XYZ layer
* Select **Zoom To Layer**
  {% endstep %}

{% step %}

#### Save for Reuse (Optional)

To reuse this XYZ connection across projects:

* Right-click the Spexi XYZ layer in the **Contents** pane
* Click **Save As Layer File**
* Save the `.lyrx` file in a shared GIS resources folder
* Next time, simply drag the `.lyrx` file into your map
  {% endstep %}
  {% endstepper %}


# ArcGIS Online

### Orthomosaics

Spexi provides [**WMTS**](#add-spexi-orthomosaics-as-a-wmts-layer) and [**XYZ**](#add-spexi-orthomosaics-as-a-xyz-layer) tile service URLs that you can add directly into ArcGIS Online as a web layer.

**Important:**\
XYZ service URLs cannot be added as a permanent “Item” in your Content, however, ArcGIS Online does support adding external XYZ tile services directly into a web map.

ArcGIS Online allows you to add WMTS layers as a new item by supplying the URL and adding a custom parameter for your API key.

### Add Spexi Orthomosaics as a WMTS Layer

Use this method if you are working with the **WMTS URL** provided in the Spexi Integrations page.

{% stepper %}
{% step %}

#### Copy Your WMTS URL

Use the standard WMTS Capabilities URL like this:

```
https://world.spexi.com/developer-api/mapi/v1/org/ORG_ID/layer/LAYER_ID/raster-tile/WebMercatorQuad/WMTSCapabilities.xml

```

{% endstep %}

{% step %}

#### Add the WMTS Layer in ArcGIS Online

* Log into **ArcGIS Online**
* Go to the top menu → **Content**
* Click **New item**
* In the panel that appears, choose **URL**
* Paste the WMTS URL you copied from Spexi
* Under **Type**, select **WMTS**

ArcGIS Online will verify the endpoint and display configuration options.
{% endstep %}

{% step %}

#### Add Your `api_key` as a Custom Parameter

* Scroll to the **Add Custom Parameters** section
* Click **+ Add Parameter**
  * Enter:
    * **Name:** `api_key`
    * **Value:** *(paste your API key here)*

It should look like:

| Parameter Name | Value                |
| -------------- | -------------------- |
| api\_key       | YOUR\_API\_KEY\_HERE |

* Click **Add**
  {% endstep %}

{% step %}

#### Finalize the Item

* Enter a title (e.g., **Spexi Orthomosaic – WMTS**)
* Choose a folder (optional)
* Add tags such as `Spexi`, `Orthomosaic`, `WMTS`
* Click **Save**

You now have a saved Spexi WMTS layer item inside your AGOL content.
{% endstep %}

{% step %}

#### Add the Layer to a Web Map

* Open the newly created WMTS item
* Click **Open in Map Viewer**

The orthomosaic will load into the AGOL Map Viewer.

If you don’t see imagery immediately:

* Click **Zoom to Layer** from the layer’s overflow menu
  {% endstep %}

{% step %}

#### Share with Your Organization (Optional)

If you want colleagues to access the imagery:

1. Open the WMTS item page
2. Click **Share**
3. Select **Organization** or specific groups
4. Click **Save**
   {% endstep %}
   {% endstepper %}

### Add Spexi Orthomosaics as a XYZ Layer

XYZ layers can be added **directly into a Map Viewer session**:

{% stepper %}
{% step %}

#### Build Your XYZ URL With API Key

From the Spexi Integrations page, take the XYZ template and append your API key:

```
https://world.spexi.com/developer-api/mapi/v1/org/ORG_ID/layer/LAYER_ID/raster-tile/WebMercatorQuad/{z}/{x}/{y}.png?api_key=YOUR_API_KEY

```

Keep `{z}`, `{x}`, and `{y}` exactly as provided.
{% endstep %}

{% step %}

#### Add XYZ Tiles Using “Add Layer from URL”

1. In Map Viewer, click **Add → Add layer from URL**
2. Paste your full XYZ URL (including `?api_key=`)
3. Click **Add**

ArcGIS Online will detect the URL as a valid Web Tiled Layer and display it.
{% endstep %}
{% endstepper %}


# QGIS

### **Orthomosaics**

Spexi provides [**WMTS**](#add-spexi-orthomosaics-as-a-wmts-layer) and [**XYZ**](#add-spexi-orthomosaics-as-an-xyz-tile-layer) tile service URLs that allow you to stream orthomosaics directly into QGIS.

### Authentication in QGIS

Spexi tile services require HTTP header-based authentication.

You will configure:

* **Header Key:** `x-api-key`
* **Header Value:** `YOUR_API_KEY`

This applies to **both** WMTS and XYZ connections.

### Add Spexi Orthomosaics as a WMTS Layer

{% stepper %}
{% step %}

#### Create a WMTS Connection

* In the **Browser** panel, right-click **WMS/WMTS**
* Select **New Connection**
  {% endstep %}

{% step %}

#### Enter WMTS Connection Details

In the connection dialog:

* **Name:** Any descriptive name (e.g., *Spexi WMTS*)
* **URL:** Paste your Spexi WMTS URL exactly as provided

Example:

```
https://world.spexi.com/developer-api/mapi/v1/org/ORG_ID/layer/LAYER_ID/raster-tile/WebMercatorQuad/WMTSCapabilities.xml

```

{% endstep %}

{% step %}

#### Add Authentication

* Under **Authentication**, click the green **➕** icon
* Create a new configuration:
  * **Type:** *API Header*
* Add:
  * **Header Key:** `x-api-key`
  * **Header Value:** `YOUR_API_KEY`
* Save the configuration and select it in the dropdown
  {% endstep %}

{% step %}

#### Add the WMTS Layer to the Map

* In the **Browser**, expand **WMS/WMTS**
* Select your new Spexi connection
* Choose the available layer
* Drag it into your map

If the map looks blank, right-click the layer → **Zoom to Layer(s)**
{% endstep %}
{% endstepper %}

### Add Spexi Orthomosaics as an XYZ Tile Layer

{% stepper %}
{% step %}

#### Create an XYZ Tile Connection

* In the **Browser** panel, right-click **XYZ Tiles**
* Select **New Connection**
  {% endstep %}

{% step %}

#### Enter XYZ Connection Details

In the connection dialog:

* **Name:** Any descriptive name (e.g., *Spexi XYZ*)
* **URL:** Paste your Spexi XYZ URL exactly as provided

Example:

```
https://world.spexi.com/developer-api/mapi/v1/org/ORG_ID/layer/LAYER_ID/raster-tile/WebMercatorQuad/{z}/{x}/{y}.png

```

{% endstep %}

{% step %}

#### Add Authentication

* Under **Authentication**, click the green **➕** icon
* Create a new configuration:
  * **Type:** *API Header*
* Add:
  * **Header Key:** `x-api-key`
  * **Header Value:** `YOUR_API_KEY`
* Save the configuration and select it in the dropdown
  {% endstep %}

{% step %}

#### Add the XYZ Layer to the Map

* In the **Browser**, expand **XYZ Tiles**
* Drag your Spexi XYZ connection into the map
* If needed, right-click → **Zoom to Layer(s)**
  {% endstep %}
  {% endstepper %}


# Integrating Orthomosaics

Spexi orthomosaics are high-resolution aerial maps that can be streamed directly into your GIS tools - no downloading required. Our tile services allow fast visualization and smooth navigation at any scale, whether you’re analyzing a single property or an entire city.

With Spexi integrations, you can:

* Add on-demand orthomosaic layers into your GIS workspace
* Control visibility, order, transparency, and other display settings like any raster map layer.
* Benefit from optimized performance through web-friendly tile delivery
* Use your existing GIS workflows for measurement and spatial analysis

### **Before You Start**

1. Log in to the [**Spexi World Viewer**](https://world.spexi.com)
2. Open the **Integrations** section
3. Copy either URL:
   * **WMTS URL**
   * **XYZ URL**

#### **Important -** [**Copy Your API Key**](/api-reference/authentication)

Your API key is displayed **once** when you create it and cannot be retrieved again.

Make sure you **copy and store it securely**.

### How to Integrate

Choose your GIS system from the list below to view step-by-step setup instructions:

* [ArcGIS Pro](/integrations/getting-started/arcgis-pro#orthomosaics)
* [ArcGIS Online](/integrations/getting-started/arcgis-online#orthomosaics)
* [QGIS](/integrations/getting-started/qgis#orthomosaics)

If your tool supports **WMTS** or **XYZ**, it supports Spexi.


# Integrating Panorama Markers

* Users can add a GeoJSON file layer to overlay Spexi’s imagery in GIS platforms such as ArcGIS Pro.
* Clicking on a location within the GIS tool opens the corresponding Spexi panoramic image in a new browser tab.
* Spexi imagery can be viewed directly within many GIS environments, eliminating the need to switch between platforms.


