Skip to main content

Overview

This guide helps you migrate from the legacy AVERT Imagery API (v1) to the new unified API v2.0.0. The migration involves updating endpoints, parameter names, and response handling.
API v1 will continue to work but is no longer actively maintained. We strongly recommend migrating to v2 for better features and ongoing support.

Why Migrate?

Unified API

Single endpoint replaces multiple endpoints

Better Filtering

New atmospheric and temporal filters

Smart Downloads

Get estimates before downloading

Improved Pagination

Comprehensive pagination metadata

Breaking Changes Summary

Changev1v2
Endpoint/api/imagery/infrared/query
/api/imagery/visible/query
/api/imagery/q
Image typeURL path?imageType=infrared|visible
Date paramssearch_from, search_todatefrom, dateto
Date formatISO 8601 (2022-10-01T00:00)Compact (yyyymmddhhmmss)
ResponseArray [{...}, {...}]Object with pagination {results: [...], pagination: {...}}
Download limitFixed 100 imagesConfigurable up to 200

Migration Steps

Step 1: Update Endpoint URLs

v1: Separate endpoints
# Infrared images
https://avert-legacy.ldeo.columbia.edu/api/imagery/infrared/query

# Visible images
https://avert-legacy.ldeo.columbia.edu/api/imagery/visible/query
v2: Single unified endpoint
# Infrared images
https://avert.ldeo.columbia.edu/api/imagery/q?imageType=infrared

# Visible images
https://avert.ldeo.columbia.edu/api/imagery/q?imageType=visible
# Separate endpoints for each image type
infrared_url = "https://avert-legacy.ldeo.columbia.edu/api/imagery/infrared/query"
visible_url = "https://avert-legacy.ldeo.columbia.edu/api/imagery/visible/query"

infrared_images = requests.get(infrared_url, params=params).json()
visible_images = requests.get(visible_url, params=params).json()

Step 2: Update Parameter Names

Date range parameters have new names and format:
v1 Parameterv2 ParameterFormat Change
search_fromdatefromISO 8601 → yyyymmddhhmmss
search_todatetoISO 8601 → yyyymmddhhmmss
params = {
    'site': 'CLNE',
    'vnum': 311240,
    'search_from': '2022-10-01T00:00',
    'search_to': '2022-10-02T00:00'
}
Helper function for date conversion:
from datetime import datetime

def convert_to_v2_date(iso_date_str):
    """Convert ISO 8601 date to v2 format"""
    # Parse ISO 8601 format (e.g., "2022-10-01T00:00")
    dt = datetime.fromisoformat(iso_date_str)
    # Return v2 format (e.g., "20221001000000")
    return dt.strftime('%Y%m%d%H%M%S')

# Usage
v1_date = '2022-10-01T00:00'
v2_date = convert_to_v2_date(v1_date)
print(v2_date)  # '20221001000000'

Step 3: Update Response Handling

v1: Returns array directly
[
  {
    "image_id": "...",
    "image_url": "...",
    ...
  },
  ...
]
v2: Returns structured object
{
  "results": [
    {
      "image_id": "...",
      "image_url": "...",
      ...
    },
    ...
  ],
  "pagination": {
    "page": 1,
    "limit": 100,
    "total_count": 1500,
    "has_next": true,
    ...
  },
  "query": {...}
}
response = requests.get(url, params=params)
images = response.json()  # Direct array

# Iterate images
for img in images:
    print(img['image_url'])
const response = await fetch(url);
const images = await response.json();  // Direct array

// Iterate images
images.forEach(img => {
  console.log(img.image_url);
});

Step 4: Update Download Logic

v1: Fixed 100-image limit
# v1: Downloads max 100 images
response = requests.get(url, params={'download': True})
v2: Estimate first, then download
# v2: Get estimate first
estimate_response = requests.get(url, params={**params, 'download': 'estimate'})
estimate = estimate_response.json()

print(f"Will download {estimate['total_images']} images ({estimate['estimated_size_mb']} MB)")

# Then download if confirmed
if user_confirms:
    download_response = requests.get(url, params={**params, 'download': 'true'})
    with open('images.zip', 'wb') as f:
        f.write(download_response.content)
def download_images_v2(params):
    """Download images with v2 API (with estimate)"""
    base_url = 'https://avert.ldeo.columbia.edu/api/imagery/q'
    
    # Step 1: Get estimate
    estimate_params = {**params, 'download': 'estimate'}
    estimate_response = requests.get(base_url, params=estimate_params)
    estimate = estimate_response.json()
    
    total = estimate['total_images']
    size_mb = estimate['estimated_size_mb']
    time_sec = estimate['estimated_time_seconds']
    
    # Step 2: Show estimate and confirm
    print(f"Download estimate:")
    print(f"  - Images: {total}")
    print(f"  - Size: {size_mb} MB")
    print(f"  - Time: {time_sec} seconds")
    
    if estimate.get('warning'):
        print(f"  - Warning: {estimate['suggestion']}")
    
    confirm = input("Proceed with download? (y/n): ")
    
    if confirm.lower() == 'y':
        # Step 3: Download
        print(f"Downloading {total} images...")
        download_params = {**params, 'download': 'true'}
        download_response = requests.get(base_url, params=download_params)
        
        with open('avert_images.zip', 'wb') as f:
            f.write(download_response.content)
        
        print(f"✓ Downloaded to avert_images.zip")
    else:
        print("Download cancelled")

# Usage
params = {
    'imageType': 'infrared',
    'site': 'CLNE',
    'datefrom': '20251101000000',
    'dateto': '20251130235959',
    'freq': 'hourly'  # NEW: Use temporal sampling
}
download_images_v2(params)

