Detect and Classify

Learn how to add Detect and Classify (D&C) to your tasking workflow. D&C applies automated detection models to your SAR imagery and delivers structured results identifying objects of interest within the scene.

What is Detect and Classify?

When you task a satellite image through the ICEYE API, you receive SAR data products (GRD, SLC, etc.). D&C goes a step further: it runs detection models on the acquired imagery and returns GeoJSON files containing the locations and classifications of detected objects.

Available detection models

ICEYE currently offers three derivative product types:

Derivative product type Description

DC_AIRCRAFT

Detects and classifies aircraft

DC_VESSELS

Detects and classifies vessels

DC_VEHICLES

Detects and classifies ground vehicles (military and civilian, including trucks, tanks, cars, and armored vehicles)

You can request one or more of these in a single task.

How it works

D&C is not a separate API. It extends the existing tasking workflow with two additions:

  1. You include a derivativeProductTypes parameter when creating a task

  2. After the task is fulfilled, you retrieve the detection results from a dedicated derivatives endpoint

The rest of the workflow (authentication, task creation, monitoring) stays the same.

Prerequisites

Before using D&C, make sure you have:

  • A contract with D&C enabled — derivative product types must be enabled in your contract. Contact your ICEYE representative.

  • Valid authentication credentials — see Authentication.

  • A supported imaging mode — derivatives are only available for high-resolution spotlight modes: SPOTLIGHT, SPOTLIGHT_FINE, SPOTLIGHT_FINE_1L, SPOTLIGHT_EXTENDED_DWELL, and SPOTLIGHT_EXTENDED_DWELL_FINE. Other modes (e.g., STRIPMAP, SCAN) are not supported.

Part 1: Creating a task with D&C

Creating a D&C task is identical to creating a regular task, with one addition: the derivativeProductTypes field in the request body.

The derivativeProductTypes parameter

This parameter accepts an array of derivative product type strings. Add it alongside your usual task parameters:

"derivativeProductTypes": ["DC_AIRCRAFT", "DC_VESSELS"]
D&C processing uses the GRD image as input. You must explicitly include GRD in the productTypes parameter of your task request. It is not sufficient for GRD to be a default product in your contract. For the full list of validation rules and error codes, see Create task — Derivative product types.

Full request example

  • cURL

  • Python

  • JavaScript

curl --location "${API_BASE_URL}/api/tasking/v2/tasks" \
  --header "Content-Type: application/json" \
  --header "Accept: application/json, application/problem+json" \
  --header "Authorization: Bearer ${API_ACCESS_TOKEN}" \
  --data '{
    "acquisitionWindow": {
      "start": "2026-03-01T00:00:00Z",
      "end": "2026-03-02T00:00:00Z"
    },
    "contractID": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
    "imagingMode": "SPOTLIGHT",
    "pointOfInterest": {
      "lat": 60.1699,
      "lon": 24.9384
    },
    "productTypes": ["GRD"],
    "derivativeProductTypes": ["DC_AIRCRAFT", "DC_VESSELS"]
  }'
import requests

task_payload = {
    "acquisitionWindow": {
        "start": "2026-03-01T00:00:00Z",
        "end": "2026-03-02T00:00:00Z"
    },
    "contractID": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
    "imagingMode": "SPOTLIGHT",
    "pointOfInterest": {
        "lat": 60.1699,
        "lon": 24.9384
    },
    "productTypes": ["GRD"],
    "derivativeProductTypes": ["DC_AIRCRAFT", "DC_VESSELS"]
}

response = requests.post(
    f"{API_BASE_URL}/api/tasking/v2/tasks",
    headers={
        "Content-Type": "application/json",
        "Accept": "application/json, application/problem+json",
        "Authorization": f"Bearer {access_token}"
    },
    json=task_payload
)

task = response.json()
print(f"Task created: {task['id']}, status: {task['status']}")
const taskPayload = {
  acquisitionWindow: {
    start: "2026-03-01T00:00:00Z",
    end: "2026-03-02T00:00:00Z"
  },
  contractID: "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
  imagingMode: "SPOTLIGHT",
  pointOfInterest: {
    lat: 60.1699,
    lon: 24.9384
  },
  productTypes: ["GRD"],
  derivativeProductTypes: ["DC_AIRCRAFT", "DC_VESSELS"]
};

