Skip to main content

Archive Search — WebSocket API

Use a WebSocket to stream archive search results and progress updates in real time.

Endpoint

  • Production: wss://d3so7ozptr7ad5.cloudfront.net/prod

Authentication

There are two ways to authenticate:

  1. Anonymous/Guest JWT — Contact support@skywatch.com for details

  2. Login JWT — If user is authenticated with SkyWatch

Include the token in your connect message as JWT_TOKEN: "Bearer <token>".

Connect & Search Payload

{
"action": "connect",
"config": {
"location": {
"type": "Polygon",
"coordinates": [
[
[-73.95950959050467, 40.803232950312264],
[-73.98518739769608, 40.768306075577726],
[-73.97154148035514, 40.761912689996564],
[-73.94657494129676, 40.79741232310445],
[-73.95950959050467, 40.803232950312264]
]
]
},
"start_date": "YYYY-MM-DD",
"end_date": "YYYY-MM-DD",
"coverage": 30,
"resolution": ["low","medium","high","very_high"],
"sensor_type": ["optical","aerial","sar","elevation","basemap"],
"purchase_options": {
"band_options": ["4-band"],
"dem_option": ["DSM"],
"look_option": ["1 Look"]
},
"resolution_high": 0.01,
"resolution_low": 30,
"sources": ["SkySat"],
"providers": ["Airbus"]
},
"JWT_TOKEN": "Bearer <token>"
}

Important Constraints:

  • Only Polygon GeoJSON type is supported (no MultiPolygon, LineString, Feature, or FeatureCollection)
  • Z coordinates are accepted but ignored
  • Hard limit: 2500 coordinates per geometry
  • Validate coordinate count before sending to avoid disconnection

Messages

The WebSocket server sends three types of messages:

1. search_results — Contains search results from providers

Results are in the data attribute as a JSON string that must be parsed. Each result includes:

AttributeTypeDescription
idstringSearch result ID (required for ordering)
locationdictProduct footprint as GeoJSON (sometimes only bounding box)
intersectiondictIntersection of product with requested AOI
sourcestringProduct source (e.g., SkySat, Pleiades-Neo, Sentinel-2)
product_namestringProduct name
resolutionfloatProduct resolution in meters
start_timestringProduct capture start time
end_timestringProduct capture end time
preview_uristringPreview image URL
thumbnail_uristringThumbnail image URL (lower resolution than preview)
location_coverage_percentfloatPercentage of AOI covered by product
area_sq_kmfloatIntersected area in km²
costfloatPrice of the product
result_cloud_cover_percentagefloatCloud coverage percentage on product

2. progress_bar_update — Tracks search progress

Format: { "message": "progress_bar_update", "data": { "providers": <total_count> } }

Track completed providers with a client-side counter. The providers value is the total number of providers to expect.

3. error — Validation or authentication errors

Format: { "message": "error", "data": { "errors": [ { "message": "..." } ] } }

Connection closes automatically after an error. Common errors:

Error MessageDescription
Invalid geometry. Please check for self-intersections or malformed polygonsNon-standard geometry (self-intersections, non-closed polygons)
Donuts are not supportedUser geometry contains holes
Only Polygon type is supported. You sent MultiPolygonGeoJSON must be Polygon type only (no Features/FeatureCollections)
API key is invalid or has been deactivatedJWT token is invalid, deactivated, or expired

Limits

  • Payload size ≤ 128 KB (practically ~2500 coordinates depending on JWT token size)
  • Block oversized AOIs in your UI before sending to prevent connection drops

Connection Lifecycle

  1. Connection closes automatically when search completes on the server side
  2. Reconnect required for new searches (including re-authentication)
  3. Handle disconnects gracefully — connection can drop unexpectedly; implement reconnection logic
  4. Token expiration — JWT tokens expire (typically 7200 seconds for guest tokens); retrieve new token and resend search if expired
  5. Thumbnail loading — Preview and thumbnail images are generated asynchronously and may not be available immediately. Implement retry logic when loading images (they typically appear within a few seconds after results are delivered)

Examples

<script>
const url = "wss://d3so7ozptr7ad5.cloudfront.net/prod";
const ws = new WebSocket(url);
ws.onopen = () => {
ws.send(JSON.stringify({
action: "connect",
config: {
location: {
type: "Polygon",
coordinates: [
[
[-73.95950959050467, 40.803232950312264],
[-73.98518739769608, 40.768306075577726],
[-73.97154148035514, 40.761912689996564],
[-73.94657494129676, 40.79741232310445],
[-73.95950959050467, 40.803232950312264]
]
]
},
start_date: "2024-12-01",
end_date: "2025-01-31",
coverage: 30,
resolution: ["high","very_high"]
},
JWT_TOKEN: "Bearer {{JWT}}"
}));
};
ws.onmessage = (evt) => {
const msg = JSON.parse(evt.data);
if (msg.message === "search_results") {
const results = JSON.parse(msg.data);
console.log("results", results);
}
if (msg.message === "progress_bar_update") {
console.log("providers total:", msg.data.providers);
}
if (msg.message === "error") {
console.error(msg.data.errors);
}
};
</script>