New Features in v2

1. Atmospheric Condition Filters

v2 adds new filters for fog, clouds, and day/night:
params = {
    'imageType': 'infrared',
    'site': 'CLNE',
    'is_night': False,        # NEW: Daytime only
    'has_fog': False,          # NEW: No fog
    'has_clouds': False,       # NEW: No clouds
    'limit': 50
}

2. Temporal Sampling (freq)

Dramatically reduce dataset size while maintaining temporal coverage:
# Get one image per hour (60x data reduction)
params = {
    'site': 'VPMI',
    'freq': 'hourly',          # NEW: Temporal sampling
    'datefrom': '20251101000000',
    'dateto': '20251130235959'
}

# Get daily summaries (1440x data reduction)
params = {
    'site': 'VPMI',
    'freq': 'daily',           # NEW: One per day
    'datefrom': '20250101000000',
    'dateto': '20251231235959'
}
freq options:
  • all - All captured images (default)
  • minutely - One per minute
  • hourly - One per hour
  • daily - One per day

3. Enhanced Pagination

v2 provides comprehensive pagination metadata:
data = requests.get(url, params=params).json()

pagination = data['pagination']
print(f"Page {pagination['page']} of {pagination['total_pages']}")
print(f"Showing {pagination['count']} of {pagination['total_count']} results")

if pagination['has_next']:
    # Load next page
    next_page_params = {**params, 'page': pagination['next_page']}

4. Query Echo

v2 includes your query parameters in the response for debugging:
data = requests.get(url, params=params).json()

print("Your query:")
print(data['query'])
# Shows exactly what filters were applied

Complete Migration Example

Here’s a complete before/after example:
import requests

# v1 API
url = "https://avert-legacy.ldeo.columbia.edu/api/imagery/infrared/query"
params = {
    'site': 'CLNE',
    'vnum': 311240,
    'search_from': '2022-10-01T00:00',
    'search_to': '2022-10-31T23:59',
    'limit': 100
}

response = requests.get(url, params=params)
images = response.json()  # Direct array

print(f"Found {len(images)} images")
for img in images[:5]:
    print(f"  - {img['image_id']}")

# Download
download_params = {**params, 'download': True}
download_response = requests.get(url, params=download_params)
with open('images.zip', 'wb') as f:
    f.write(download_response.content)

Migration Checklist

Use this checklist to ensure complete migration:
1

Update endpoint URLs

  • Replace /api/imagery/infrared/query with /api/imagery/q?imageType=infrared
  • Replace /api/imagery/visible/query with /api/imagery/q?imageType=visible
  • Update base URL to https://avert.ldeo.columbia.edu
2

Update parameters

  • Replace search_from with datefrom
  • Replace search_to with dateto
  • Convert date format from ISO 8601 to yyyymmddhhmmss
  • Add imageType parameter
3

Update response handling

  • Extract data['results'] instead of using response directly
  • Access pagination via data['pagination']
  • Update loops to iterate over data['results']
4

Update download logic

  • Add download=estimate call before downloading
  • Show estimate to users
  • Change download=True to download='true' (string)
5

Add new features (optional)

  • Add atmospheric filters (has_fog, has_clouds, is_night)
  • Add temporal sampling (freq parameter)
  • Implement pagination navigation
  • Add rate limit handling with retry logic
6

Test thoroughly

  • Test basic queries
  • Test with filters
  • Test pagination
  • Test downloads with estimates
  • Test error handling

Common Migration Issues

Issue: Trying to access .results on v1 responseSolution: Update response handling
# Wrong (v1 style with v2 API)
images = response.json()
for img in images:  # Error!
    ...

# Correct (v2 style)
data = response.json()
images = data['results']
for img in images:
    ...
Issue: Using ISO 8601 date format with v2 APISolution: Convert to yyyymmddhhmmss format
# Wrong
'search_from': '2022-10-01T00:00'

# Correct
'datefrom': '20221001000000'
Issue: Forgot to add imageType parameterSolution: Explicitly specify image type
# Wrong - might get wrong image type
params = {'site': 'CLNE'}

# Correct
params = {'site': 'CLNE', 'imageType': 'infrared'}
Issue: Using wrong value for download parameterSolution: Use string ‘true’ not boolean True
# Wrong
params = {'download': True}  # Boolean

# Correct
params = {'download': 'true'}  # String

Testing Your Migration

Test your migrated code with these queries:

Test 1: Basic Query

# Should return structured response with results array
params = {
    'imageType': 'infrared',
    'site': 'CLNE',
    'limit': 5
}
data = requests.get('https://avert.ldeo.columbia.edu/api/imagery/q', params=params).json()

assert 'results' in data
assert 'pagination' in data
assert len(data['results']) <= 5
print("✓ Test 1 passed")

Test 2: Date Filtering

# Should accept new date format
params = {
    'imageType': 'infrared',
    'site': 'CLNE',
    'datefrom': '20251101000000',
    'dateto': '20251101235959',
    'limit': 10
}
data = requests.get('https://avert.ldeo.columbia.edu/api/imagery/q', params=params).json()

assert data['query']['datefrom'] == '20251101000000'
print("✓ Test 2 passed")

Test 3: Download Estimate

# Should return estimate without downloading
params = {
    'imageType': 'infrared',
    'site': 'CLNE',
    'limit': 10,
    'download': 'estimate'
}
estimate = requests.get('https://avert.ldeo.columbia.edu/api/imagery/q', params=params).json()

assert 'total_images' in estimate
assert 'estimated_size_mb' in estimate
print(f"✓ Test 3 passed - Would download {estimate['total_images']} images")

Getting Help