const response = await fetch(`${API_BASE_URL}/api/tasking/v2/tasks`, {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Accept": "application/json, application/problem+json",
    "Authorization": `Bearer ${accessToken}`
  },
  body: JSON.stringify(taskPayload)
});

const task = await response.json();
console.log(`Task created: ${task.id}, status: ${task.status}`);

Response

On success, you receive a 201 status code. The response confirms which derivative product types were requested:

{
  "id": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
  "pointOfInterest": {
    "lat": 60.1699,
    "lon": 24.9384
  },
  "acquisitionWindow": {
    "start": "2026-03-01T00:00:00Z",
    "end": "2026-03-02T00:00:00Z"
  },
  "createdAt": "2026-02-18T10:00:00Z",
  "updatedAt": "2026-02-18T10:00:00Z",
  "imagingMode": "SPOTLIGHT",
  "contractID": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
  "status": "RECEIVED",
  "exclusivity": "PRIVATE",
  "priority": "COMMERCIAL",
  "sla": "SLA_8H",
  "eula": "STANDARD",
  "incidenceAngle": {
    "min": 20,
    "max": 35
  },
  "lookSide": "ANY",
  "passDirection": "ANY",
  "productTypes": ["GRD"],
  "derivativeProductTypes": ["DC_AIRCRAFT", "DC_VESSELS"]
}

The derivativeProductTypes array in the response mirrors what you requested. If a derivative type is not supported by your contract, the API returns an error.

Part 2: Monitoring the task

D&C processing starts automatically after the task is fulfilled and the SAR products are available. There is nothing different about monitoring a D&C task. Use the same polling approach as any other task.

Polling for status

  • cURL

  • Python

  • JavaScript

curl --location "${API_BASE_URL}/api/tasking/v2/tasks/${taskID}" \
  --header "Accept: application/json, application/problem+json" \
  --header "Authorization: Bearer ${API_ACCESS_TOKEN}"
import time

while True:
    response = requests.get(
        f"{API_BASE_URL}/api/tasking/v2/tasks/{task_id}",
        headers={"Authorization": f"Bearer {access_token}"}
    )
    task = response.json()
    print(f"Status: {task['status']}")

    if task["status"] in ["FULFILLED", "DONE", "FAILED", "REJECTED", "CANCELED"]:
        break

    time.sleep(30)
async function waitForFulfillment(taskId) {
  const terminalStates = ["FULFILLED", "DONE", "FAILED", "REJECTED", "CANCELED"];

  while (true) {
    const response = await fetch(
      `${API_BASE_URL}/api/tasking/v2/tasks/${taskId}`,
      { headers: { "Authorization": `Bearer ${accessToken}` } }
    );
    const task = await response.json();
    console.log(`Status: ${task.status}`);

    if (terminalStates.includes(task.status)) return task;

    await new Promise(resolve => setTimeout(resolve, 30000));
  }
}

Wait for the task status to reach FULFILLED or DONE. Once the SAR products are ready, D&C processing begins in the background. At that point, move on to Part 3 and start polling the derivatives endpoint for results.

Part 3: Retrieving D&C results

Once the task status is FULFILLED or DONE, start polling the derivatives endpoint. D&C processing runs asynchronously after the SAR products are available, so the derivatives may not be ready immediately.

Request

  • cURL

  • Python

  • JavaScript

curl --location "${API_BASE_URL}/api/tasking/v2/tasks/${taskID}/derivatives" \
  --header "Accept: application/json, application/problem+json" \
  --header "Authorization: Bearer ${API_ACCESS_TOKEN}"
response = requests.get(
    f"{API_BASE_URL}/api/tasking/v2/tasks/{task_id}/derivatives",
    headers={"Authorization": f"Bearer {access_token}"}
)

if response.status_code == 200:
    print("All derivatives ready")
elif response.status_code == 206:
    print("Some derivatives still processing")
