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:
-
Anonymous/Guest JWT — Contact support@skywatch.com for details
-
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:
| Attribute | Type | Description |
|---|---|---|
id | string | Search result ID (required for ordering) |
location | dict | Product footprint as GeoJSON (sometimes only bounding box) |
intersection | dict | Intersection of product with requested AOI |
source | string | Product source (e.g., SkySat, Pleiades-Neo, Sentinel-2) |
product_name | string | Product name |
resolution | float | Product resolution in meters |
start_time | string | Product capture start time |
end_time | string | Product capture end time |
preview_uri | string | Preview image URL |
thumbnail_uri | string | Thumbnail image URL (lower resolution than preview) |
location_coverage_percent | float | Percentage of AOI covered by product |
area_sq_km | float | Intersected area in km² |
cost | float | Price of the product |
result_cloud_cover_percentage | float | Cloud 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 Message | Description |
|---|---|
| Invalid geometry. Please check for self-intersections or malformed polygons | Non-standard geometry (self-intersections, non-closed polygons) |
| Donuts are not supported | User geometry contains holes |
| Only Polygon type is supported. You sent MultiPolygon | GeoJSON must be Polygon type only (no Features/FeatureCollections) |
| API key is invalid or has been deactivated | JWT 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
- Connection closes automatically when search completes on the server side
- Reconnect required for new searches (including re-authentication)
- Handle disconnects gracefully — connection can drop unexpectedly; implement reconnection logic
- Token expiration — JWT tokens expire (typically 7200 seconds for guest tokens); retrieve new token and resend search if expired
- 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
- Browser JS
- Python
- Postman
<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>
import json, websocket
def on_open(ws):
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":"2024-12-01",
"end_date":"2025-01-31",
"coverage":30,
"resolution":["high","very_high"]
},
"JWT_TOKEN":"Bearer {{JWT}}"
}
ws.send(json.dumps(payload))
def on_message(ws, message):
msg = json.loads(message)
if msg.get("message") == "search_results":
results = json.loads(msg["data"])
print("Results:", results[:1])
elif msg.get("message") == "progress_bar_update":
print("Providers total:", msg["data"]["providers"])
elif msg.get("message") == "error":
print("Error:", msg["data"]["errors"])
ws = websocket.WebSocketApp("wss://d3so7ozptr7ad5.cloudfront.net/prod",
on_open=on_open, on_message=on_message)
ws.run_forever()
- In Postman, create New > WebSocket Request
- Paste the WebSocket URL:
wss://d3so7ozptr7ad5.cloudfront.net/prod - Click Connect
- Send the JSON connect payload with your search parameters and JWT token