elif response.status_code == 404:
    print("No derivatives available yet, keep polling")

derivatives = response.json()
for derivative in derivatives["data"]:
    print(f"Type: {derivative['derivativeProductType']}")
    for asset in derivative.get("assets", []):
        print(f"  Download: {asset['href']}")
const response = await fetch(
  `${API_BASE_URL}/api/tasking/v2/tasks/${taskId}/derivatives`,
  { headers: { "Authorization": `Bearer ${accessToken}` } }
);

if (response.status === 200) {
  console.log("All derivatives ready");
} else if (response.status === 206) {
  console.log("Some derivatives still processing");
} else if (response.status === 404) {
  console.log("No derivatives available yet, keep polling");
}

const derivatives = await response.json();
for (const derivative of derivatives.data) {
  console.log(`Type: ${derivative.derivativeProductType}`);
  for (const asset of derivative.assets || []) {
    console.log(`  Download: ${asset.href}`);
  }
}

Understanding the response status codes

The endpoint returns one of three status codes:

200 (All derivatives ready)

All requested derivative products have been processed and are available for download. You can stop polling.

206 (Partial content)

Some derivative products are available, but others are still being processed. Continue polling until you receive a 200.

404 (Not found)

No derivative products are available yet. The GRD product may still be processing, or derivative processing has not started. Keep polling.

Poll the endpoint periodically (for example, every 30 seconds) until you receive a 200 response. For the full list of error responses, see Task derivatives.

Response body

The response contains a data array with one entry per derivative product:

{
  "data": [
    {
      "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "derivativeProductType": "DC_AIRCRAFT",
      "imageReference": "c2ac555e-27ac-4c6a-bf87-717fa81539e3",
      "assets": [
        {
          "type": "geojson",
          "href": "https://XXXXXXXXXXXX.cloudfront.net/XXXX/aircraft-detections.geojson?Expires=..."
        }
      ]
    },
    {
      "id": "7ba92e11-3344-4a8b-9c12-abcdef123456",
      "derivativeProductType": "DC_VESSELS",
      "imageReference": "c2ac555e-27ac-4c6a-bf87-717fa81539e3",
      "assets": [
        {
          "type": "geojson",
          "href": "https://XXXXXXXXXXXX.cloudfront.net/XXXX/vessel-detections.geojson?Expires=..."
        }
      ]
    }
  ]
}

Each derivative entry contains:

  • id — unique identifier for the derivative record

  • derivativeProductType — which detection model produced this result (e.g., DC_AIRCRAFT)

  • imageReference — UUID reference to the source image used for processing

  • imageId — alternative string identifier for the source image (optional, may be omitted)

  • assets — array of downloadable files with signed URLs

Download URLs are signed and expire after 1 hour. Do not store the URLs for long-term access. Request fresh URLs by calling the derivatives endpoint again.

Part 4: Downloading D&C results

The assets array contains signed URLs pointing to GeoJSON files. Download them like any other file:

  • cURL

  • Python

  • JavaScript

curl --location "${DERIVATIVE_ASSET_URL}" \
  --output aircraft-detections.geojson
for derivative in derivatives["data"]:
    for asset in derivative.get("assets", []):
        download_response = requests.get(asset["href"])
        filename = f"{derivative['derivativeProductType'].lower()}.geojson"
        with open(filename, "wb") as f:
            f.write(download_response.content)
        print(f"Downloaded {filename}")
for (const derivative of derivatives.data) {
  for (const asset of derivative.assets || []) {
    const downloadResponse = await fetch(asset.href);
    const content = await downloadResponse.text();
    const filename = `${derivative.derivativeProductType.toLowerCase()}.geojson`;
    // Save or process the GeoJSON content
    console.log(`Downloaded ${filename}: ${content.length} bytes`);
  }
}

Part 5: Understanding the GeoJSON results

Each D&C result is a standard GeoJSON FeatureCollection with two top-level fields:

{
  "type": "FeatureCollection",
  "properties": { ... },
  "features": [ ... ]
}
  • properties — metadata about the detection model (model type, version, and description)

  • features — array of individual detections

Detection features

Each feature in the features array represents a single detected object. The geometry is a Polygon describing the oriented bounding box of the detected object. The properties contain the classification details.

{
  "type": "Feature",
  "geometry": {
    "type": "Polygon",
    "coordinates": [
      [
        [144.908385, -37.844419],
        [144.910070, -37.846546],
        [144.909335, -37.846911],
        [144.907651, -37.844785],
        [144.908385, -37.844419]
      ]
    ]
  },
  "properties": {
    "title": "Container Ship",
    "supercategory": "Ship",
    "category": "Civil",
    "subcategory": "Cargo",
    "type": "Container Ship",
    "class_id": "containership",
    "length": 260.0,
    "score": 0.998,
    "det_score": 0.772,
    "alt_title": "Unknown/other type",
    "alt_class_id": "unknown",
    "alt_score": 0.0001
  }
}

Common feature properties

All detection models return the following properties for each detected object:

Property Description

title

Human-readable name of the detected object (e.g., "Container Ship", "Attack/Fighter/Fighter-bomber", "Transport")

supercategory

Top-level grouping (e.g., "Ship", "Aircraft", "Vehicle")

category

Broad classification (e.g., "Civil", "Military", "Airplane", "Transport")

subcategory

More specific grouping (e.g., "Cargo", "Attack/Fighter/Fighter-bomber", "Missile Launcher")

class_id

Machine-readable identifier for the classification (e.g., containership, affb, transport)

score

Classification confidence score (0 to 1). Higher values indicate greater confidence in the classification

alt_title

Alternative classification if the model considered a second possibility

alt_supercategory

Alternative top-level grouping

alt_category

Alternative broad classification

alt_subcategory

Alternative specific grouping

alt_class_id

Machine-readable identifier for the alternative classification

alt_score

Confidence score for the alternative classification

Model-specific properties

Each detection model may include additional properties specific to the type of object being detected:

Vessels (DC_VESSELS):

  • type / alt_type — detailed vessel type (e.g., "Container Ship", "Motor Hopper")

  • length — estimated length of the vessel in meters

  • det_score — detection confidence score (0 to 1), indicating how confident the model is that an object exists at this location

Aircraft (DC_AIRCRAFT):

  • fighter_class / alt_fighter_class — detailed fighter subclass, available for the "Attack/Fighter/Fighter-bomber" category (recommended for Dwell modes)

  • fighter_score / alt_fighter_score — confidence scores for the fighter subclass classification

Vehicles (DC_VEHICLES):

  • det_score — detection confidence score (0 to 1), indicating how confident the model is that an object exists at this location

Additional metadata fields may be present depending on the derivative product type.

Geometry

The detection geometry is always a Polygon with five coordinate pairs (a closed rectangle). This represents an oriented bounding box around the detected object, aligned with the object’s orientation rather than with the cardinal directions.

The coordinates use the WGS 84 (EPSG:4326) coordinate reference system, with longitude first and latitude second, following the GeoJSON specification.

Complete workflow summary

Here is the end-to-end D&C workflow:

1. Create task (with derivativeProductTypes and GRD in productTypes)
       |
       v
2. Poll task status (GET /tasks/{id}) until FULFILLED or DONE
       |
       v
3. Download SAR products (GET /tasks/{id}/products)
       |
       v
4. Poll derivatives (GET /tasks/{id}/derivatives)
       |
       |-- 404: not available yet, keep polling
       |-- 206: partial results, keep polling
       |
       '-- 200: all results ready, stop polling
              |
              v
       Download GeoJSON files from asset URLs
API call Frequency Trigger Stop condition

POST Create Task

Once

User requests D&C

After task created

GET Task Status

Periodic

After task created

Status is FULFILLED or DONE

GET Task Products

Once

Status is FULFILLED or DONE

After download

GET Task Derivatives

Periodic (until 200)

After task is FULFILLED or DONE

Response status is 200

If the derivatives endpoint returns 206, wait and retry. D&C processing typically completes shortly after the SAR products are available, but processing time can vary depending on image size and the number of requested derivative types.