{
  "info": {
    "_postman_id": "b6e7c1a4-9f31-4d2a-9c52-geog-ai-spec",
    "name": "geog.ai Spatial Intelligence API",
    "description": "geog.ai turns coordinates into spatial decisions. Every API call resolves location into\nenriched context — terrain, jurisdiction, neighbors, atmospheric conditions — and optionally\nruns physics-based propagation models to answer \"what happens next?\"\n\n**Base URL:** `https://api.geog.ai/v1`\n\n**Response modes:**\n- **Synchronous** — context queries and RF/graph lookups return immediately (typically <200 ms)\n- **Async jobs** — propagation simulations (`/simulate/*`) return a job ID; results delivered\n  via webhook or polled via `GET /jobs/{job_id}`\n- **Streaming** — real-time plume tracking via SSE (`/simulate/plume/stream`, Site Calibration plans only)\n\nEvery response is wrapped in a standard envelope that includes a confidence score (0.0–1.0),\nmodel version, calibration age, and data provenance.\n\n---\n\n**Setup:**\n1. Import the matching environment file `geog-ai.postman_environment.json`.\n2. Set `api_key` to your `geog_test_sk_…` or `geog_live_sk_…` token.\n3. The `base_url` defaults to `https://api.geog.ai/v1`.\n\nRegenerate this collection from `openapi.yaml` with `python3 docs/postman/generate_postman.py`.",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
    "_exporter_id": "geog-ai-openapi-generator"
  },
  "item": [
    {
      "name": "Context API",
      "description": "Resolve spatial state for registered devices and arbitrary coordinates.",
      "item": [
        {
          "name": "Resolve SpatialState for a registered device",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/context?device_id=sensor_h2s_023",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "context"
              ],
              "query": [
                {
                  "key": "device_id",
                  "value": "sensor_h2s_023",
                  "description": "Registered device identifier.",
                  "disabled": false
                },
                {
                  "key": "include",
                  "value": "terrain,jurisdiction,wind",
                  "description": "Comma-separated context fields to include. Default: all. Options: terrain, jurisdiction, wind, nearby, assets, calibration.",
                  "disabled": true
                },
                {
                  "key": "max_age_s",
                  "value": "300",
                  "description": "Maximum acceptable state age in seconds. Older states trigger fresh enrichment.",
                  "disabled": true
                }
              ]
            },
            "description": "Returns the full `SpatialState` for a registered device — terrain, jurisdiction, wind vector,\nnearby entities, atmospheric stability class, and asset proximity. Enrichment runs at ingest\ntime; this call returns the pre-computed state.\n\n**Pricing:** $0.001 / call\n\n`GET /context`\n\n_operationId:_ `getContext`",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{api_key}}",
                  "type": "string"
                }
              ]
            }
          },
          "response": [
            {
              "name": "200 SpatialState resolved successfully.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{base_url}}/context?device_id=sensor_h2s_023",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "context"
                  ],
                  "query": [
                    {
                      "key": "device_id",
                      "value": "sensor_h2s_023",
                      "description": "Registered device identifier.",
                      "disabled": false
                    },
                    {
                      "key": "include",
                      "value": "terrain,jurisdiction,wind",
                      "description": "Comma-separated context fields to include. Default: all. Options: terrain, jurisdiction, wind, nearby, assets, calibration.",
                      "disabled": true
                    },
                    {
                      "key": "max_age_s",
                      "value": "300",
                      "description": "Maximum acceptable state age in seconds. Older states trigger fresh enrichment.",
                      "disabled": true
                    }
                  ]
                },
                "description": "Returns the full `SpatialState` for a registered device — terrain, jurisdiction, wind vector,\nnearby entities, atmospheric stability class, and asset proximity. Enrichment runs at ingest\ntime; this call returns the pre-computed state.\n\n**Pricing:** $0.001 / call\n\n`GET /context`\n\n_operationId:_ `getContext`",
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{api_key}}",
                      "type": "string"
                    }
                  ]
                }
              },
              "status": "SpatialState resolved successfully.",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"ok\": true,\n  \"result\": {\n    \"entity_id\": \"sensor_h2s_023\",\n    \"location\": {\n      \"lat\": 31.9686,\n      \"lon\": -99.9018,\n      \"alt_m\": 547.2,\n      \"h3_index\": \"8944c0ba857ffff\",\n      \"indoor\": null\n    },\n    \"time\": \"2026-04-21T03:14:22Z\",\n    \"context\": {\n      \"wind_vector\": {\n        \"speed_ms\": 8.2,\n        \"bearing_deg\": 312\n      },\n      \"terrain\": {\n        \"elevation_m\": 547.2,\n        \"slope_deg\": 3.1,\n        \"aspect_deg\": 180\n      },\n      \"atmospheric_stability\": \"D\",\n      \"nearby_entities\": [\n        {\n          \"id\": \"sensor_h2s_021\",\n          \"distance_m\": 184.2,\n          \"bearing_deg\": 271,\n          \"reading_ppm\": 0.4\n        },\n        {\n          \"id\": \"sensor_h2s_024\",\n          \"distance_m\": 412.7,\n          \"bearing_deg\": 88,\n          \"reading_ppm\": 0.1\n        }\n      ],\n      \"jurisdiction\": {\n        \"authority\": \"TCEQ\",\n        \"permit_id\": \"PSDTX1234\",\n        \"limit_ppm\": 10\n      },\n      \"asset_proximity\": [\n        {\n          \"asset_id\": \"wellhead_07\",\n          \"distance_m\": 96.1,\n          \"type\": \"wellhead\"\n        }\n      ]\n    }\n  },\n  \"meta\": {\n    \"confidence\": 0.93,\n    \"model_version\": \"plume-v4.1.2\",\n    \"calibration_age_days\": 47,\n    \"site_calibrated\": true,\n    \"provenance\": [\n      \"terrain:USGS-3DEP-1m\",\n      \"met:NOAA-HRRR-2026-04-21T03Z\",\n      \"jurisdiction:TCEQ-2025-Q4\"\n    ],\n    \"request_id\": \"req_01hx29sknd4bqyt8r\",\n    \"latency_ms\": 87\n  }\n}"
            }
          ]
        },
        {
          "name": "Batch context resolution (up to 500 devices)",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/context/batch?device_ids=[\"sensor_h2s_023\",\"sensor_h2s_024\",\"drone_01\"]",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "context",
                "batch"
              ],
              "query": [
                {
                  "key": "device_ids",
                  "value": "[\"sensor_h2s_023\",\"sensor_h2s_024\",\"drone_01\"]",
                  "description": "JSON-encoded array of device IDs. Max 500 per request.",
                  "disabled": false
                },
                {
                  "key": "include",
                  "value": "",
                  "description": "Comma-separated context fields to include (see /context).",
                  "disabled": true
                }
              ]
            },
            "description": "Resolves SpatialState for up to 500 devices in a single request. Partial failures\nare represented with `null` result entries and an error sub-object.\n\n**Pricing:** $0.001 / device\n\n`GET /context/batch`\n\n_operationId:_ `getContextBatch`",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{api_key}}",
                  "type": "string"
                }
              ]
            }
          },
          "response": [
            {
              "name": "200 Batch context resolved.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{base_url}}/context/batch?device_ids=[\"sensor_h2s_023\",\"sensor_h2s_024\",\"drone_01\"]",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "context",
                    "batch"
                  ],
                  "query": [
                    {
                      "key": "device_ids",
                      "value": "[\"sensor_h2s_023\",\"sensor_h2s_024\",\"drone_01\"]",
                      "description": "JSON-encoded array of device IDs. Max 500 per request.",
                      "disabled": false
                    },
                    {
                      "key": "include",
                      "value": "",
                      "description": "Comma-separated context fields to include (see /context).",
                      "disabled": true
                    }
                  ]
                },
                "description": "Resolves SpatialState for up to 500 devices in a single request. Partial failures\nare represented with `null` result entries and an error sub-object.\n\n**Pricing:** $0.001 / device\n\n`GET /context/batch`\n\n_operationId:_ `getContextBatch`",
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{api_key}}",
                      "type": "string"
                    }
                  ]
                }
              },
              "status": "Batch context resolved.",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"ok\": true,\n  \"result\": {\n    \"count\": 3,\n    \"succeeded\": 3,\n    \"failed\": 0,\n    \"items\": [\n      {\n        \"entity_id\": \"sensor_h2s_023\",\n        \"location\": {\n          \"lat\": 31.9686,\n          \"lon\": -99.9018,\n          \"alt_m\": 547.2,\n          \"h3_index\": \"8944c0ba857ffff\",\n          \"indoor\": null\n        },\n        \"time\": \"2026-04-21T03:14:22Z\",\n        \"context\": {\n          \"wind_vector\": {\n            \"speed_ms\": 8.2,\n            \"bearing_deg\": 312\n          },\n          \"atmospheric_stability\": \"D\"\n        }\n      },\n      {\n        \"entity_id\": \"sensor_h2s_024\",\n        \"location\": {\n          \"lat\": 31.969,\n          \"lon\": -99.9012,\n          \"alt_m\": 548.0,\n          \"h3_index\": \"8944c0ba853ffff\",\n          \"indoor\": null\n        },\n        \"time\": \"2026-04-21T03:14:22Z\",\n        \"context\": {\n          \"wind_vector\": {\n            \"speed_ms\": 8.2,\n            \"bearing_deg\": 312\n          },\n          \"atmospheric_stability\": \"D\"\n        }\n      },\n      {\n        \"entity_id\": \"drone_01\",\n        \"location\": {\n          \"lat\": 31.9701,\n          \"lon\": -99.9024,\n          \"alt_m\": 612.5,\n          \"h3_index\": \"8944c0ba84bffff\",\n          \"indoor\": null\n        },\n        \"time\": \"2026-04-21T03:14:22Z\",\n        \"context\": {\n          \"wind_vector\": {\n            \"speed_ms\": 8.2,\n            \"bearing_deg\": 312\n          }\n        }\n      }\n    ]\n  },\n  \"meta\": {\n    \"confidence\": 0.92,\n    \"model_version\": \"plume-v4.1.2\",\n    \"calibration_age_days\": 47,\n    \"site_calibrated\": true,\n    \"provenance\": [\n      \"terrain:USGS-3DEP-1m\",\n      \"met:NOAA-HRRR-2026-04-21T03Z\"\n    ],\n    \"request_id\": \"req_01hx29sknd4bqyt8r\",\n    \"latency_ms\": 142\n  }\n}"
            }
          ]
        },
        {
          "name": "Proximity search",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/nearby?lat=31.96&lon=-99.9&radius_m=500",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "nearby"
              ],
              "query": [
                {
                  "key": "lat",
                  "value": "31.96",
                  "description": "WGS84 latitude of center point.",
                  "disabled": false
                },
                {
                  "key": "lon",
                  "value": "-99.9",
                  "description": "WGS84 longitude of center point.",
                  "disabled": false
                },
                {
                  "key": "radius_m",
                  "value": "500",
                  "description": "Search radius in meters. Max 50,000 m.",
                  "disabled": false
                },
                {
                  "key": "type",
                  "value": "gas_sensor",
                  "description": "Filter by entity type. Built-in values: gas_sensor, water_sensor, rf_node, asset, personnel, drone. Any registered custom type is also accepted.",
                  "disabled": true
                },
                {
                  "key": "limit",
                  "value": "50",
                  "description": "Maximum results to return. Default 50, max 500.",
                  "disabled": true
                }
              ]
            },
            "description": "Returns all registered entities within a given radius of a coordinate, optionally\nfiltered by type. Results are ordered by distance.\n\n**Pricing:** $0.001 / call\n\n`GET /nearby`\n\n_operationId:_ `getNearby`",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{api_key}}",
                  "type": "string"
                }
              ]
            }
          },
          "response": [
            {
              "name": "200 Nearby entities returned.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{base_url}}/nearby?lat=31.96&lon=-99.9&radius_m=500",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "nearby"
                  ],
                  "query": [
                    {
                      "key": "lat",
                      "value": "31.96",
                      "description": "WGS84 latitude of center point.",
                      "disabled": false
                    },
                    {
                      "key": "lon",
                      "value": "-99.9",
                      "description": "WGS84 longitude of center point.",
                      "disabled": false
                    },
                    {
                      "key": "radius_m",
                      "value": "500",
                      "description": "Search radius in meters. Max 50,000 m.",
                      "disabled": false
                    },
                    {
                      "key": "type",
                      "value": "gas_sensor",
                      "description": "Filter by entity type. Built-in values: gas_sensor, water_sensor, rf_node, asset, personnel, drone. Any registered custom type is also accepted.",
                      "disabled": true
                    },
                    {
                      "key": "limit",
                      "value": "50",
                      "description": "Maximum results to return. Default 50, max 500.",
                      "disabled": true
                    }
                  ]
                },
                "description": "Returns all registered entities within a given radius of a coordinate, optionally\nfiltered by type. Results are ordered by distance.\n\n**Pricing:** $0.001 / call\n\n`GET /nearby`\n\n_operationId:_ `getNearby`",
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{api_key}}",
                      "type": "string"
                    }
                  ]
                }
              },
              "status": "Nearby entities returned.",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"ok\": true,\n  \"result\": {\n    \"center\": {\n      \"lat\": 31.96,\n      \"lon\": -99.9\n    },\n    \"radius_m\": 500,\n    \"count\": 4,\n    \"entities\": [\n      {\n        \"id\": \"sensor_h2s_023\",\n        \"type\": \"gas_sensor\",\n        \"distance_m\": 142.0,\n        \"bearing_deg\": 87\n      },\n      {\n        \"id\": \"sensor_h2s_021\",\n        \"type\": \"gas_sensor\",\n        \"distance_m\": 268.4,\n        \"bearing_deg\": 271\n      },\n      {\n        \"id\": \"sensor_h2s_024\",\n        \"type\": \"gas_sensor\",\n        \"distance_m\": 401.8,\n        \"bearing_deg\": 88\n      },\n      {\n        \"id\": \"drone_01\",\n        \"type\": \"drone\",\n        \"distance_m\": 489.2,\n        \"bearing_deg\": 12\n      }\n    ]\n  },\n  \"meta\": {\n    \"confidence\": 0.95,\n    \"model_version\": \"plume-v4.1.2\",\n    \"calibration_age_days\": 47,\n    \"site_calibrated\": true,\n    \"provenance\": [\n      \"registry:tenant-2026-04-21\"\n    ],\n    \"request_id\": \"req_01hx29sknd4bqyt8r\",\n    \"latency_ms\": 41\n  }\n}"
            }
          ]
        },
        {
          "name": "Polygon containment query",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/within?geometry=",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "within"
              ],
              "query": [
                {
                  "key": "geometry",
                  "value": "",
                  "description": "URL-encoded GeoJSON Polygon or MultiPolygon.",
                  "disabled": false
                },
                {
                  "key": "type",
                  "value": "",
                  "description": "Entity type filter. Same built-in values as /nearby (gas_sensor, water_sensor, rf_node, asset, personnel, drone), plus any registered custom type.",
                  "disabled": true
                },
                {
                  "key": "include_context",
                  "value": "False",
                  "description": "If true, includes full SpatialState for each result (billed at $0.001/entity).",
                  "disabled": true
                }
              ]
            },
            "description": "Returns all registered entities whose location falls within a given GeoJSON polygon.\nUsed for zone-based queries — \"which sensors are inside this permit boundary?\"\n\n**Pricing:** $0.001 / call (+$0.001/entity if include_context=true)\n\n`GET /within`\n\n_operationId:_ `getWithin`",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{api_key}}",
                  "type": "string"
                }
              ]
            }
          },
          "response": [
            {
              "name": "200 Entities within polygon returned.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{base_url}}/within?geometry=",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "within"
                  ],
                  "query": [
                    {
                      "key": "geometry",
                      "value": "",
                      "description": "URL-encoded GeoJSON Polygon or MultiPolygon.",
                      "disabled": false
                    },
                    {
                      "key": "type",
                      "value": "",
                      "description": "Entity type filter. Same built-in values as /nearby (gas_sensor, water_sensor, rf_node, asset, personnel, drone), plus any registered custom type.",
                      "disabled": true
                    },
                    {
                      "key": "include_context",
                      "value": "False",
                      "description": "If true, includes full SpatialState for each result (billed at $0.001/entity).",
                      "disabled": true
                    }
                  ]
                },
                "description": "Returns all registered entities whose location falls within a given GeoJSON polygon.\nUsed for zone-based queries — \"which sensors are inside this permit boundary?\"\n\n**Pricing:** $0.001 / call (+$0.001/entity if include_context=true)\n\n`GET /within`\n\n_operationId:_ `getWithin`",
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{api_key}}",
                      "type": "string"
                    }
                  ]
                }
              },
              "status": "Entities within polygon returned.",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"ok\": true,\n  \"result\": {\n    \"count\": 3,\n    \"entities\": [\n      {\n        \"id\": \"sensor_h2s_023\",\n        \"type\": \"gas_sensor\",\n        \"location\": {\n          \"lat\": 31.9686,\n          \"lon\": -99.9018,\n          \"alt_m\": 547.2,\n          \"h3_index\": \"8944c0ba857ffff\",\n          \"indoor\": null\n        }\n      },\n      {\n        \"id\": \"sensor_h2s_024\",\n        \"type\": \"gas_sensor\",\n        \"location\": {\n          \"lat\": 31.969,\n          \"lon\": -99.9012,\n          \"alt_m\": 548.0,\n          \"h3_index\": \"8944c0ba853ffff\",\n          \"indoor\": null\n        }\n      },\n      {\n        \"id\": \"wellhead_07\",\n        \"type\": \"asset\",\n        \"location\": {\n          \"lat\": 31.9682,\n          \"lon\": -99.902,\n          \"alt_m\": 547.0,\n          \"h3_index\": \"8944c0ba85bffff\",\n          \"indoor\": null\n        }\n      }\n    ]\n  },\n  \"meta\": {\n    \"confidence\": 0.97,\n    \"model_version\": \"plume-v4.1.2\",\n    \"calibration_age_days\": 47,\n    \"site_calibrated\": true,\n    \"provenance\": [\n      \"registry:tenant-2026-04-21\"\n    ],\n    \"request_id\": \"req_01hx29sknd4bqyt8r\",\n    \"latency_ms\": 38\n  }\n}"
            }
          ]
        },
        {
          "name": "Jurisdiction resolution for any coordinate",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/jurisdiction",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "jurisdiction"
              ],
              "query": [
                {
                  "key": "lat",
                  "value": "31.9686",
                  "description": "WGS84 latitude. Required unless device_id is provided.",
                  "disabled": true
                },
                {
                  "key": "lon",
                  "value": "-99.9018",
                  "description": "WGS84 longitude. Required unless device_id is provided.",
                  "disabled": true
                },
                {
                  "key": "device_id",
                  "value": "",
                  "description": "Alternative to lat/lon — uses the device's registered coordinates.",
                  "disabled": true
                },
                {
                  "key": "domains",
                  "value": "air,water",
                  "description": "Comma-separated domain filter. Options: air, water, noise, land, fire. Default: all.",
                  "disabled": true
                }
              ]
            },
            "description": "Returns all applicable regulatory jurisdictions and permit obligations for a given\ncoordinate — air quality authority, watershed governance, noise ordinance, and\ncross-boundary relationships.\n\n**Pricing:** $0.0005 / call (free when device_id is passed to /context)\n\n`GET /jurisdiction`\n\n_operationId:_ `getJurisdiction`",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{api_key}}",
                  "type": "string"
                }
              ]
            }
          },
          "response": [
            {
              "name": "200 Jurisdiction data returned.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{base_url}}/jurisdiction",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "jurisdiction"
                  ],
                  "query": [
                    {
                      "key": "lat",
                      "value": "31.9686",
                      "description": "WGS84 latitude. Required unless device_id is provided.",
                      "disabled": true
                    },
                    {
                      "key": "lon",
                      "value": "-99.9018",
                      "description": "WGS84 longitude. Required unless device_id is provided.",
                      "disabled": true
                    },
                    {
                      "key": "device_id",
                      "value": "",
                      "description": "Alternative to lat/lon — uses the device's registered coordinates.",
                      "disabled": true
                    },
                    {
                      "key": "domains",
                      "value": "air,water",
                      "description": "Comma-separated domain filter. Options: air, water, noise, land, fire. Default: all.",
                      "disabled": true
                    }
                  ]
                },
                "description": "Returns all applicable regulatory jurisdictions and permit obligations for a given\ncoordinate — air quality authority, watershed governance, noise ordinance, and\ncross-boundary relationships.\n\n**Pricing:** $0.0005 / call (free when device_id is passed to /context)\n\n`GET /jurisdiction`\n\n_operationId:_ `getJurisdiction`",
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{api_key}}",
                      "type": "string"
                    }
                  ]
                }
              },
              "status": "Jurisdiction data returned.",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"ok\": true,\n  \"result\": {\n    \"location\": {\n      \"lat\": 31.9686,\n      \"lon\": -99.9018\n    },\n    \"jurisdiction\": {\n      \"air_quality\": {\n        \"authority\": \"TCEQ\",\n        \"permit_id\": \"PSDTX1234\",\n        \"limit_ppm\": 10\n      },\n      \"water\": {\n        \"authority\": \"TCEQ\",\n        \"watershed_id\": \"basin_colorado_mid\"\n      }\n    }\n  },\n  \"meta\": {\n    \"confidence\": 0.99,\n    \"model_version\": \"jurisdiction-v2.3.0\",\n    \"calibration_age_days\": 12,\n    \"site_calibrated\": false,\n    \"provenance\": [\n      \"jurisdiction:TCEQ-2025-Q4\",\n      \"watershed:USGS-WBD-2025\"\n    ],\n    \"request_id\": \"req_01hx29sknd4bqyt8r\",\n    \"latency_ms\": 33\n  }\n}"
            }
          ]
        }
      ]
    },
    {
      "name": "Simulate API",
      "description": "Physics-based propagation simulations (async jobs).",
      "item": [
        {
          "name": "Atmospheric dispersion simulation",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/simulate/plume",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "simulate",
                "plume"
              ]
            },
            "description": "Runs an atmospheric dispersion model for a point or area source. Tier 1 uses Gaussian\nplume (fast screening, <8 s). Tier 2 uses AERMOD-style regulatory-grade modeling\n(15–60 s). Tier 3 uses Lagrangian particle tracking for non-steady-state scenarios\n(minutes). Returns concentration isopleths, predicted readings at registered sensor\nlocations, and affected zone classifications.\n\n**Pricing:** $0.05–$0.25 / run depending on tier.\n\n`POST /simulate/plume`\n\n_operationId:_ `simulatePlume`",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{api_key}}",
                  "type": "string"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"source\": {\n    \"lat\": 31.9642,\n    \"lon\": -99.9035,\n    \"alt_m\": 545,\n    \"emission_rate_gs\": 2.4,\n    \"stack_height_m\": 12\n  },\n  \"wind\": {\n    \"speed_ms\": 8.2,\n    \"bearing_deg\": 312\n  },\n  \"stability_class\": \"D\",\n  \"duration_min\": 60,\n  \"tier\": 2,\n  \"species\": \"H2S\",\n  \"output_receptors\": [\n    \"sensor_h2s_021\",\n    \"sensor_h2s_023\",\n    \"sensor_h2s_024\"\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [
            {
              "name": "202 Simulation job accepted.",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{base_url}}/simulate/plume",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "simulate",
                    "plume"
                  ]
                },
                "description": "Runs an atmospheric dispersion model for a point or area source. Tier 1 uses Gaussian\nplume (fast screening, <8 s). Tier 2 uses AERMOD-style regulatory-grade modeling\n(15–60 s). Tier 3 uses Lagrangian particle tracking for non-steady-state scenarios\n(minutes). Returns concentration isopleths, predicted readings at registered sensor\nlocations, and affected zone classifications.\n\n**Pricing:** $0.05–$0.25 / run depending on tier.\n\n`POST /simulate/plume`\n\n_operationId:_ `simulatePlume`",
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{api_key}}",
                      "type": "string"
                    }
                  ]
                },
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"source\": {\n    \"lat\": 31.9642,\n    \"lon\": -99.9035,\n    \"alt_m\": 545,\n    \"emission_rate_gs\": 2.4,\n    \"stack_height_m\": 12\n  },\n  \"wind\": {\n    \"speed_ms\": 8.2,\n    \"bearing_deg\": 312\n  },\n  \"stability_class\": \"D\",\n  \"duration_min\": 60,\n  \"tier\": 2,\n  \"species\": \"H2S\",\n  \"output_receptors\": [\n    \"sensor_h2s_021\",\n    \"sensor_h2s_023\",\n    \"sensor_h2s_024\"\n  ]\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Simulation job accepted.",
              "code": 202,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"ok\": true,\n  \"job\": {\n    \"id\": \"job_01hx2a3f9k8qmzn7p\",\n    \"type\": \"simulate/plume\",\n    \"status\": \"queued\",\n    \"eta_seconds\": 8,\n    \"poll_url\": \"https://api.geog.ai/v1/jobs/job_01hx2a3f9k8qmzn7p\",\n    \"webhook_delivered\": false\n  },\n  \"meta\": {\n    \"request_id\": \"req_01hx29sknd4bqyt8r\"\n  }\n}"
            }
          ]
        },
        {
          "name": "Live plume tracking via Server-Sent Events",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Accept",
                "value": "text/event-stream"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/simulate/plume/stream",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "simulate",
                "plume",
                "stream"
              ]
            },
            "description": "Opens a Server-Sent Events (SSE) stream that delivers a running plume\nsimulation in real time. The client POSTs a `PlumeStreamRequest` with\n`Accept: text/event-stream`; the server responds `200 OK` with\n`Content-Type: text/event-stream` and emits a sequence of named events\nuntil the simulation completes or the client disconnects.\n\n**Event types** (the SSE `event:` field):\n\n- `tick` — heartbeat with simulation clock and wind vector, emitted\n  every `tick_interval_s` seconds\n- `concentration` — updated isopleth polygons and per-receptor\n  concentrations, emitted on every tick after the field stabilises\n- `alert` — emitted when an `alert_thresholds` value is crossed at\n  any receptor or isopleth\n- `end` — terminal event with run summary; clients should stop\n  reconnecting after receiving this\n\nEvery event carries a stable `id:` field. Clients that drop the\nconnection should reconnect with `Last-Event-ID` to resume from the\nlast event seen. The official SDKs (`streamPlume` in TypeScript,\n`stream_plume` in Python) implement this reconnect-with-backoff\nbehaviour automatically.\n\n**Availability:** Site Calibration plans only.\n\n**Pricing:** $0.25 / run, billed once on `end`.\n\n`POST /simulate/plume/stream`\n\n_operationId:_ `streamPlume`",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{api_key}}",
                  "type": "string"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"source\": {\n    \"lat\": 31.9642,\n    \"lon\": -99.9035,\n    \"alt_m\": 545,\n    \"emission_rate_gs\": 2.4,\n    \"stack_height_m\": 12\n  },\n  \"wind\": {\n    \"speed_ms\": 8.2,\n    \"bearing_deg\": 312\n  },\n  \"stability_class\": \"D\",\n  \"duration_min\": 60,\n  \"species\": \"H2S\",\n  \"output_receptors\": [\n    \"sensor_h2s_021\",\n    \"sensor_h2s_023\",\n    \"sensor_h2s_024\"\n  ],\n  \"tick_interval_s\": 5,\n  \"alert_thresholds\": {\n    \"warn\": 1.0,\n    \"action\": 5.0,\n    \"evacuate\": 10.0\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [
            {
              "name": "200 SSE stream opened. The response body is a `text/event-stream",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "text/event-stream"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{base_url}}/simulate/plume/stream",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "simulate",
                    "plume",
                    "stream"
                  ]
                },
                "description": "Opens a Server-Sent Events (SSE) stream that delivers a running plume\nsimulation in real time. The client POSTs a `PlumeStreamRequest` with\n`Accept: text/event-stream`; the server responds `200 OK` with\n`Content-Type: text/event-stream` and emits a sequence of named events\nuntil the simulation completes or the client disconnects.\n\n**Event types** (the SSE `event:` field):\n\n- `tick` — heartbeat with simulation clock and wind vector, emitted\n  every `tick_interval_s` seconds\n- `concentration` — updated isopleth polygons and per-receptor\n  concentrations, emitted on every tick after the field stabilises\n- `alert` — emitted when an `alert_thresholds` value is crossed at\n  any receptor or isopleth\n- `end` — terminal event with run summary; clients should stop\n  reconnecting after receiving this\n\nEvery event carries a stable `id:` field. Clients that drop the\nconnection should reconnect with `Last-Event-ID` to resume from the\nlast event seen. The official SDKs (`streamPlume` in TypeScript,\n`stream_plume` in Python) implement this reconnect-with-backoff\nbehaviour automatically.\n\n**Availability:** Site Calibration plans only.\n\n**Pricing:** $0.25 / run, billed once on `end`.\n\n`POST /simulate/plume/stream`\n\n_operationId:_ `streamPlume`",
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{api_key}}",
                      "type": "string"
                    }
                  ]
                },
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"source\": {\n    \"lat\": 31.9642,\n    \"lon\": -99.9035,\n    \"alt_m\": 545,\n    \"emission_rate_gs\": 2.4,\n    \"stack_height_m\": 12\n  },\n  \"wind\": {\n    \"speed_ms\": 8.2,\n    \"bearing_deg\": 312\n  },\n  \"stability_class\": \"D\",\n  \"duration_min\": 60,\n  \"species\": \"H2S\",\n  \"output_receptors\": [\n    \"sensor_h2s_021\",\n    \"sensor_h2s_023\",\n    \"sensor_h2s_024\"\n  ],\n  \"tick_interval_s\": 5,\n  \"alert_thresholds\": {\n    \"warn\": 1.0,\n    \"action\": 5.0,\n    \"evacuate\": 10.0\n  }\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "SSE stream opened. The response body is a `text/event-stream`",
              "code": 200,
              "_postman_previewlanguage": "text",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "text/event-stream"
                },
                {
                  "key": "Cache-Control",
                  "value": "no-cache"
                },
                {
                  "key": "Connection",
                  "value": "keep-alive"
                }
              ],
              "body": "event: tick\nid: 1\ndata: {\"sim_time_s\":5,\"wall_time\":\"2026-04-21T03:14:27Z\",\"progress\":0.0014,\"wind_vector\":{\"speed_ms\":8.2,\"bearing_deg\":312}}\n\nevent: concentration\nid: 2\ndata: {\"sim_time_s\":10,\"isopleths\":[{\"concentration_ppm\":10,\"polygon\":{\"type\":\"Polygon\",\"coordinates\":[]}}],\"receptors\":[{\"device_id\":\"sensor_h2s_023\",\"concentration_ppm\":4.7}],\"max_concentration_ppm\":12.4}\n\nevent: alert\nid: 9\ndata: {\"sim_time_s\":45,\"threshold\":\"action\",\"threshold_ppm\":5.0,\"observed_ppm\":6.2,\"device_id\":\"sensor_h2s_023\",\"location\":{\"lat\":31.9686,\"lon\":-99.9018}}\n\nevent: end\nid: 720\ndata: {\"sim_time_s\":3600,\"reason\":\"completed\",\"summary\":{\"ticks_emitted\":720,\"alerts_emitted\":3,\"max_concentration_ppm\":58.1,\"job_id\":\"job_01hx2a3f9k8qmzn7p\"}}\n"
            }
          ]
        },
        {
          "name": "Flood and hydrological simulation",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/simulate/flood",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "simulate",
                "flood"
              ]
            },
            "description": "Runs DEM-based watershed delineation, SCS Curve Number rainfall-runoff modeling,\nkinematic wave channel routing, and 2D inundation mapping. Returns flood extent\npolygons at multiple return intervals, time-to-crest forecasts, and sensors predicted\nto be inundated.\n\nEither `watershed_id` or `area` is required.\n\n**Pricing:** $0.10 / run\n\n`POST /simulate/flood`\n\n_operationId:_ `simulateFlood`",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{api_key}}",
                  "type": "string"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"watershed_id\": \"basin_colorado_mid\",\n  \"precip_mm\": 85,\n  \"duration_hr\": 3,\n  \"return_periods\": [\n    10,\n    100\n  ],\n  \"antecedent_moisture\": \"wet\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [
            {
              "name": "202 Simulation job accepted.",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{base_url}}/simulate/flood",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "simulate",
                    "flood"
                  ]
                },
                "description": "Runs DEM-based watershed delineation, SCS Curve Number rainfall-runoff modeling,\nkinematic wave channel routing, and 2D inundation mapping. Returns flood extent\npolygons at multiple return intervals, time-to-crest forecasts, and sensors predicted\nto be inundated.\n\nEither `watershed_id` or `area` is required.\n\n**Pricing:** $0.10 / run\n\n`POST /simulate/flood`\n\n_operationId:_ `simulateFlood`",
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{api_key}}",
                      "type": "string"
                    }
                  ]
                },
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"watershed_id\": \"basin_colorado_mid\",\n  \"precip_mm\": 85,\n  \"duration_hr\": 3,\n  \"return_periods\": [\n    10,\n    100\n  ],\n  \"antecedent_moisture\": \"wet\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Simulation job accepted.",
              "code": 202,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"ok\": true,\n  \"job\": {\n    \"id\": \"job_01hx2a4q7kflood01\",\n    \"type\": \"simulate/flood\",\n    \"status\": \"queued\",\n    \"eta_seconds\": 22,\n    \"poll_url\": \"https://api.geog.ai/v1/jobs/job_01hx2a4q7kflood01\",\n    \"webhook_delivered\": false\n  },\n  \"meta\": {\n    \"request_id\": \"req_01hx29sknd4bqyt8r\"\n  }\n}"
            }
          ]
        },
        {
          "name": "Single-node RF coverage simulation",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/simulate/rf_coverage",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "simulate",
                "rf_coverage"
              ]
            },
            "description": "Runs the ITM/Longley-Rice terrain propagation model for a single RF node. Returns a\ncoverage probability polygon at the specified RSSI threshold, plus a raster heatmap\nand link budget summary. Either `node_id` or `lat/lon/alt_m` is required.\n\n**Pricing:** $0.08 / run\n\n`POST /simulate/rf_coverage`\n\n_operationId:_ `simulateRFCoverage`",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{api_key}}",
                  "type": "string"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"node_id\": \"rf_node_A7\",\n  \"frequency_mhz\": 915,\n  \"tx_power_dbm\": 20,\n  \"rssi_threshold_dbm\": -95,\n  \"antenna_height_m\": 6,\n  \"model\": \"itm\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [
            {
              "name": "202 Simulation job accepted.",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{base_url}}/simulate/rf_coverage",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "simulate",
                    "rf_coverage"
                  ]
                },
                "description": "Runs the ITM/Longley-Rice terrain propagation model for a single RF node. Returns a\ncoverage probability polygon at the specified RSSI threshold, plus a raster heatmap\nand link budget summary. Either `node_id` or `lat/lon/alt_m` is required.\n\n**Pricing:** $0.08 / run\n\n`POST /simulate/rf_coverage`\n\n_operationId:_ `simulateRFCoverage`",
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{api_key}}",
                      "type": "string"
                    }
                  ]
                },
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"node_id\": \"rf_node_A7\",\n  \"frequency_mhz\": 915,\n  \"tx_power_dbm\": 20,\n  \"rssi_threshold_dbm\": -95,\n  \"antenna_height_m\": 6,\n  \"model\": \"itm\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Simulation job accepted.",
              "code": 202,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"ok\": true,\n  \"job\": {\n    \"id\": \"job_01hx2a4q7krf0001\",\n    \"type\": \"simulate/rf_coverage\",\n    \"status\": \"queued\",\n    \"eta_seconds\": 11,\n    \"poll_url\": \"https://api.geog.ai/v1/jobs/job_01hx2a4q7krf0001\",\n    \"webhook_delivered\": false\n  },\n  \"meta\": {\n    \"request_id\": \"req_01hx29sknd4bqyt8r\"\n  }\n}"
            }
          ]
        },
        {
          "name": "Noise propagation simulation",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/simulate/noise",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "simulate",
                "noise"
              ]
            },
            "description": "Runs ISO 9613-2 octave-band outdoor sound propagation from a point or line source.\nAccounts for geometric spreading, atmospheric absorption, ground effect, barrier\ninsertion loss, and vegetation attenuation. Returns noise contour polygons (isodB\nlines) and exceedance flags at registered receptor locations.\n\nEither `source_id` or a source geometry must be provided.\n\n**Pricing:** $0.08 / run\n\n`POST /simulate/noise`\n\n_operationId:_ `simulateNoise`",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{api_key}}",
                  "type": "string"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"source_id\": \"compressor_C4\",\n  \"octave_bands_db\": [\n    82,\n    86,\n    91,\n    95,\n    93,\n    88,\n    84,\n    79\n  ],\n  \"contour_levels_dba\": [\n    45,\n    55,\n    65\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [
            {
              "name": "202 Simulation job accepted.",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{base_url}}/simulate/noise",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "simulate",
                    "noise"
                  ]
                },
                "description": "Runs ISO 9613-2 octave-band outdoor sound propagation from a point or line source.\nAccounts for geometric spreading, atmospheric absorption, ground effect, barrier\ninsertion loss, and vegetation attenuation. Returns noise contour polygons (isodB\nlines) and exceedance flags at registered receptor locations.\n\nEither `source_id` or a source geometry must be provided.\n\n**Pricing:** $0.08 / run\n\n`POST /simulate/noise`\n\n_operationId:_ `simulateNoise`",
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{api_key}}",
                      "type": "string"
                    }
                  ]
                },
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"source_id\": \"compressor_C4\",\n  \"octave_bands_db\": [\n    82,\n    86,\n    91,\n    95,\n    93,\n    88,\n    84,\n    79\n  ],\n  \"contour_levels_dba\": [\n    45,\n    55,\n    65\n  ]\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Simulation job accepted.",
              "code": 202,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"ok\": true,\n  \"job\": {\n    \"id\": \"job_01hx2a4q7knoise01\",\n    \"type\": \"simulate/noise\",\n    \"status\": \"queued\",\n    \"eta_seconds\": 14,\n    \"poll_url\": \"https://api.geog.ai/v1/jobs/job_01hx2a4q7knoise01\",\n    \"webhook_delivered\": false\n  },\n  \"meta\": {\n    \"request_id\": \"req_01hx29sknd4bqyt8r\"\n  }\n}"
            }
          ]
        },
        {
          "name": "Thermal / heat diffusion simulation",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/simulate/thermal",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "simulate",
                "thermal"
              ]
            },
            "description": "Models heat propagation from industrial sources, fire events, or equipment failures.\nReturns time-to-temperature-threshold at monitored locations and hot zone polygons.\n\n**Pricing:** $0.08 / run\n\n`POST /simulate/thermal`\n\n_operationId:_ `simulateThermal`",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{api_key}}",
                  "type": "string"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"source\": {\n    \"lat\": 31.9642,\n    \"lon\": -99.9035,\n    \"power_kw\": 850,\n    \"temperature_c\": 240\n  },\n  \"duration_min\": 120,\n  \"threshold_c\": [\n    40,\n    60,\n    80\n  ],\n  \"output_receptors\": [\n    \"sensor_temp_07\",\n    \"sensor_temp_12\"\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [
            {
              "name": "202 Simulation job accepted.",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{base_url}}/simulate/thermal",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "simulate",
                    "thermal"
                  ]
                },
                "description": "Models heat propagation from industrial sources, fire events, or equipment failures.\nReturns time-to-temperature-threshold at monitored locations and hot zone polygons.\n\n**Pricing:** $0.08 / run\n\n`POST /simulate/thermal`\n\n_operationId:_ `simulateThermal`",
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{api_key}}",
                      "type": "string"
                    }
                  ]
                },
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"source\": {\n    \"lat\": 31.9642,\n    \"lon\": -99.9035,\n    \"power_kw\": 850,\n    \"temperature_c\": 240\n  },\n  \"duration_min\": 120,\n  \"threshold_c\": [\n    40,\n    60,\n    80\n  ],\n  \"output_receptors\": [\n    \"sensor_temp_07\",\n    \"sensor_temp_12\"\n  ]\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Simulation job accepted.",
              "code": 202,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"ok\": true,\n  \"job\": {\n    \"id\": \"job_01hx2a4q7kthermal\",\n    \"type\": \"simulate/thermal\",\n    \"status\": \"queued\",\n    \"eta_seconds\": 12,\n    \"poll_url\": \"https://api.geog.ai/v1/jobs/job_01hx2a4q7kthermal\",\n    \"webhook_delivered\": false\n  },\n  \"meta\": {\n    \"request_id\": \"req_01hx29sknd4bqyt8r\"\n  }\n}"
            }
          ]
        },
        {
          "name": "Fire spread simulation",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/simulate/fire",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "simulate",
                "fire"
              ]
            },
            "description": "Models wildfire spread using terrain, fuel model, and weather conditions. Returns fire\nperimeter polygons at specified time intervals, rate-of-spread vectors, and smoke plume\ntrajectory (linked to `/simulate/plume` for full smoke transport).\n\n**Pricing:** $0.15 / run\n\n`POST /simulate/fire`\n\n_operationId:_ `simulateFire`",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{api_key}}",
                  "type": "string"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"ignition_point\": {\n    \"type\": \"Point\",\n    \"coordinates\": [\n      -119.42,\n      34.21\n    ]\n  },\n  \"fuel_model\": \"GR2\",\n  \"weather\": {\n    \"wind_speed_ms\": 8.3,\n    \"wind_bearing_deg\": 225,\n    \"rh_pct\": 12,\n    \"temp_c\": 38\n  },\n  \"duration_hr\": 24,\n  \"output_intervals_hr\": [\n    1,\n    4,\n    12,\n    24\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [
            {
              "name": "202 Simulation job accepted.",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{base_url}}/simulate/fire",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "simulate",
                    "fire"
                  ]
                },
                "description": "Models wildfire spread using terrain, fuel model, and weather conditions. Returns fire\nperimeter polygons at specified time intervals, rate-of-spread vectors, and smoke plume\ntrajectory (linked to `/simulate/plume` for full smoke transport).\n\n**Pricing:** $0.15 / run\n\n`POST /simulate/fire`\n\n_operationId:_ `simulateFire`",
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{api_key}}",
                      "type": "string"
                    }
                  ]
                },
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"ignition_point\": {\n    \"type\": \"Point\",\n    \"coordinates\": [\n      -119.42,\n      34.21\n    ]\n  },\n  \"fuel_model\": \"GR2\",\n  \"weather\": {\n    \"wind_speed_ms\": 8.3,\n    \"wind_bearing_deg\": 225,\n    \"rh_pct\": 12,\n    \"temp_c\": 38\n  },\n  \"duration_hr\": 24,\n  \"output_intervals_hr\": [\n    1,\n    4,\n    12,\n    24\n  ]\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Simulation job accepted.",
              "code": 202,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"ok\": true,\n  \"job\": {\n    \"id\": \"job_01hx2a4q7kfire001\",\n    \"type\": \"simulate/fire\",\n    \"status\": \"queued\",\n    \"eta_seconds\": 42,\n    \"poll_url\": \"https://api.geog.ai/v1/jobs/job_01hx2a4q7kfire001\",\n    \"webhook_delivered\": false\n  },\n  \"meta\": {\n    \"request_id\": \"req_01hx29sknd4bqyt8r\"\n  }\n}"
            }
          ]
        }
      ]
    },
    {
      "name": "RF API",
      "description": "Radio-frequency coverage, link budget, and mesh analysis.",
      "item": [
        {
          "name": "Coverage polygon for a registered node",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/rf/coverage?node=rf_node_A7",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "rf",
                "coverage"
              ],
              "query": [
                {
                  "key": "node",
                  "value": "rf_node_A7",
                  "description": "Registered RF node ID.",
                  "disabled": false
                },
                {
                  "key": "threshold_dbm",
                  "value": "-92",
                  "description": "RSSI threshold in dBm. Default -90 dBm.",
                  "disabled": true
                }
              ]
            },
            "description": "Returns the coverage probability polygon for a registered RF node at a given RSSI\nthreshold. Cached per node until terrain or node configuration changes.\n\n**Pricing:** $0.08 / call\n\n`GET /rf/coverage`\n\n_operationId:_ `getRFCoverage`",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{api_key}}",
                  "type": "string"
                }
              ]
            }
          },
          "response": [
            {
              "name": "200 Coverage polygon returned.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{base_url}}/rf/coverage?node=rf_node_A7",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "rf",
                    "coverage"
                  ],
                  "query": [
                    {
                      "key": "node",
                      "value": "rf_node_A7",
                      "description": "Registered RF node ID.",
                      "disabled": false
                    },
                    {
                      "key": "threshold_dbm",
                      "value": "-92",
                      "description": "RSSI threshold in dBm. Default -90 dBm.",
                      "disabled": true
                    }
                  ]
                },
                "description": "Returns the coverage probability polygon for a registered RF node at a given RSSI\nthreshold. Cached per node until terrain or node configuration changes.\n\n**Pricing:** $0.08 / call\n\n`GET /rf/coverage`\n\n_operationId:_ `getRFCoverage`",
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{api_key}}",
                      "type": "string"
                    }
                  ]
                }
              },
              "status": "Coverage polygon returned.",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"ok\": true,\n  \"result\": {\n    \"node_id\": \"rf_node_A7\",\n    \"threshold_dbm\": -92,\n    \"coverage_polygon\": {\n      \"type\": \"Polygon\",\n      \"coordinates\": [\n        [\n          [\n            -99.911,\n            31.962\n          ],\n          [\n            -99.901,\n            31.962\n          ],\n          [\n            -99.901,\n            31.972\n          ],\n          [\n            -99.911,\n            31.972\n          ],\n          [\n            -99.911,\n            31.962\n          ]\n        ]\n      ]\n    },\n    \"coverage_area_km2\": 4.12,\n    \"max_range_m\": 1820,\n    \"cached\": true,\n    \"cache_age_min\": 17\n  },\n  \"meta\": {\n    \"confidence\": 0.91,\n    \"model_version\": \"rf-itm-v3.2.0\",\n    \"calibration_age_days\": 22,\n    \"site_calibrated\": true,\n    \"provenance\": [\n      \"terrain:USGS-3DEP-1m\"\n    ],\n    \"request_id\": \"req_01hx29sknd4bqyt8r\",\n    \"latency_ms\": 64\n  }\n}"
            }
          ]
        },
        {
          "name": "Point-to-point RF link budget",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/rf/link?from=rf_node_A7&to=rf_node_B3",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "rf",
                "link"
              ],
              "query": [
                {
                  "key": "from",
                  "value": "rf_node_A7",
                  "description": "Source node ID.",
                  "disabled": false
                },
                {
                  "key": "to",
                  "value": "rf_node_B3",
                  "description": "Target node ID.",
                  "disabled": false
                },
                {
                  "key": "reliability_pct",
                  "value": "99.0",
                  "description": "Required link reliability percentage. Default 99.0.",
                  "disabled": true
                }
              ]
            },
            "description": "Returns the link budget between two registered nodes — predicted RSSI, fade margin,\nFresnel zone clearance, and obstruction analysis. Returns a pass/fail recommendation\ngiven the specified reliability threshold.\n\n**Pricing:** $0.03 / call\n\n`GET /rf/link`\n\n_operationId:_ `getRFLink`",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{api_key}}",
                  "type": "string"
                }
              ]
            }
          },
          "response": [
            {
              "name": "200 Link budget calculated.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{base_url}}/rf/link?from=rf_node_A7&to=rf_node_B3",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "rf",
                    "link"
                  ],
                  "query": [
                    {
                      "key": "from",
                      "value": "rf_node_A7",
                      "description": "Source node ID.",
                      "disabled": false
                    },
                    {
                      "key": "to",
                      "value": "rf_node_B3",
                      "description": "Target node ID.",
                      "disabled": false
                    },
                    {
                      "key": "reliability_pct",
                      "value": "99.0",
                      "description": "Required link reliability percentage. Default 99.0.",
                      "disabled": true
                    }
                  ]
                },
                "description": "Returns the link budget between two registered nodes — predicted RSSI, fade margin,\nFresnel zone clearance, and obstruction analysis. Returns a pass/fail recommendation\ngiven the specified reliability threshold.\n\n**Pricing:** $0.03 / call\n\n`GET /rf/link`\n\n_operationId:_ `getRFLink`",
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{api_key}}",
                      "type": "string"
                    }
                  ]
                }
              },
              "status": "Link budget calculated.",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"ok\": true,\n  \"result\": {\n    \"from\": \"rf_node_A7\",\n    \"to\": \"rf_node_B3\",\n    \"distance_m\": 1842.0,\n    \"predicted_rssi_dbm\": -78.4,\n    \"fade_margin_db\": 11.6,\n    \"fresnel_clearance_pct\": 84.0,\n    \"obstructions\": [],\n    \"link_viable\": true,\n    \"reliability_at_threshold\": 99.4\n  },\n  \"meta\": {\n    \"confidence\": 0.94,\n    \"model_version\": \"rf-itm-v3.2.0\",\n    \"calibration_age_days\": 22,\n    \"site_calibrated\": true,\n    \"provenance\": [\n      \"terrain:USGS-3DEP-1m\"\n    ],\n    \"request_id\": \"req_01hx29sknd4bqyt8r\",\n    \"latency_ms\": 56\n  }\n}"
            }
          ]
        },
        {
          "name": "Coverage gap heatmap within an area",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/rf/gaps?area=",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "rf",
                "gaps"
              ],
              "query": [
                {
                  "key": "area",
                  "value": "",
                  "description": "URL-encoded GeoJSON Polygon defining the area to analyze.",
                  "disabled": false
                },
                {
                  "key": "threshold_dbm",
                  "value": "-90",
                  "description": "RSSI below which a cell is considered a gap. Default -90 dBm.",
                  "disabled": true
                },
                {
                  "key": "node_ids",
                  "value": "",
                  "description": "Comma-separated node IDs to analyze against. Default all registered nodes in area.",
                  "disabled": true
                }
              ]
            },
            "description": "Identifies coverage gaps within a defined area given existing node topology. Returns a\nGeoJSON heatmap of gap severity and a list of H3 cells with insufficient coverage.\n\n**Pricing:** $0.05 / call\n\n`GET /rf/gaps`\n\n_operationId:_ `getRFGaps`",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{api_key}}",
                  "type": "string"
                }
              ]
            }
          },
          "response": [
            {
              "name": "200 Coverage gap analysis returned.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{base_url}}/rf/gaps?area=",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "rf",
                    "gaps"
                  ],
                  "query": [
                    {
                      "key": "area",
                      "value": "",
                      "description": "URL-encoded GeoJSON Polygon defining the area to analyze.",
                      "disabled": false
                    },
                    {
                      "key": "threshold_dbm",
                      "value": "-90",
                      "description": "RSSI below which a cell is considered a gap. Default -90 dBm.",
                      "disabled": true
                    },
                    {
                      "key": "node_ids",
                      "value": "",
                      "description": "Comma-separated node IDs to analyze against. Default all registered nodes in area.",
                      "disabled": true
                    }
                  ]
                },
                "description": "Identifies coverage gaps within a defined area given existing node topology. Returns a\nGeoJSON heatmap of gap severity and a list of H3 cells with insufficient coverage.\n\n**Pricing:** $0.05 / call\n\n`GET /rf/gaps`\n\n_operationId:_ `getRFGaps`",
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{api_key}}",
                      "type": "string"
                    }
                  ]
                }
              },
              "status": "Coverage gap analysis returned.",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"ok\": true,\n  \"result\": {\n    \"coverage_pct\": 67.4,\n    \"gap_pct\": 32.6,\n    \"gap_heatmap\": {\n      \"type\": \"FeatureCollection\",\n      \"features\": []\n    },\n    \"gap_cells_h3\": [\n      \"8944c0ba8a3ffff\",\n      \"8944c0ba8a7ffff\",\n      \"8944c0ba8abffff\"\n    ],\n    \"worst_gap_location\": {\n      \"lat\": 31.9712,\n      \"lon\": -99.8945,\n      \"best_rssi_dbm\": -101.4\n    }\n  },\n  \"meta\": {\n    \"confidence\": 0.88,\n    \"model_version\": \"rf-itm-v3.2.0\",\n    \"calibration_age_days\": 22,\n    \"site_calibrated\": true,\n    \"provenance\": [\n      \"terrain:USGS-3DEP-1m\"\n    ],\n    \"request_id\": \"req_01hx29sknd4bqyt8r\",\n    \"latency_ms\": 192\n  }\n}"
            }
          ]
        },
        {
          "name": "Full mesh connectivity matrix",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/rf/mesh/viability",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "rf",
                "mesh",
                "viability"
              ]
            },
            "description": "Computes the full link budget matrix for a mesh network — every node-to-node pair,\nwith failure probability based on calibrated path loss models. Returns a connectivity\nmatrix, mesh reliability score, single-points-of-failure, and failure scenario analysis.\n\nAsync job; typical completion 15–40 seconds for networks up to 200 nodes.\n\n**Pricing:** $0.15 / run\n\n`POST /rf/mesh/viability`\n\n_operationId:_ `rfMeshViability`",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{api_key}}",
                  "type": "string"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"node_ids\": [\n    \"rf_node_A7\",\n    \"rf_node_B3\",\n    \"rf_node_C2\",\n    \"rf_node_D9\"\n  ],\n  \"min_path_reliability_pct\": 99.5,\n  \"failure_scenarios\": [\n    {\n      \"node_id\": \"rf_node_A7\",\n      \"failure_probability\": 0.05\n    }\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [
            {
              "name": "202 Mesh viability job accepted.",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{base_url}}/rf/mesh/viability",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "rf",
                    "mesh",
                    "viability"
                  ]
                },
                "description": "Computes the full link budget matrix for a mesh network — every node-to-node pair,\nwith failure probability based on calibrated path loss models. Returns a connectivity\nmatrix, mesh reliability score, single-points-of-failure, and failure scenario analysis.\n\nAsync job; typical completion 15–40 seconds for networks up to 200 nodes.\n\n**Pricing:** $0.15 / run\n\n`POST /rf/mesh/viability`\n\n_operationId:_ `rfMeshViability`",
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{api_key}}",
                      "type": "string"
                    }
                  ]
                },
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"node_ids\": [\n    \"rf_node_A7\",\n    \"rf_node_B3\",\n    \"rf_node_C2\",\n    \"rf_node_D9\"\n  ],\n  \"min_path_reliability_pct\": 99.5,\n  \"failure_scenarios\": [\n    {\n      \"node_id\": \"rf_node_A7\",\n      \"failure_probability\": 0.05\n    }\n  ]\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Mesh viability job accepted.",
              "code": 202,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"ok\": true,\n  \"job\": {\n    \"id\": \"job_01hx2a4q7kmesh001\",\n    \"type\": \"rf/mesh/viability\",\n    \"status\": \"queued\",\n    \"eta_seconds\": 28,\n    \"poll_url\": \"https://api.geog.ai/v1/jobs/job_01hx2a4q7kmesh001\",\n    \"webhook_delivered\": false\n  },\n  \"meta\": {\n    \"request_id\": \"req_01hx29sknd4bqyt8r\"\n  }\n}"
            }
          ]
        },
        {
          "name": "Node placement optimizer for RF coverage",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/rf/optimize/placement",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "rf",
                "optimize",
                "placement"
              ]
            },
            "description": "Given existing mesh topology, terrain, and coverage requirements, returns the top-N\ncandidate locations that maximize marginal coverage gain.\n\n**Pricing:** $1.00–$5.00 / run\n\n`POST /rf/optimize/placement`\n\n_operationId:_ `rfOptimizePlacement`",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{api_key}}",
                  "type": "string"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"area\": {\n    \"type\": \"Polygon\",\n    \"coordinates\": [\n      [\n        [\n          \"-99.92 - 31.95\",\n          [\n            -99.88,\n            31.95\n          ],\n          [\n            -99.88,\n            31.99\n          ],\n          [\n            -99.92,\n            31.99\n          ],\n          [\n            -99.92,\n            31.95\n          ]\n        ]\n      ]\n    ]\n  },\n  \"coverage_threshold\": 0.95,\n  \"existing_nodes\": [\n    \"rf_node_A7\",\n    \"rf_node_B3\"\n  ],\n  \"candidate_count\": 5,\n  \"frequency_mhz\": 915,\n  \"constraints\": {\n    \"min_distance_from_edge_m\": 50,\n    \"require_road_access\": true\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [
            {
              "name": "202 Placement optimization job accepted.",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{base_url}}/rf/optimize/placement",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "rf",
                    "optimize",
                    "placement"
                  ]
                },
                "description": "Given existing mesh topology, terrain, and coverage requirements, returns the top-N\ncandidate locations that maximize marginal coverage gain.\n\n**Pricing:** $1.00–$5.00 / run\n\n`POST /rf/optimize/placement`\n\n_operationId:_ `rfOptimizePlacement`",
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{api_key}}",
                      "type": "string"
                    }
                  ]
                },
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"area\": {\n    \"type\": \"Polygon\",\n    \"coordinates\": [\n      [\n        [\n          \"-99.92 - 31.95\",\n          [\n            -99.88,\n            31.95\n          ],\n          [\n            -99.88,\n            31.99\n          ],\n          [\n            -99.92,\n            31.99\n          ],\n          [\n            -99.92,\n            31.95\n          ]\n        ]\n      ]\n    ]\n  },\n  \"coverage_threshold\": 0.95,\n  \"existing_nodes\": [\n    \"rf_node_A7\",\n    \"rf_node_B3\"\n  ],\n  \"candidate_count\": 5,\n  \"frequency_mhz\": 915,\n  \"constraints\": {\n    \"min_distance_from_edge_m\": 50,\n    \"require_road_access\": true\n  }\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Placement optimization job accepted.",
              "code": 202,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"ok\": true,\n  \"job\": {\n    \"id\": \"job_01hx2a4q7krfopt01\",\n    \"type\": \"rf/optimize/placement\",\n    \"status\": \"queued\",\n    \"eta_seconds\": 180,\n    \"poll_url\": \"https://api.geog.ai/v1/jobs/job_01hx2a4q7krfopt01\",\n    \"webhook_delivered\": false\n  },\n  \"meta\": {\n    \"request_id\": \"req_01hx29sknd4bqyt8r\"\n  }\n}"
            }
          ]
        }
      ]
    },
    {
      "name": "Optimize API",
      "description": "Node and sensor placement optimization; coverage and gap analysis.",
      "item": [
        {
          "name": "General node placement optimizer",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/optimize/node_placement",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "optimize",
                "node_placement"
              ]
            },
            "description": "Generalizes RF placement to any monitoring objective — air quality sensor spacing\n(accounting for plume physics), flood gauge placement (watershed coverage), or\nacoustic monitor placement (source coverage). Returns ranked candidate locations with\nobjective-specific marginal gain scores.\n\n**Pricing:** $1.00–$5.00 / run\n\n`POST /optimize/node_placement`\n\n_operationId:_ `optimizeNodePlacement`",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{api_key}}",
                  "type": "string"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"area\": {\n    \"type\": \"Polygon\",\n    \"coordinates\": [\n      [\n        [\n          \"-99.92 - 31.95\",\n          [\n            -99.88,\n            31.95\n          ],\n          [\n            -99.88,\n            31.99\n          ],\n          [\n            -99.92,\n            31.99\n          ],\n          [\n            -99.92,\n            31.95\n          ]\n        ]\n      ]\n    ]\n  },\n  \"coverage_threshold\": 0.9,\n  \"existing_nodes\": [\n    \"sensor_h2s_021\",\n    \"sensor_h2s_023\"\n  ],\n  \"objective\": \"plume_detection\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [
            {
              "name": "202 Node placement job accepted.",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{base_url}}/optimize/node_placement",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "optimize",
                    "node_placement"
                  ]
                },
                "description": "Generalizes RF placement to any monitoring objective — air quality sensor spacing\n(accounting for plume physics), flood gauge placement (watershed coverage), or\nacoustic monitor placement (source coverage). Returns ranked candidate locations with\nobjective-specific marginal gain scores.\n\n**Pricing:** $1.00–$5.00 / run\n\n`POST /optimize/node_placement`\n\n_operationId:_ `optimizeNodePlacement`",
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{api_key}}",
                      "type": "string"
                    }
                  ]
                },
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"area\": {\n    \"type\": \"Polygon\",\n    \"coordinates\": [\n      [\n        [\n          \"-99.92 - 31.95\",\n          [\n            -99.88,\n            31.95\n          ],\n          [\n            -99.88,\n            31.99\n          ],\n          [\n            -99.92,\n            31.99\n          ],\n          [\n            -99.92,\n            31.95\n          ]\n        ]\n      ]\n    ]\n  },\n  \"coverage_threshold\": 0.9,\n  \"existing_nodes\": [\n    \"sensor_h2s_021\",\n    \"sensor_h2s_023\"\n  ],\n  \"objective\": \"plume_detection\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Node placement job accepted.",
              "code": 202,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"ok\": true,\n  \"job\": {\n    \"id\": \"job_01hx2a4q7knode001\",\n    \"type\": \"optimize/node_placement\",\n    \"status\": \"queued\",\n    \"eta_seconds\": 120,\n    \"poll_url\": \"https://api.geog.ai/v1/jobs/job_01hx2a4q7knode001\",\n    \"webhook_delivered\": false\n  },\n  \"meta\": {\n    \"request_id\": \"req_01hx29sknd4bqyt8r\"\n  }\n}"
            }
          ]
        },
        {
          "name": "Vertical-aware sensor placement optimization",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/optimize/sensor_placement",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "optimize",
                "sensor_placement"
              ]
            },
            "description": "Recommends sensor placement for a given ZOOID vertical — accounts for the vertical's\nspecific measurement physics, regulatory requirements, and deployment constraints.\n\n**Pricing:** $2.00–$5.00 / run\n\n`POST /optimize/sensor_placement`\n\n_operationId:_ `optimizeSensorPlacement`",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{api_key}}",
                  "type": "string"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"vertical\": \"V01\",\n  \"area\": {\n    \"type\": \"Polygon\",\n    \"coordinates\": [\n      [\n        [\n          \"-99.92 - 31.95\",\n          [\n            -99.88,\n            31.95\n          ],\n          [\n            -99.88,\n            31.99\n          ],\n          [\n            -99.92,\n            31.99\n          ],\n          [\n            -99.92,\n            31.95\n          ]\n        ]\n      ]\n    ]\n  },\n  \"target_coverage_pct\": 0.95,\n  \"budget_nodes\": 8\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [
            {
              "name": "202 Sensor placement job accepted.",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{base_url}}/optimize/sensor_placement",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "optimize",
                    "sensor_placement"
                  ]
                },
                "description": "Recommends sensor placement for a given ZOOID vertical — accounts for the vertical's\nspecific measurement physics, regulatory requirements, and deployment constraints.\n\n**Pricing:** $2.00–$5.00 / run\n\n`POST /optimize/sensor_placement`\n\n_operationId:_ `optimizeSensorPlacement`",
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{api_key}}",
                      "type": "string"
                    }
                  ]
                },
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"vertical\": \"V01\",\n  \"area\": {\n    \"type\": \"Polygon\",\n    \"coordinates\": [\n      [\n        [\n          \"-99.92 - 31.95\",\n          [\n            -99.88,\n            31.95\n          ],\n          [\n            -99.88,\n            31.99\n          ],\n          [\n            -99.92,\n            31.99\n          ],\n          [\n            -99.92,\n            31.95\n          ]\n        ]\n      ]\n    ]\n  },\n  \"target_coverage_pct\": 0.95,\n  \"budget_nodes\": 8\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Sensor placement job accepted.",
              "code": 202,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"ok\": true,\n  \"job\": {\n    \"id\": \"job_01hx2a4q7ksensor01\",\n    \"type\": \"optimize/sensor_placement\",\n    \"status\": \"queued\",\n    \"eta_seconds\": 240,\n    \"poll_url\": \"https://api.geog.ai/v1/jobs/job_01hx2a4q7ksensor01\",\n    \"webhook_delivered\": false\n  },\n  \"meta\": {\n    \"request_id\": \"req_01hx29sknd4bqyt8r\"\n  }\n}"
            }
          ]
        },
        {
          "name": "Coverage analysis for an area",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/coverage?area=&type=gas_sensor",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "coverage"
              ],
              "query": [
                {
                  "key": "area",
                  "value": "",
                  "description": "URL-encoded GeoJSON polygon defining the area of interest.",
                  "disabled": false
                },
                {
                  "key": "type",
                  "value": "gas_sensor",
                  "description": "Sensor type to assess coverage for.",
                  "disabled": false
                }
              ]
            },
            "description": "Returns the current monitoring coverage fraction for a given area and sensor type.\nCoverage is defined by the spatial footprint of registered sensors given their\ndetection physics.\n\n**Pricing:** $0.01 / call\n\n`GET /coverage`\n\n_operationId:_ `getCoverage`",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{api_key}}",
                  "type": "string"
                }
              ]
            }
          },
          "response": [
            {
              "name": "200 Coverage analysis returned.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{base_url}}/coverage?area=&type=gas_sensor",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "coverage"
                  ],
                  "query": [
                    {
                      "key": "area",
                      "value": "",
                      "description": "URL-encoded GeoJSON polygon defining the area of interest.",
                      "disabled": false
                    },
                    {
                      "key": "type",
                      "value": "gas_sensor",
                      "description": "Sensor type to assess coverage for.",
                      "disabled": false
                    }
                  ]
                },
                "description": "Returns the current monitoring coverage fraction for a given area and sensor type.\nCoverage is defined by the spatial footprint of registered sensors given their\ndetection physics.\n\n**Pricing:** $0.01 / call\n\n`GET /coverage`\n\n_operationId:_ `getCoverage`",
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{api_key}}",
                      "type": "string"
                    }
                  ]
                }
              },
              "status": "Coverage analysis returned.",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"ok\": true,\n  \"result\": {\n    \"sensor_type\": \"gas_sensor\",\n    \"area_km2\": 12.4,\n    \"covered_km2\": 8.16,\n    \"coverage_pct\": 65.8,\n    \"active_sensors\": 14,\n    \"coverage_polygon\": {\n      \"type\": \"Polygon\",\n      \"coordinates\": [\n        [\n          [\n            -99.911,\n            31.962\n          ],\n          [\n            -99.901,\n            31.962\n          ],\n          [\n            -99.901,\n            31.972\n          ],\n          [\n            -99.911,\n            31.972\n          ],\n          [\n            -99.911,\n            31.962\n          ]\n        ]\n      ]\n    }\n  },\n  \"meta\": {\n    \"confidence\": 0.92,\n    \"model_version\": \"coverage-v1.4.0\",\n    \"calibration_age_days\": 18,\n    \"site_calibrated\": true,\n    \"provenance\": [\n      \"registry:tenant-2026-04-21\"\n    ],\n    \"request_id\": \"req_01hx29sknd4bqyt8r\",\n    \"latency_ms\": 72\n  }\n}"
            }
          ]
        },
        {
          "name": "Monitoring gap analysis for an area",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/gaps?area=",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "gaps"
              ],
              "query": [
                {
                  "key": "area",
                  "value": "",
                  "description": "URL-encoded GeoJSON polygon defining the area of interest.",
                  "disabled": false
                },
                {
                  "key": "threshold_m",
                  "value": "400",
                  "description": "Maximum acceptable distance from any sensor in metres. Default 500 m.",
                  "disabled": true
                },
                {
                  "key": "type",
                  "value": "",
                  "description": "Sensor type filter.",
                  "disabled": true
                }
              ]
            },
            "description": "Identifies monitoring gaps within a defined area — H3 cells where no sensor provides\nadequate coverage given detection physics. Returns a GeoJSON gap heatmap and summary\nstatistics.\n\n**Pricing:** $0.01 / call\n\n`GET /gaps`\n\n_operationId:_ `getGaps`",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{api_key}}",
                  "type": "string"
                }
              ]
            }
          },
          "response": [
            {
              "name": "200 Gap analysis returned.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{base_url}}/gaps?area=",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "gaps"
                  ],
                  "query": [
                    {
                      "key": "area",
                      "value": "",
                      "description": "URL-encoded GeoJSON polygon defining the area of interest.",
                      "disabled": false
                    },
                    {
                      "key": "threshold_m",
                      "value": "400",
                      "description": "Maximum acceptable distance from any sensor in metres. Default 500 m.",
                      "disabled": true
                    },
                    {
                      "key": "type",
                      "value": "",
                      "description": "Sensor type filter.",
                      "disabled": true
                    }
                  ]
                },
                "description": "Identifies monitoring gaps within a defined area — H3 cells where no sensor provides\nadequate coverage given detection physics. Returns a GeoJSON gap heatmap and summary\nstatistics.\n\n**Pricing:** $0.01 / call\n\n`GET /gaps`\n\n_operationId:_ `getGaps`",
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{api_key}}",
                      "type": "string"
                    }
                  ]
                }
              },
              "status": "Gap analysis returned.",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"ok\": true,\n  \"result\": {\n    \"gap_pct\": 34.2,\n    \"gap_heatmap\": {\n      \"type\": \"FeatureCollection\",\n      \"features\": []\n    },\n    \"gap_cells_h3\": [\n      \"8944c0ba8a3ffff\",\n      \"8944c0ba8a7ffff\"\n    ],\n    \"largest_gap_area_km2\": 1.8,\n    \"largest_gap_centroid\": {\n      \"lat\": 31.9714,\n      \"lon\": -99.8946\n    }\n  },\n  \"meta\": {\n    \"confidence\": 0.9,\n    \"model_version\": \"coverage-v1.4.0\",\n    \"calibration_age_days\": 18,\n    \"site_calibrated\": true,\n    \"provenance\": [\n      \"registry:tenant-2026-04-21\"\n    ],\n    \"request_id\": \"req_01hx29sknd4bqyt8r\",\n    \"latency_ms\": 96\n  }\n}"
            }
          ]
        }
      ]
    },
    {
      "name": "Trajectory API",
      "description": "Spatiotemporal trajectory storage, retrieval, and prediction.",
      "item": [
        {
          "name": "Trajectory history for a moving entity",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/trajectory?entity_id=drone_01&from=2026-04-21T02:00:00Z&to=2026-04-21T03:00:00Z",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "trajectory"
              ],
              "query": [
                {
                  "key": "entity_id",
                  "value": "drone_01",
                  "description": "Registered entity ID (drone, vehicle, or personnel).",
                  "disabled": false
                },
                {
                  "key": "from",
                  "value": "2026-04-21T02:00:00Z",
                  "description": "Start of time window (ISO 8601).",
                  "disabled": false
                },
                {
                  "key": "to",
                  "value": "2026-04-21T03:00:00Z",
                  "description": "End of time window (ISO 8601). Max window 30 days.",
                  "disabled": false
                },
                {
                  "key": "resolution_s",
                  "value": "0",
                  "description": "Temporal resolution of returned positions in seconds. Default raw (all recorded positions).",
                  "disabled": true
                }
              ]
            },
            "description": "Returns the stored trajectory (sequence of positions with timestamps and uncertainty\nbounds) for a registered moving entity over a specified time window.\n\n**Pricing:** $0.002 / call\n\n`GET /trajectory`\n\n_operationId:_ `getTrajectory`",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{api_key}}",
                  "type": "string"
                }
              ]
            }
          },
          "response": [
            {
              "name": "200 Trajectory returned.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{base_url}}/trajectory?entity_id=drone_01&from=2026-04-21T02:00:00Z&to=2026-04-21T03:00:00Z",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "trajectory"
                  ],
                  "query": [
                    {
                      "key": "entity_id",
                      "value": "drone_01",
                      "description": "Registered entity ID (drone, vehicle, or personnel).",
                      "disabled": false
                    },
                    {
                      "key": "from",
                      "value": "2026-04-21T02:00:00Z",
                      "description": "Start of time window (ISO 8601).",
                      "disabled": false
                    },
                    {
                      "key": "to",
                      "value": "2026-04-21T03:00:00Z",
                      "description": "End of time window (ISO 8601). Max window 30 days.",
                      "disabled": false
                    },
                    {
                      "key": "resolution_s",
                      "value": "0",
                      "description": "Temporal resolution of returned positions in seconds. Default raw (all recorded positions).",
                      "disabled": true
                    }
                  ]
                },
                "description": "Returns the stored trajectory (sequence of positions with timestamps and uncertainty\nbounds) for a registered moving entity over a specified time window.\n\n**Pricing:** $0.002 / call\n\n`GET /trajectory`\n\n_operationId:_ `getTrajectory`",
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{api_key}}",
                      "type": "string"
                    }
                  ]
                }
              },
              "status": "Trajectory returned.",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"ok\": true,\n  \"result\": {\n    \"entity_id\": \"drone_01\",\n    \"window\": {\n      \"from\": \"2026-04-21T02:00:00Z\",\n      \"to\": \"2026-04-21T03:00:00Z\"\n    },\n    \"point_count\": 3,\n    \"positions\": [\n      {\n        \"time\": \"2026-04-21T02:00:00Z\",\n        \"lat\": 31.9701,\n        \"lon\": -99.9024,\n        \"alt_m\": 612.5,\n        \"uncertainty_m\": 1.2\n      },\n      {\n        \"time\": \"2026-04-21T02:30:00Z\",\n        \"lat\": 31.9712,\n        \"lon\": -99.9018,\n        \"alt_m\": 615.0,\n        \"uncertainty_m\": 1.4\n      },\n      {\n        \"time\": \"2026-04-21T03:00:00Z\",\n        \"lat\": 31.9724,\n        \"lon\": -99.9011,\n        \"alt_m\": 618.2,\n        \"uncertainty_m\": 1.6\n      }\n    ],\n    \"geojson_linestring\": {\n      \"type\": \"LineString\",\n      \"coordinates\": [\n        [\n          -99.9024,\n          31.9701,\n          612.5\n        ],\n        [\n          -99.9018,\n          31.9712,\n          615.0\n        ],\n        [\n          -99.9011,\n          31.9724,\n          618.2\n        ]\n      ]\n    }\n  },\n  \"meta\": {\n    \"confidence\": 0.96,\n    \"model_version\": \"trajectory-v2.0.1\",\n    \"calibration_age_days\": 30,\n    \"site_calibrated\": true,\n    \"provenance\": [\n      \"telemetry:drone-2026-04-21\"\n    ],\n    \"request_id\": \"req_01hx29sknd4bqyt8r\",\n    \"latency_ms\": 49\n  }\n}"
            }
          ]
        },
        {
          "name": "Trajectory prediction / dead reckoning",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/trajectory/predict",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "trajectory",
                "predict"
              ]
            },
            "description": "Predicts the future trajectory of a moving entity given current position, velocity,\nand historical movement patterns. Returns a predicted path with expanding uncertainty\nbounds. Used for drone flight path prediction, fleet routing optimization, and\npersonnel zone arrival forecasting.\n\n**Pricing:** $0.005 / call\n\n`POST /trajectory/predict`\n\n_operationId:_ `trajectoryPredict`",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{api_key}}",
                  "type": "string"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"entity_id\": \"drone_01\",\n  \"lookahead_min\": 30,\n  \"mission_plan\": {\n    \"type\": \"LineString\",\n    \"coordinates\": [\n      [\n        -99.9024,\n        31.9701\n      ],\n      [\n        -99.898,\n        31.9755\n      ],\n      [\n        -99.8932,\n        31.981\n      ]\n    ]\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [
            {
              "name": "200 Trajectory prediction returned.",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{base_url}}/trajectory/predict",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "trajectory",
                    "predict"
                  ]
                },
                "description": "Predicts the future trajectory of a moving entity given current position, velocity,\nand historical movement patterns. Returns a predicted path with expanding uncertainty\nbounds. Used for drone flight path prediction, fleet routing optimization, and\npersonnel zone arrival forecasting.\n\n**Pricing:** $0.005 / call\n\n`POST /trajectory/predict`\n\n_operationId:_ `trajectoryPredict`",
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{api_key}}",
                      "type": "string"
                    }
                  ]
                },
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"entity_id\": \"drone_01\",\n  \"lookahead_min\": 30,\n  \"mission_plan\": {\n    \"type\": \"LineString\",\n    \"coordinates\": [\n      [\n        -99.9024,\n        31.9701\n      ],\n      [\n        -99.898,\n        31.9755\n      ],\n      [\n        -99.8932,\n        31.981\n      ]\n    ]\n  }\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Trajectory prediction returned.",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"ok\": true,\n  \"result\": {\n    \"entity_id\": \"drone_01\",\n    \"predicted_positions\": [\n      {\n        \"time\": \"2026-04-21T03:10:00Z\",\n        \"lat\": 31.974,\n        \"lon\": -99.9,\n        \"alt_m\": 620.0,\n        \"uncertainty_m\": 4.2\n      },\n      {\n        \"time\": \"2026-04-21T03:20:00Z\",\n        \"lat\": 31.976,\n        \"lon\": -99.898,\n        \"alt_m\": 622.4,\n        \"uncertainty_m\": 8.7\n      },\n      {\n        \"time\": \"2026-04-21T03:30:00Z\",\n        \"lat\": 31.978,\n        \"lon\": -99.896,\n        \"alt_m\": 624.1,\n        \"uncertainty_m\": 14.1\n      }\n    ],\n    \"predicted_path\": {\n      \"type\": \"LineString\",\n      \"coordinates\": [\n        [\n          -99.9,\n          31.974,\n          620.0\n        ],\n        [\n          -99.898,\n          31.976,\n          622.4\n        ],\n        [\n          -99.896,\n          31.978,\n          624.1\n        ]\n      ]\n    },\n    \"uncertainty_corridor\": {\n      \"type\": \"Polygon\",\n      \"coordinates\": [\n        [\n          [\n            -99.9004,\n            31.9738\n          ],\n          [\n            -99.8956,\n            31.9778\n          ],\n          [\n            -99.8964,\n            31.9784\n          ],\n          [\n            -99.9008,\n            31.9742\n          ],\n          [\n            -99.9004,\n            31.9738\n          ]\n        ]\n      ]\n    }\n  },\n  \"meta\": {\n    \"confidence\": 0.84,\n    \"model_version\": \"trajectory-v2.0.1\",\n    \"calibration_age_days\": 30,\n    \"site_calibrated\": true,\n    \"provenance\": [\n      \"telemetry:drone-2026-04-21\"\n    ],\n    \"request_id\": \"req_01hx29sknd4bqyt8r\",\n    \"latency_ms\": 102\n  }\n}"
            }
          ]
        }
      ]
    },
    {
      "name": "Graph API",
      "description": "Spatial graph operations — influence spread, evacuation routing, upstream tracing.",
      "item": [
        {
          "name": "Network-reachable nodes within a cost radius from a source",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/route/influence_spread",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "route",
                "influence_spread"
              ]
            },
            "description": "Given a source point and a network-distance `radius_cost`, returns every node in the\nnamed routing network reachable within that cost. Backed by `pgr_drivingDistance` over\n`geo_road_networks`, scoped to the caller's tenant and vertical. Reachable nodes are\nordered by ascending accumulated cost.\n\n**Pricing:** $0.005 / call\n\n`POST /route/influence_spread`\n\n_operationId:_ `postRouteInfluenceSpread`",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{api_key}}",
                  "type": "string"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"vertical_id\": \"oilgas\",\n  \"network_id\": \"wellpad_07\",\n  \"source\": {\n    \"lat\": 31.9686,\n    \"lng\": -102.0779\n  },\n  \"radius_cost\": 1000\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [
            {
              "name": "200 Reachable nodes returned.",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{base_url}}/route/influence_spread",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "route",
                    "influence_spread"
                  ]
                },
                "description": "Given a source point and a network-distance `radius_cost`, returns every node in the\nnamed routing network reachable within that cost. Backed by `pgr_drivingDistance` over\n`geo_road_networks`, scoped to the caller's tenant and vertical. Reachable nodes are\nordered by ascending accumulated cost.\n\n**Pricing:** $0.005 / call\n\n`POST /route/influence_spread`\n\n_operationId:_ `postRouteInfluenceSpread`",
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{api_key}}",
                      "type": "string"
                    }
                  ]
                },
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"vertical_id\": \"oilgas\",\n  \"network_id\": \"wellpad_07\",\n  \"source\": {\n    \"lat\": 31.9686,\n    \"lng\": -102.0779\n  },\n  \"radius_cost\": 1000\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Reachable nodes returned.",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"source_node\": 4021,\n  \"radius_cost\": 1000,\n  \"reachable_node_count\": 37,\n  \"nodes\": [\n    {\n      \"node_id\": 4021,\n      \"cost\": 0.0\n    },\n    {\n      \"node_id\": 4088,\n      \"cost\": 213.4\n    },\n    {\n      \"node_id\": 4103,\n      \"cost\": 742.9\n    }\n  ]\n}"
            }
          ]
        },
        {
          "name": "Least-cost route to the nearest safe zone, avoiding active hazards",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/route/evacuation",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "route",
                "evacuation"
              ]
            },
            "description": "Returns the least-cost route from a starting point to whichever of the supplied\n`safe_zones` is cheapest to reach, routing around active hazard geometries. The avoid\nset is auto-populated from recent *succeeded* simulate jobs (live plume, flood, fire,\nRF-failure FeatureCollections) within `freshness_minutes`. Uses pgRouting on the named\nnetwork.\n\n**Pricing:** $0.01 / call\n\n`POST /route/evacuation`\n\n_operationId:_ `postRouteEvacuation`",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{api_key}}",
                  "type": "string"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"vertical_id\": \"oilgas\",\n  \"network_id\": \"wellpad_07\",\n  \"from\": {\n    \"lat\": 31.9686,\n    \"lng\": -102.0779\n  },\n  \"safe_zones\": [\n    {\n      \"lat\": 31.9721,\n      \"lng\": -102.0742\n    },\n    {\n      \"lat\": 31.965,\n      \"lng\": -102.081\n    }\n  ],\n  \"freshness_minutes\": 30\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [
            {
              "name": "200 Evacuation route returned as a GeoJSON Feature.",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{base_url}}/route/evacuation",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "route",
                    "evacuation"
                  ]
                },
                "description": "Returns the least-cost route from a starting point to whichever of the supplied\n`safe_zones` is cheapest to reach, routing around active hazard geometries. The avoid\nset is auto-populated from recent *succeeded* simulate jobs (live plume, flood, fire,\nRF-failure FeatureCollections) within `freshness_minutes`. Uses pgRouting on the named\nnetwork.\n\n**Pricing:** $0.01 / call\n\n`POST /route/evacuation`\n\n_operationId:_ `postRouteEvacuation`",
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{api_key}}",
                      "type": "string"
                    }
                  ]
                },
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"vertical_id\": \"oilgas\",\n  \"network_id\": \"wellpad_07\",\n  \"from\": {\n    \"lat\": 31.9686,\n    \"lng\": -102.0779\n  },\n  \"safe_zones\": [\n    {\n      \"lat\": 31.9721,\n      \"lng\": -102.0742\n    },\n    {\n      \"lat\": 31.965,\n      \"lng\": -102.081\n    }\n  ],\n  \"freshness_minutes\": 30\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Evacuation route returned as a GeoJSON Feature.",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"type\": \"Feature\",\n  \"geometry\": {\n    \"type\": \"LineString\",\n    \"coordinates\": [\n      [\n        -102.0779,\n        31.9686\n      ],\n      [\n        -102.0761,\n        31.9702\n      ],\n      [\n        -102.0742,\n        31.9721\n      ]\n    ]\n  },\n  \"properties\": {\n    \"network_id\": \"wellpad_07\",\n    \"total_cost\": 340.2,\n    \"chosen_safe_zone\": {\n      \"lat\": 31.9721,\n      \"lng\": -102.0742\n    },\n    \"candidate_count\": 2,\n    \"avoid_jobs_considered\": 3\n  }\n}"
            }
          ]
        }
      ]
    },
    {
      "name": "Calibration",
      "description": "Site-specific model calibration state.",
      "item": [
        {
          "name": "Site-specific model calibration state",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/model/calibration?model=plume&site_id=wellpad_07",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "model",
                "calibration"
              ],
              "query": [
                {
                  "key": "model",
                  "value": "plume",
                  "description": "Propagation model to query calibration state for.",
                  "disabled": false
                },
                {
                  "key": "site_id",
                  "value": "wellpad_07",
                  "description": "Site identifier.",
                  "disabled": false
                }
              ]
            },
            "description": "Returns the current calibration state for a given propagation model and site —\nincluding calibration age, parameter corrections applied, and prediction accuracy\nmetrics over the last 30/90 days.\n\nRequires Site Calibration plan.\n\n**Pricing:** $0.001 / call (Site Calibration plan only)\n\n`GET /model/calibration`\n\n_operationId:_ `getModelCalibration`",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{api_key}}",
                  "type": "string"
                }
              ]
            }
          },
          "response": [
            {
              "name": "200 Calibration state returned.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{base_url}}/model/calibration?model=plume&site_id=wellpad_07",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "model",
                    "calibration"
                  ],
                  "query": [
                    {
                      "key": "model",
                      "value": "plume",
                      "description": "Propagation model to query calibration state for.",
                      "disabled": false
                    },
                    {
                      "key": "site_id",
                      "value": "wellpad_07",
                      "description": "Site identifier.",
                      "disabled": false
                    }
                  ]
                },
                "description": "Returns the current calibration state for a given propagation model and site —\nincluding calibration age, parameter corrections applied, and prediction accuracy\nmetrics over the last 30/90 days.\n\nRequires Site Calibration plan.\n\n**Pricing:** $0.001 / call (Site Calibration plan only)\n\n`GET /model/calibration`\n\n_operationId:_ `getModelCalibration`",
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{api_key}}",
                      "type": "string"
                    }
                  ]
                }
              },
              "status": "Calibration state returned.",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"ok\": true,\n  \"result\": {\n    \"model\": \"plume\",\n    \"site_id\": \"wellpad_07\",\n    \"calibration_age_days\": 47,\n    \"last_calibrated_at\": \"2026-03-05T14:22:00Z\",\n    \"accuracy_30d\": {\n      \"mean_absolute_error\": 0.18,\n      \"r_squared\": 0.94\n    },\n    \"corrections_applied\": {\n      \"stability_correction\": 0.05,\n      \"terrain_correction_factor\": 1.12,\n      \"effective_emission_height_m\": 14.2\n    }\n  },\n  \"meta\": {\n    \"confidence\": 0.97,\n    \"model_version\": \"plume-v4.1.2\",\n    \"calibration_age_days\": 47,\n    \"site_calibrated\": true,\n    \"provenance\": [\n      \"calibration:wellpad_07-2026-03-05\"\n    ],\n    \"request_id\": \"req_01hx29sknd4bqyt8r\",\n    \"latency_ms\": 42\n  }\n}"
            }
          ]
        }
      ]
    },
    {
      "name": "Jobs",
      "description": "Async job status polling.",
      "item": [
        {
          "name": "Poll async job status and retrieve result",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/jobs/:job_id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "jobs",
                ":job_id"
              ],
              "variable": [
                {
                  "key": "job_id",
                  "value": "",
                  "description": "Job ID returned from a POST /simulate/* or other async endpoint."
                }
              ]
            },
            "description": "Returns the current status of an async simulation job. When status is `complete`,\nthe full result is included in the `result` field of the response envelope.\nJobs expire 48 hours after completion.\n\n`GET /jobs/{job_id}`\n\n_operationId:_ `getJob`",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{api_key}}",
                  "type": "string"
                }
              ]
            }
          },
          "response": [
            {
              "name": "200 Job status (and result if complete).",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{base_url}}/jobs/:job_id",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "jobs",
                    ":job_id"
                  ],
                  "variable": [
                    {
                      "key": "job_id",
                      "value": "",
                      "description": "Job ID returned from a POST /simulate/* or other async endpoint."
                    }
                  ]
                },
                "description": "Returns the current status of an async simulation job. When status is `complete`,\nthe full result is included in the `result` field of the response envelope.\nJobs expire 48 hours after completion.\n\n`GET /jobs/{job_id}`\n\n_operationId:_ `getJob`",
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{api_key}}",
                      "type": "string"
                    }
                  ]
                }
              },
              "status": "Job status (and result if complete).",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"ok\": true,\n  \"job\": {\n    \"id\": \"job_01hx2a3f9k8qmzn7p\",\n    \"type\": \"simulate/plume\",\n    \"status\": \"complete\",\n    \"eta_seconds\": null,\n    \"webhook_delivered\": true\n  },\n  \"result\": {\n    \"isopleths\": [\n      {\n        \"concentration_ppm\": 10,\n        \"polygon\": {\n          \"type\": \"Polygon\",\n          \"coordinates\": [\n            [\n              [\n                -99.905,\n                31.9645\n              ],\n              [\n                -99.902,\n                31.9648\n              ],\n              [\n                -99.9018,\n                31.967\n              ],\n              [\n                -99.9048,\n                31.9667\n              ],\n              [\n                -99.905,\n                31.9645\n              ]\n            ]\n          ]\n        }\n      }\n    ],\n    \"max_concentration_ppm\": 58.1,\n    \"receptors\": [\n      {\n        \"device_id\": \"sensor_h2s_023\",\n        \"concentration_ppm\": 4.7\n      }\n    ]\n  },\n  \"meta\": {\n    \"confidence\": 0.92,\n    \"model_version\": \"plume-v4.1.2\",\n    \"calibration_age_days\": 47,\n    \"site_calibrated\": true,\n    \"provenance\": [\n      \"met:NOAA-HRRR-2026-04-21T03Z\"\n    ],\n    \"request_id\": \"req_01hx29sknd4bqyt8r\",\n    \"latency_ms\": 17\n  }\n}"
            }
          ]
        }
      ]
    },
    {
      "name": "Capabilities",
      "description": "Deterministic capability registry — the truthful catalog of user-level spatial operations (with status, inputs/outputs, dependencies, validation rules) plus the public dataset/region coverage summary.",
      "item": [
        {
          "name": "List registered spatial capabilities",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/capabilities",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "capabilities"
              ],
              "query": [
                {
                  "key": "status",
                  "value": "available",
                  "description": "",
                  "disabled": true
                },
                {
                  "key": "category",
                  "value": "",
                  "description": "",
                  "disabled": true
                },
                {
                  "key": "async",
                  "value": "False",
                  "description": "",
                  "disabled": true
                }
              ]
            },
            "description": "Returns the capability registry — user-level spatial operations backed by ground-truth classification (never claiming more than the implementation supports) — plus the machine-readable error taxonomy and result trust levels. Public, no authentication required.\n\n`GET /capabilities`\n\n_operationId:_ `listCapabilities`",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{api_key}}",
                  "type": "string"
                }
              ]
            }
          },
          "response": [
            {
              "name": "200 Capability list",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{base_url}}/capabilities",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "capabilities"
                  ],
                  "query": [
                    {
                      "key": "status",
                      "value": "available",
                      "description": "",
                      "disabled": true
                    },
                    {
                      "key": "category",
                      "value": "",
                      "description": "",
                      "disabled": true
                    },
                    {
                      "key": "async",
                      "value": "False",
                      "description": "",
                      "disabled": true
                    }
                  ]
                },
                "description": "Returns the capability registry — user-level spatial operations backed by ground-truth classification (never claiming more than the implementation supports) — plus the machine-readable error taxonomy and result trust levels. Public, no authentication required.\n\n`GET /capabilities`\n\n_operationId:_ `listCapabilities`",
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{api_key}}",
                      "type": "string"
                    }
                  ]
                }
              },
              "status": "Capability list",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"capability_layer_version\": \"\",\n  \"count\": 0,\n  \"capabilities\": [\n    {\n      \"id\": \"\",\n      \"title\": \"\",\n      \"category\": \"\",\n      \"status\": \"available\",\n      \"description\": \"\",\n      \"deterministic\": false,\n      \"async\": false,\n      \"inputs\": {},\n      \"outputs\": {},\n      \"dependencies\": [\n        \"\"\n      ],\n      \"validation_rules\": [\n        \"\"\n      ],\n      \"underlying_operations\": [\n        \"\"\n      ]\n    }\n  ],\n  \"error_taxonomy\": {},\n  \"trust_levels\": [\n    \"VERIFIED\"\n  ]\n}"
            }
          ]
        },
        {
          "name": "Public dataset/region coverage summary",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/capabilities/coverage",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "capabilities",
                "coverage"
              ]
            },
            "description": "Which regions and datasets are actually covered — DEM sources with regions/resolutions, live dataset row counts, and routing-engine availability. Missing coverage is reported, never hidden. Public.\n\n`GET /capabilities/coverage`\n\n_operationId:_ `getCapabilityCoverage`",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{api_key}}",
                  "type": "string"
                }
              ]
            }
          },
          "response": [
            {
              "name": "200 Coverage summary",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{base_url}}/capabilities/coverage",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "capabilities",
                    "coverage"
                  ]
                },
                "description": "Which regions and datasets are actually covered — DEM sources with regions/resolutions, live dataset row counts, and routing-engine availability. Missing coverage is reported, never hidden. Public.\n\n`GET /capabilities/coverage`\n\n_operationId:_ `getCapabilityCoverage`",
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{api_key}}",
                      "type": "string"
                    }
                  ]
                }
              },
              "status": "Coverage summary",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"coverage\": {\n    \"dem_sources\": [\n      {}\n    ],\n    \"datasets\": {},\n    \"notes\": [\n      \"\"\n    ]\n  },\n  \"capability_layer_version\": \"\"\n}"
            }
          ]
        },
        {
          "name": "Capability detail",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/capabilities/:capability_id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "capabilities",
                ":capability_id"
              ],
              "variable": [
                {
                  "key": "capability_id",
                  "value": "",
                  "description": ""
                }
              ]
            },
            "description": "`GET /capabilities/{capability_id}`\n\n_operationId:_ `getCapability`",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{api_key}}",
                  "type": "string"
                }
              ]
            }
          },
          "response": [
            {
              "name": "200 Capability detail",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{base_url}}/capabilities/:capability_id",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "capabilities",
                    ":capability_id"
                  ],
                  "variable": [
                    {
                      "key": "capability_id",
                      "value": "",
                      "description": ""
                    }
                  ]
                },
                "description": "`GET /capabilities/{capability_id}`\n\n_operationId:_ `getCapability`",
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{api_key}}",
                      "type": "string"
                    }
                  ]
                }
              },
              "status": "Capability detail",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"capability\": {\n    \"id\": \"\",\n    \"title\": \"\",\n    \"category\": \"\",\n    \"status\": \"available\",\n    \"description\": \"\",\n    \"deterministic\": false,\n    \"async\": false,\n    \"inputs\": {},\n    \"outputs\": {},\n    \"dependencies\": [\n      \"\"\n    ],\n    \"validation_rules\": [\n      \"\"\n    ],\n    \"underlying_operations\": [\n      \"\"\n    ]\n  },\n  \"capability_layer_version\": \"\"\n}"
            }
          ]
        },
        {
          "name": "Execute one registered capability directly",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/capabilities/:capability_id/execute",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "capabilities",
                ":capability_id",
                "execute"
              ],
              "variable": [
                {
                  "key": "capability_id",
                  "value": "",
                  "description": ""
                }
              ]
            },
            "description": "The capability-API access level — run a single registered capability with explicit inputs. The result carries the standard validation record, normalized provenance, and trust level. Unknown capabilities are impossible: only registry ids resolve. Executing a simulation capability requires the `simulate` key scope and an optimization capability requires `optimize`; read-only keys receive 403.\n\n`POST /capabilities/{capability_id}/execute`\n\n_operationId:_ `executeCapability`",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{api_key}}",
                  "type": "string"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"inputs\": {}\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [
            {
              "name": "200 Capability execution result",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{base_url}}/capabilities/:capability_id/execute",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "capabilities",
                    ":capability_id",
                    "execute"
                  ],
                  "variable": [
                    {
                      "key": "capability_id",
                      "value": "",
                      "description": ""
                    }
                  ]
                },
                "description": "The capability-API access level — run a single registered capability with explicit inputs. The result carries the standard validation record, normalized provenance, and trust level. Unknown capabilities are impossible: only registry ids resolve. Executing a simulation capability requires the `simulate` key scope and an optimization capability requires `optimize`; read-only keys receive 403.\n\n`POST /capabilities/{capability_id}/execute`\n\n_operationId:_ `executeCapability`",
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{api_key}}",
                      "type": "string"
                    }
                  ]
                },
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"inputs\": {}\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Capability execution result",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"result\": {\n    \"step_index\": 0,\n    \"capability_id\": \"\",\n    \"label\": \"\",\n    \"status\": \"succeeded\",\n    \"validation\": {\n      \"capability_id\": \"\",\n      \"validated_at\": \"2026-04-21T03:14:22Z\",\n      \"checks\": [\n        {\n          \"check\": \"\",\n          \"status\": \"passed\",\n          \"detail\": \"\"\n        }\n      ],\n      \"passed\": false\n    },\n    \"provenance\": {\n      \"datasets\": [\n        {\n          \"source\": \"\",\n          \"version\": \"\",\n          \"stac_id\": \"\",\n          \"retrieved_at\": \"2026-04-21T03:14:22Z\",\n          \"crs\": \"\",\n          \"resolution_m\": 0.0,\n          \"fallback\": false\n        }\n      ],\n      \"calculation\": {\n        \"capability_id\": \"\",\n        \"implementation_version\": \"\",\n        \"parameters_hash\": \"\",\n        \"calibration_version\": \"\",\n        \"job_id\": \"\"\n      },\n      \"generated_at\": \"2026-04-21T03:14:22Z\"\n    },\n    \"trust_level\": \"VERIFIED\",\n    \"job_id\": \"\",\n    \"error\": {\n      \"code\": \"INVALID_REQUEST\",\n      \"message\": \"\",\n      \"retryable\": false,\n      \"detail\": {}\n    },\n    \"started_at\": \"2026-04-21T03:14:22Z\",\n    \"finished_at\": \"2026-04-21T03:14:22Z\"\n  }\n}"
            }
          ]
        }
      ]
    },
    {
      "name": "Analyze",
      "description": "AI Spatial Analyst — natural-language analysis (`POST /analyze`) with a deterministic planner-safety pipeline, plus the MCP server endpoint (`POST /mcp`). The LLM only selects registered capabilities; every computation runs deterministically through the capability layer.",
      "item": [
        {
          "name": "Natural-language spatial analysis (AI Spatial Analyst)",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/analyze",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "analyze"
              ]
            },
            "description": "Translates a natural-language query into a SpatialAnalysisPlan via an LLM planner, then forces the candidate through a deterministic validation gauntlet (schema → registered capabilities → required inputs → tier/cost) BEFORE anything executes. `execution: \"plan\"` returns the validated plan without executing; `execution: \"auto\"` additionally executes it deterministically through the capability layer and returns per-step outputs, validation records, provenance, and trust level. The LLM never invents spatial calculations and no LLM-generated code ever runs. LLM token cost is metered against the tenant and reported in `planner.token_cost_units`. Auto mode requires the `simulate` key scope, plus `optimize` when the plan contains an optimization step (403 otherwise).\n\n`POST /analyze`\n\n_operationId:_ `analyze`",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{api_key}}",
                  "type": "string"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"query\": \"\",\n  \"context\": {},\n  \"execution\": \"plan\",\n  \"narrative\": false\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [
            {
              "name": "200 Validated plan (plan mode) or executed plan (auto mode)",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{base_url}}/analyze",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "analyze"
                  ]
                },
                "description": "Translates a natural-language query into a SpatialAnalysisPlan via an LLM planner, then forces the candidate through a deterministic validation gauntlet (schema → registered capabilities → required inputs → tier/cost) BEFORE anything executes. `execution: \"plan\"` returns the validated plan without executing; `execution: \"auto\"` additionally executes it deterministically through the capability layer and returns per-step outputs, validation records, provenance, and trust level. The LLM never invents spatial calculations and no LLM-generated code ever runs. LLM token cost is metered against the tenant and reported in `planner.token_cost_units`. Auto mode requires the `simulate` key scope, plus `optimize` when the plan contains an optimization step (403 otherwise).\n\n`POST /analyze`\n\n_operationId:_ `analyze`",
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{api_key}}",
                      "type": "string"
                    }
                  ]
                },
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"query\": \"\",\n  \"context\": {},\n  \"execution\": \"plan\",\n  \"narrative\": false\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Validated plan (plan mode) or executed plan (auto mode)",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"mode\": \"plan\",\n  \"plan\": {\n    \"plan_id\": \"\",\n    \"schema_version\": \"\",\n    \"objective\": \"\",\n    \"status\": \"draft\",\n    \"steps\": [\n      {\n        \"capability_id\": \"\",\n        \"inputs\": {},\n        \"label\": \"\"\n      }\n    ],\n    \"assumptions\": [\n      \"\"\n    ],\n    \"required_data\": [\n      \"\"\n    ],\n    \"estimated_cost\": {},\n    \"validation\": {},\n    \"step_results\": [\n      {\n        \"step_index\": 0,\n        \"capability_id\": \"\",\n        \"label\": \"\",\n        \"status\": \"succeeded\",\n        \"validation\": {\n          \"capability_id\": \"\",\n          \"validated_at\": \"2026-04-21T03:14:22Z\",\n          \"checks\": [\n            {\n              \"check\": \"\",\n              \"status\": \"passed\",\n              \"detail\": \"\"\n            }\n          ],\n          \"passed\": false\n        },\n        \"provenance\": {\n          \"datasets\": [\n            {\n              \"source\": \"\",\n              \"version\": \"\",\n              \"stac_id\": \"\",\n              \"retrieved_at\": \"2026-04-21T03:14:22Z\",\n              \"crs\": \"\",\n              \"resolution_m\": 0.0,\n              \"fallback\": false\n            }\n          ],\n          \"calculation\": {\n            \"capability_id\": \"\",\n            \"implementation_version\": \"\",\n            \"parameters_hash\": \"\",\n            \"calibration_version\": \"\",\n            \"job_id\": \"\"\n          },\n          \"generated_at\": \"2026-04-21T03:14:22Z\"\n        },\n        \"trust_level\": \"VERIFIED\",\n        \"job_id\": \"\",\n        \"error\": {\n          \"code\": \"INVALID_REQUEST\",\n          \"message\": \"\",\n          \"retryable\": false,\n          \"detail\": {}\n        },\n        \"started_at\": \"2026-04-21T03:14:22Z\",\n        \"finished_at\": \"2026-04-21T03:14:22Z\"\n      }\n    ],\n    \"trust_level\": \"VERIFIED\",\n    \"created_at\": \"2026-04-21T03:14:22Z\",\n    \"executed_at\": \"2026-04-21T03:14:22Z\"\n  },\n  \"planner\": {\n    \"planner_version\": \"\",\n    \"model\": \"\",\n    \"tokens\": {\n      \"input\": 0,\n      \"output\": 0,\n      \"total\": 0\n    },\n    \"token_cost_units\": 0.0,\n    \"validation\": {}\n  },\n  \"narrative\": {\n    \"summary\": \"\",\n    \"based_on_steps\": [\n      0\n    ],\n    \"plan_id\": \"\",\n    \"generated_by\": \"\",\n    \"disclaimer\": \"\"\n  }\n}"
            }
          ]
        },
        {
          "name": "MCP server endpoint (Streamable HTTP, JSON-RPC 2.0)",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/mcp",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "mcp"
              ]
            },
            "description": "Model Context Protocol server exposing high-level spatial tools (get_spatial_context, find_nearby, find_within, get_elevation, get_terrain_profile, analyze_trajectory, calculate_route, calculate_evacuation_route, simulate_flood, list_capabilities, execute_analysis_plan) that delegate to the deterministic capability registry. Supports `initialize`, `ping`, `tools/list`, `tools/call`. Connect any MCP client with transport \"streamable-http\", URL `https://api.geog.ai/v1/mcp`, and an `Authorization: Bearer <key>` header — see the MCP guide in the docs. Tool calls enforce capability-aware key scopes: simulate_flood needs `simulate`, and execute_analysis_plan needs every scope its steps require (403 otherwise).\n\n`POST /mcp`\n\n_operationId:_ `mcpRpc`",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{api_key}}",
                  "type": "string"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"jsonrpc\": \"2.0\",\n  \"method\": \"\",\n  \"params\": {}\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [
            {
              "name": "200 JSON-RPC 2.0 response envelope",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{base_url}}/mcp",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "mcp"
                  ]
                },
                "description": "Model Context Protocol server exposing high-level spatial tools (get_spatial_context, find_nearby, find_within, get_elevation, get_terrain_profile, analyze_trajectory, calculate_route, calculate_evacuation_route, simulate_flood, list_capabilities, execute_analysis_plan) that delegate to the deterministic capability registry. Supports `initialize`, `ping`, `tools/list`, `tools/call`. Connect any MCP client with transport \"streamable-http\", URL `https://api.geog.ai/v1/mcp`, and an `Authorization: Bearer <key>` header — see the MCP guide in the docs. Tool calls enforce capability-aware key scopes: simulate_flood needs `simulate`, and execute_analysis_plan needs every scope its steps require (403 otherwise).\n\n`POST /mcp`\n\n_operationId:_ `mcpRpc`",
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{api_key}}",
                      "type": "string"
                    }
                  ]
                },
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"jsonrpc\": \"2.0\",\n  \"method\": \"\",\n  \"params\": {}\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "JSON-RPC 2.0 response envelope",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"jsonrpc\": \"2.0\",\n  \"result\": {},\n  \"error\": {\n    \"code\": 0,\n    \"message\": \"\",\n    \"data\": {}\n  }\n}"
            }
          ]
        }
      ]
    },
    {
      "name": "Plans",
      "description": "SpatialAnalysisPlan — serializable, auditable multi-step analysis plans executed deterministically through the capability layer, with per-step validation records, normalized provenance, and trust levels.",
      "item": [
        {
          "name": "List plans for the caller",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/plans",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "plans"
              ],
              "query": [
                {
                  "key": "limit",
                  "value": "50",
                  "description": "",
                  "disabled": true
                }
              ]
            },
            "description": "`GET /plans`\n\n_operationId:_ `listPlans`",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{api_key}}",
                  "type": "string"
                }
              ]
            }
          },
          "response": [
            {
              "name": "200 Plan list",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{base_url}}/plans",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "plans"
                  ],
                  "query": [
                    {
                      "key": "limit",
                      "value": "50",
                      "description": "",
                      "disabled": true
                    }
                  ]
                },
                "description": "`GET /plans`\n\n_operationId:_ `listPlans`",
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{api_key}}",
                      "type": "string"
                    }
                  ]
                }
              },
              "status": "Plan list",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"count\": 0,\n  \"plans\": [\n    {\n      \"plan_id\": \"\",\n      \"schema_version\": \"\",\n      \"objective\": \"\",\n      \"status\": \"draft\",\n      \"steps\": [\n        {\n          \"capability_id\": \"\",\n          \"inputs\": {},\n          \"label\": \"\"\n        }\n      ],\n      \"assumptions\": [\n        \"\"\n      ],\n      \"required_data\": [\n        \"\"\n      ],\n      \"estimated_cost\": {},\n      \"validation\": {},\n      \"step_results\": [\n        {\n          \"step_index\": 0,\n          \"capability_id\": \"\",\n          \"label\": \"\",\n          \"status\": \"succeeded\",\n          \"validation\": {\n            \"capability_id\": \"\",\n            \"validated_at\": \"2026-04-21T03:14:22Z\",\n            \"checks\": [\n              {\n                \"check\": \"\",\n                \"status\": \"passed\",\n                \"detail\": \"\"\n              }\n            ],\n            \"passed\": false\n          },\n          \"provenance\": {\n            \"datasets\": [\n              {\n                \"source\": \"\",\n                \"version\": \"\",\n                \"stac_id\": \"\",\n                \"retrieved_at\": \"2026-04-21T03:14:22Z\",\n                \"crs\": \"\",\n                \"resolution_m\": 0.0,\n                \"fallback\": false\n              }\n            ],\n            \"calculation\": {\n              \"capability_id\": \"\",\n              \"implementation_version\": \"\",\n              \"parameters_hash\": \"\",\n              \"calibration_version\": \"\",\n              \"job_id\": \"\"\n            },\n            \"generated_at\": \"2026-04-21T03:14:22Z\"\n          },\n          \"trust_level\": \"VERIFIED\",\n          \"job_id\": \"\",\n          \"error\": {\n            \"code\": \"INVALID_REQUEST\",\n            \"message\": \"\",\n            \"retryable\": false,\n            \"detail\": {}\n          },\n          \"started_at\": \"2026-04-21T03:14:22Z\",\n          \"finished_at\": \"2026-04-21T03:14:22Z\"\n        }\n      ],\n      \"trust_level\": \"VERIFIED\",\n      \"created_at\": \"2026-04-21T03:14:22Z\",\n      \"executed_at\": \"2026-04-21T03:14:22Z\"\n    }\n  ]\n}"
            }
          ]
        },
        {
          "name": "Create a SpatialAnalysisPlan",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/plans",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "plans"
              ]
            },
            "description": "Validates every step against the capability registry, computes the cost/tier estimate, and persists the plan as a draft. Plans are serializable, auditable, and executable independently of any LLM.\n\n`POST /plans`\n\n_operationId:_ `createPlan`",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{api_key}}",
                  "type": "string"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"objective\": \"\",\n  \"steps\": [\n    {\n      \"capability_id\": \"\",\n      \"inputs\": {},\n      \"label\": \"\"\n    }\n  ],\n  \"assumptions\": [\n    \"\"\n  ],\n  \"required_data\": [\n    \"\"\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [
            {
              "name": "201 Plan created (draft)",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{base_url}}/plans",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "plans"
                  ]
                },
                "description": "Validates every step against the capability registry, computes the cost/tier estimate, and persists the plan as a draft. Plans are serializable, auditable, and executable independently of any LLM.\n\n`POST /plans`\n\n_operationId:_ `createPlan`",
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{api_key}}",
                      "type": "string"
                    }
                  ]
                },
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"objective\": \"\",\n  \"steps\": [\n    {\n      \"capability_id\": \"\",\n      \"inputs\": {},\n      \"label\": \"\"\n    }\n  ],\n  \"assumptions\": [\n    \"\"\n  ],\n  \"required_data\": [\n    \"\"\n  ]\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Plan created (draft)",
              "code": 201,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"plan\": {\n    \"plan_id\": \"\",\n    \"schema_version\": \"\",\n    \"objective\": \"\",\n    \"status\": \"draft\",\n    \"steps\": [\n      {\n        \"capability_id\": \"\",\n        \"inputs\": {},\n        \"label\": \"\"\n      }\n    ],\n    \"assumptions\": [\n      \"\"\n    ],\n    \"required_data\": [\n      \"\"\n    ],\n    \"estimated_cost\": {},\n    \"validation\": {},\n    \"step_results\": [\n      {\n        \"step_index\": 0,\n        \"capability_id\": \"\",\n        \"label\": \"\",\n        \"status\": \"succeeded\",\n        \"validation\": {\n          \"capability_id\": \"\",\n          \"validated_at\": \"2026-04-21T03:14:22Z\",\n          \"checks\": [\n            {\n              \"check\": \"\",\n              \"status\": \"passed\",\n              \"detail\": \"\"\n            }\n          ],\n          \"passed\": false\n        },\n        \"provenance\": {\n          \"datasets\": [\n            {\n              \"source\": \"\",\n              \"version\": \"\",\n              \"stac_id\": \"\",\n              \"retrieved_at\": \"2026-04-21T03:14:22Z\",\n              \"crs\": \"\",\n              \"resolution_m\": 0.0,\n              \"fallback\": false\n            }\n          ],\n          \"calculation\": {\n            \"capability_id\": \"\",\n            \"implementation_version\": \"\",\n            \"parameters_hash\": \"\",\n            \"calibration_version\": \"\",\n            \"job_id\": \"\"\n          },\n          \"generated_at\": \"2026-04-21T03:14:22Z\"\n        },\n        \"trust_level\": \"VERIFIED\",\n        \"job_id\": \"\",\n        \"error\": {\n          \"code\": \"INVALID_REQUEST\",\n          \"message\": \"\",\n          \"retryable\": false,\n          \"detail\": {}\n        },\n        \"started_at\": \"2026-04-21T03:14:22Z\",\n        \"finished_at\": \"2026-04-21T03:14:22Z\"\n      }\n    ],\n    \"trust_level\": \"VERIFIED\",\n    \"created_at\": \"2026-04-21T03:14:22Z\",\n    \"executed_at\": \"2026-04-21T03:14:22Z\"\n  }\n}"
            }
          ]
        },
        {
          "name": "Plan detail (including step results)",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/plans/:plan_id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "plans",
                ":plan_id"
              ],
              "variable": [
                {
                  "key": "plan_id",
                  "value": "",
                  "description": ""
                }
              ]
            },
            "description": "`GET /plans/{plan_id}`\n\n_operationId:_ `getPlan`",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{api_key}}",
                  "type": "string"
                }
              ]
            }
          },
          "response": [
            {
              "name": "200 Plan detail",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{base_url}}/plans/:plan_id",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "plans",
                    ":plan_id"
                  ],
                  "variable": [
                    {
                      "key": "plan_id",
                      "value": "",
                      "description": ""
                    }
                  ]
                },
                "description": "`GET /plans/{plan_id}`\n\n_operationId:_ `getPlan`",
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{api_key}}",
                      "type": "string"
                    }
                  ]
                }
              },
              "status": "Plan detail",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"plan\": {\n    \"plan_id\": \"\",\n    \"schema_version\": \"\",\n    \"objective\": \"\",\n    \"status\": \"draft\",\n    \"steps\": [\n      {\n        \"capability_id\": \"\",\n        \"inputs\": {},\n        \"label\": \"\"\n      }\n    ],\n    \"assumptions\": [\n      \"\"\n    ],\n    \"required_data\": [\n      \"\"\n    ],\n    \"estimated_cost\": {},\n    \"validation\": {},\n    \"step_results\": [\n      {\n        \"step_index\": 0,\n        \"capability_id\": \"\",\n        \"label\": \"\",\n        \"status\": \"succeeded\",\n        \"validation\": {\n          \"capability_id\": \"\",\n          \"validated_at\": \"2026-04-21T03:14:22Z\",\n          \"checks\": [\n            {\n              \"check\": \"\",\n              \"status\": \"passed\",\n              \"detail\": \"\"\n            }\n          ],\n          \"passed\": false\n        },\n        \"provenance\": {\n          \"datasets\": [\n            {\n              \"source\": \"\",\n              \"version\": \"\",\n              \"stac_id\": \"\",\n              \"retrieved_at\": \"2026-04-21T03:14:22Z\",\n              \"crs\": \"\",\n              \"resolution_m\": 0.0,\n              \"fallback\": false\n            }\n          ],\n          \"calculation\": {\n            \"capability_id\": \"\",\n            \"implementation_version\": \"\",\n            \"parameters_hash\": \"\",\n            \"calibration_version\": \"\",\n            \"job_id\": \"\"\n          },\n          \"generated_at\": \"2026-04-21T03:14:22Z\"\n        },\n        \"trust_level\": \"VERIFIED\",\n        \"job_id\": \"\",\n        \"error\": {\n          \"code\": \"INVALID_REQUEST\",\n          \"message\": \"\",\n          \"retryable\": false,\n          \"detail\": {}\n        },\n        \"started_at\": \"2026-04-21T03:14:22Z\",\n        \"finished_at\": \"2026-04-21T03:14:22Z\"\n      }\n    ],\n    \"trust_level\": \"VERIFIED\",\n    \"created_at\": \"2026-04-21T03:14:22Z\",\n    \"executed_at\": \"2026-04-21T03:14:22Z\"\n  }\n}"
            }
          ]
        },
        {
          "name": "Execute a plan deterministically, step by step",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/plans/:plan_id/execute",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "plans",
                ":plan_id",
                "execute"
              ],
              "variable": [
                {
                  "key": "plan_id",
                  "value": "",
                  "description": ""
                }
              ]
            },
            "description": "Runs each capability step in order through the existing job/execution layer. Every intermediate step result — output, validation record, normalized provenance, trust level — is persisted and returned. A step failure stops execution with the machine-readable taxonomy error recorded on that step.\n\n`POST /plans/{plan_id}/execute`\n\n_operationId:_ `executePlan`",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{api_key}}",
                  "type": "string"
                }
              ]
            }
          },
          "response": [
            {
              "name": "200 Executed plan with per-step results",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{base_url}}/plans/:plan_id/execute",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "plans",
                    ":plan_id",
                    "execute"
                  ],
                  "variable": [
                    {
                      "key": "plan_id",
                      "value": "",
                      "description": ""
                    }
                  ]
                },
                "description": "Runs each capability step in order through the existing job/execution layer. Every intermediate step result — output, validation record, normalized provenance, trust level — is persisted and returned. A step failure stops execution with the machine-readable taxonomy error recorded on that step.\n\n`POST /plans/{plan_id}/execute`\n\n_operationId:_ `executePlan`",
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{api_key}}",
                      "type": "string"
                    }
                  ]
                }
              },
              "status": "Executed plan with per-step results",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"plan\": {\n    \"plan_id\": \"\",\n    \"schema_version\": \"\",\n    \"objective\": \"\",\n    \"status\": \"draft\",\n    \"steps\": [\n      {\n        \"capability_id\": \"\",\n        \"inputs\": {},\n        \"label\": \"\"\n      }\n    ],\n    \"assumptions\": [\n      \"\"\n    ],\n    \"required_data\": [\n      \"\"\n    ],\n    \"estimated_cost\": {},\n    \"validation\": {},\n    \"step_results\": [\n      {\n        \"step_index\": 0,\n        \"capability_id\": \"\",\n        \"label\": \"\",\n        \"status\": \"succeeded\",\n        \"validation\": {\n          \"capability_id\": \"\",\n          \"validated_at\": \"2026-04-21T03:14:22Z\",\n          \"checks\": [\n            {\n              \"check\": \"\",\n              \"status\": \"passed\",\n              \"detail\": \"\"\n            }\n          ],\n          \"passed\": false\n        },\n        \"provenance\": {\n          \"datasets\": [\n            {\n              \"source\": \"\",\n              \"version\": \"\",\n              \"stac_id\": \"\",\n              \"retrieved_at\": \"2026-04-21T03:14:22Z\",\n              \"crs\": \"\",\n              \"resolution_m\": 0.0,\n              \"fallback\": false\n            }\n          ],\n          \"calculation\": {\n            \"capability_id\": \"\",\n            \"implementation_version\": \"\",\n            \"parameters_hash\": \"\",\n            \"calibration_version\": \"\",\n            \"job_id\": \"\"\n          },\n          \"generated_at\": \"2026-04-21T03:14:22Z\"\n        },\n        \"trust_level\": \"VERIFIED\",\n        \"job_id\": \"\",\n        \"error\": {\n          \"code\": \"INVALID_REQUEST\",\n          \"message\": \"\",\n          \"retryable\": false,\n          \"detail\": {}\n        },\n        \"started_at\": \"2026-04-21T03:14:22Z\",\n        \"finished_at\": \"2026-04-21T03:14:22Z\"\n      }\n    ],\n    \"trust_level\": \"VERIFIED\",\n    \"created_at\": \"2026-04-21T03:14:22Z\",\n    \"executed_at\": \"2026-04-21T03:14:22Z\"\n  }\n}"
            }
          ]
        },
        {
          "name": "Intermediate step results for a plan",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/plans/:plan_id/steps",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "plans",
                ":plan_id",
                "steps"
              ],
              "variable": [
                {
                  "key": "plan_id",
                  "value": "",
                  "description": ""
                }
              ]
            },
            "description": "`GET /plans/{plan_id}/steps`\n\n_operationId:_ `getPlanSteps`",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{api_key}}",
                  "type": "string"
                }
              ]
            }
          },
          "response": [
            {
              "name": "200 Step results",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{base_url}}/plans/:plan_id/steps",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "plans",
                    ":plan_id",
                    "steps"
                  ],
                  "variable": [
                    {
                      "key": "plan_id",
                      "value": "",
                      "description": ""
                    }
                  ]
                },
                "description": "`GET /plans/{plan_id}/steps`\n\n_operationId:_ `getPlanSteps`",
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{api_key}}",
                      "type": "string"
                    }
                  ]
                }
              },
              "status": "Step results",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"plan_id\": \"\",\n  \"status\": \"\",\n  \"trust_level\": \"VERIFIED\",\n  \"step_results\": [\n    {\n      \"step_index\": 0,\n      \"capability_id\": \"\",\n      \"label\": \"\",\n      \"status\": \"succeeded\",\n      \"validation\": {\n        \"capability_id\": \"\",\n        \"validated_at\": \"2026-04-21T03:14:22Z\",\n        \"checks\": [\n          {\n            \"check\": \"\",\n            \"status\": \"passed\",\n            \"detail\": \"\"\n          }\n        ],\n        \"passed\": false\n      },\n      \"provenance\": {\n        \"datasets\": [\n          {\n            \"source\": \"\",\n            \"version\": \"\",\n            \"stac_id\": \"\",\n            \"retrieved_at\": \"2026-04-21T03:14:22Z\",\n            \"crs\": \"\",\n            \"resolution_m\": 0.0,\n            \"fallback\": false\n          }\n        ],\n        \"calculation\": {\n          \"capability_id\": \"\",\n          \"implementation_version\": \"\",\n          \"parameters_hash\": \"\",\n          \"calibration_version\": \"\",\n          \"job_id\": \"\"\n        },\n        \"generated_at\": \"2026-04-21T03:14:22Z\"\n      },\n      \"trust_level\": \"VERIFIED\",\n      \"job_id\": \"\",\n      \"error\": {\n        \"code\": \"INVALID_REQUEST\",\n        \"message\": \"\",\n        \"retryable\": false,\n        \"detail\": {}\n      },\n      \"started_at\": \"2026-04-21T03:14:22Z\",\n      \"finished_at\": \"2026-04-21T03:14:22Z\"\n    }\n  ]\n}"
            }
          ]
        }
      ]
    },
    {
      "name": "Webhooks",
      "description": "Register HTTPS callbacks to receive async job results, signed with HMAC-SHA256.\n\n## Event payloads\n\nEvery delivery, regardless of event type, uses the same JSON envelope —\n`{ ok, event, result, meta }` — where `event` matches the\n`X-Geog-Event` header and `result` is a per-event payload. Receivers\nshould dispatch on `event` and parse `result` against the matching\nschema:\n\n| `event` | `result` schema |\n| --- | --- |\n| `job.complete` | [`JobEventPayload`](#tag/Webhooks/JobEventPayload) (`status=\"complete\"`, `result.result` populated) — full body schema: [`JobCompleteEvent`](#tag/Webhooks/JobCompleteEvent) |\n| `job.failed` | [`JobEventPayload`](#tag/Webhooks/JobEventPayload) (`status=\"failed\"`, `error` populated) — full body schema: [`JobFailedEvent`](#tag/Webhooks/JobFailedEvent) |\n| `calibration.updated` | [`CalibrationUpdatedPayload`](#tag/Webhooks/CalibrationUpdatedPayload) — full body schema: [`CalibrationUpdatedEvent`](#tag/Webhooks/CalibrationUpdatedEvent) |\n| `webhook.disabled` | [`WebhookDisabledPayload`](#tag/Webhooks/WebhookDisabledPayload) — same shape as `GET /webhooks/{id}/health` (`WebhookHealth`), so receivers do not need a follow-up health call. Full body schema: [`WebhookDisabledEvent`](#tag/Webhooks/WebhookDisabledEvent) |\n\nThe discriminated union of all four POST body shapes is\n[`WebhookEventDelivery`](#tag/Webhooks/WebhookEventDelivery).\n",
      "item": [
        {
          "name": "List all registered webhooks for the account",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/webhooks",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "webhooks"
              ],
              "query": [
                {
                  "key": "active",
                  "value": "False",
                  "description": "If supplied, filters the result to only active (`true`) or paused (`false`) webhooks.",
                  "disabled": true
                }
              ]
            },
            "description": "Returns every webhook registered on the calling account, ordered by `created_at` descending.\nThe signing `secret` is **never** returned by this endpoint — it is only available on the\ninitial `POST /webhooks` response. To rotate a secret, delete the webhook and register a new one.\n\n`GET /webhooks`\n\n_operationId:_ `listWebhooks`",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{api_key}}",
                  "type": "string"
                }
              ]
            }
          },
          "response": [
            {
              "name": "200 Array of webhook records (without `secret`).",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{base_url}}/webhooks",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "webhooks"
                  ],
                  "query": [
                    {
                      "key": "active",
                      "value": "False",
                      "description": "If supplied, filters the result to only active (`true`) or paused (`false`) webhooks.",
                      "disabled": true
                    }
                  ]
                },
                "description": "Returns every webhook registered on the calling account, ordered by `created_at` descending.\nThe signing `secret` is **never** returned by this endpoint — it is only available on the\ninitial `POST /webhooks` response. To rotate a secret, delete the webhook and register a new one.\n\n`GET /webhooks`\n\n_operationId:_ `listWebhooks`",
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{api_key}}",
                      "type": "string"
                    }
                  ]
                }
              },
              "status": "Array of webhook records (without `secret`).",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"ok\": true,\n  \"result\": [\n    {\n      \"id\": \"whk_01hx2f8q7n3tdvm5j\",\n      \"url\": \"https://api.acme.com/hooks/geog\",\n      \"events\": [\n        \"job.complete\",\n        \"job.failed\",\n        \"webhook.disabled\"\n      ],\n      \"description\": \"Production plume results \\u2192 SOC pipeline\",\n      \"active\": true,\n      \"disabled_at\": null,\n      \"created_at\": \"2026-04-21T03:14:22Z\"\n    },\n    {\n      \"id\": \"whk_01hx2f9r1k4uxwn6m\",\n      \"url\": \"https://api.acme.com/hooks/geog-staging\",\n      \"events\": [\n        \"job.complete\"\n      ],\n      \"description\": \"Staging mirror\",\n      \"active\": false,\n      \"disabled_at\": \"2026-04-21T03:48:11Z\",\n      \"disabled_reason\": \"auto_failure_rate\",\n      \"created_at\": \"2026-04-15T09:02:11Z\"\n    }\n  ],\n  \"meta\": {\n    \"confidence\": 1.0,\n    \"model_version\": \"webhooks-v1.0.0\",\n    \"calibration_age_days\": 0,\n    \"site_calibrated\": true,\n    \"provenance\": [\n      \"registry:tenant-2026-04-21\"\n    ],\n    \"request_id\": \"req_01hx29sknd4bqyt8r\",\n    \"latency_ms\": 22\n  }\n}"
            }
          ]
        },
        {
          "name": "Register a webhook endpoint to receive async job results",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/webhooks",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "webhooks"
              ]
            },
            "description": "Registers an HTTPS callback URL on your account. Once registered, every async job your\naccount creates (`/simulate/*`, `/rf/mesh/viability`, `/rf/optimize/placement`,\n`/optimize/*`) will POST its full result envelope to this URL when it transitions to\n`complete` or `failed`. Per-job overrides can still be supplied via the `webhook_url`\nfield on the job request body.\n\n## Delivery payload\n\nEach delivery is a `POST` with `Content-Type: application/json` containing the standard\n`{ ok, event, result, meta }` envelope. The shape of `result` depends on `event` — see\nthe per-event schemas at the top of the [Webhooks tag](#tag/Webhooks): `JobCompleteEvent`,\n`JobFailedEvent`, `CalibrationUpdatedEvent`, and `WebhookDisabledEvent` (the discriminated\nunion is `WebhookEventDelivery`). For `job.complete` and `job.failed`, `result` is the\nsame body returned by `GET /jobs/{job_id}` once the job has reached a terminal state.\n\nThe following headers are always set on the delivery:\n\n| Header | Description |\n| --- | --- |\n| `X-Geog-Signature` | Hex-encoded HMAC-SHA256 of `{timestamp}.{raw_body}` using the webhook secret. Format: `t=<unix_ts>,v1=<hex_digest>` |\n| `X-Geog-Event` | Event type (`job.complete`, `job.failed`, `calibration.updated`, `webhook.disabled`). Always matches the `event` field in the body. |\n| `X-Geog-Delivery` | Unique delivery ID — safe to use for idempotency on the receiver side |\n| `X-Geog-Webhook-Id` | ID of the registered webhook that produced this delivery |\n| `X-Geog-Test` | Present and set to `true` only on deliveries produced by `POST /webhooks/{id}/test`. Absent on real job-driven deliveries — receivers can use it to short-circuit production side-effects for synthetic traffic |\n\n## Verifying the signature (HMAC-SHA256)\n\n1. Read the `X-Geog-Signature` header and parse the comma-separated `t=` (unix timestamp,\n   seconds) and `v1=` (hex digest) parts.\n2. Reject the delivery if `|now - t| > 300` seconds to mitigate replay attacks.\n3. Concatenate `t`, a literal `.`, and the raw request body bytes.\n4. Compute `HMAC-SHA256(secret, payload).hexdigest()` and compare it to `v1` using a\n   constant-time comparison (e.g. `hmac.compare_digest`). Reject on mismatch.\n\n## Retry behaviour\n\nNon-2xx responses (or no response within 10 seconds) trigger automatic retries with\nexponential backoff at 30s, 2m, 10m, 30m, 2h, 6h, and 24h. After 7 failed attempts the\ndelivery is marked `undeliverable`. If 50% of deliveries in the last hour have failed\nthe webhook is automatically disabled (`active=false`, `disabled_reason=auto_failure_rate`)\nand an email is sent to the account owner. To detect this auto-disable programmatically\nrather than relying on the owner's inbox, either subscribe to the `webhook.disabled`\nevent (delivered on the final attempt before the webhook is paused — best subscribed on\na separately-monitored receiver) or poll `GET /webhooks/{id}/health`, which returns the\ncurrent rolling-hour failure rate, the auto-disable threshold, and the `disabled_at`\ntimestamp once tripped. All deliveries (including failures) are visible on the dashboard\nfor 30 days.\n\n`POST /webhooks`\n\n_operationId:_ `registerWebhook`",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{api_key}}",
                  "type": "string"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"url\": \"https://api.acme.com/hooks/geog\",\n  \"events\": [\n    \"job.complete\",\n    \"job.failed\",\n    \"webhook.disabled\"\n  ],\n  \"description\": \"Production plume results \\u2192 SOC pipeline\",\n  \"active\": true\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [
            {
              "name": "200 Webhook registered successfully. The `secret` field is retur",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{base_url}}/webhooks",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "webhooks"
                  ]
                },
                "description": "Registers an HTTPS callback URL on your account. Once registered, every async job your\naccount creates (`/simulate/*`, `/rf/mesh/viability`, `/rf/optimize/placement`,\n`/optimize/*`) will POST its full result envelope to this URL when it transitions to\n`complete` or `failed`. Per-job overrides can still be supplied via the `webhook_url`\nfield on the job request body.\n\n## Delivery payload\n\nEach delivery is a `POST` with `Content-Type: application/json` containing the standard\n`{ ok, event, result, meta }` envelope. The shape of `result` depends on `event` — see\nthe per-event schemas at the top of the [Webhooks tag](#tag/Webhooks): `JobCompleteEvent`,\n`JobFailedEvent`, `CalibrationUpdatedEvent`, and `WebhookDisabledEvent` (the discriminated\nunion is `WebhookEventDelivery`). For `job.complete` and `job.failed`, `result` is the\nsame body returned by `GET /jobs/{job_id}` once the job has reached a terminal state.\n\nThe following headers are always set on the delivery:\n\n| Header | Description |\n| --- | --- |\n| `X-Geog-Signature` | Hex-encoded HMAC-SHA256 of `{timestamp}.{raw_body}` using the webhook secret. Format: `t=<unix_ts>,v1=<hex_digest>` |\n| `X-Geog-Event` | Event type (`job.complete`, `job.failed`, `calibration.updated`, `webhook.disabled`). Always matches the `event` field in the body. |\n| `X-Geog-Delivery` | Unique delivery ID — safe to use for idempotency on the receiver side |\n| `X-Geog-Webhook-Id` | ID of the registered webhook that produced this delivery |\n| `X-Geog-Test` | Present and set to `true` only on deliveries produced by `POST /webhooks/{id}/test`. Absent on real job-driven deliveries — receivers can use it to short-circuit production side-effects for synthetic traffic |\n\n## Verifying the signature (HMAC-SHA256)\n\n1. Read the `X-Geog-Signature` header and parse the comma-separated `t=` (unix timestamp,\n   seconds) and `v1=` (hex digest) parts.\n2. Reject the delivery if `|now - t| > 300` seconds to mitigate replay attacks.\n3. Concatenate `t`, a literal `.`, and the raw request body bytes.\n4. Compute `HMAC-SHA256(secret, payload).hexdigest()` and compare it to `v1` using a\n   constant-time comparison (e.g. `hmac.compare_digest`). Reject on mismatch.\n\n## Retry behaviour\n\nNon-2xx responses (or no response within 10 seconds) trigger automatic retries with\nexponential backoff at 30s, 2m, 10m, 30m, 2h, 6h, and 24h. After 7 failed attempts the\ndelivery is marked `undeliverable`. If 50% of deliveries in the last hour have failed\nthe webhook is automatically disabled (`active=false`, `disabled_reason=auto_failure_rate`)\nand an email is sent to the account owner. To detect this auto-disable programmatically\nrather than relying on the owner's inbox, either subscribe to the `webhook.disabled`\nevent (delivered on the final attempt before the webhook is paused — best subscribed on\na separately-monitored receiver) or poll `GET /webhooks/{id}/health`, which returns the\ncurrent rolling-hour failure rate, the auto-disable threshold, and the `disabled_at`\ntimestamp once tripped. All deliveries (including failures) are visible on the dashboard\nfor 30 days.\n\n`POST /webhooks`\n\n_operationId:_ `registerWebhook`",
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{api_key}}",
                      "type": "string"
                    }
                  ]
                },
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"url\": \"https://api.acme.com/hooks/geog\",\n  \"events\": [\n    \"job.complete\",\n    \"job.failed\",\n    \"webhook.disabled\"\n  ],\n  \"description\": \"Production plume results \\u2192 SOC pipeline\",\n  \"active\": true\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Webhook registered successfully. The `secret` field is returned only on this initial response.",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"ok\": true,\n  \"result\": {\n    \"id\": \"whk_01hx2f8q7n3tdvm5j\",\n    \"url\": \"https://api.acme.com/hooks/geog\",\n    \"events\": [\n      \"job.complete\",\n      \"job.failed\",\n      \"webhook.disabled\"\n    ],\n    \"description\": \"Production plume results \\u2192 SOC pipeline\",\n    \"active\": true,\n    \"disabled_at\": null,\n    \"secret\": \"whsec_8k3Jq2pNvR7tYxL4mZ9cFwH1bD5sQ6aU\",\n    \"created_at\": \"2026-04-21T03:14:22Z\"\n  },\n  \"meta\": {\n    \"confidence\": 1.0,\n    \"model_version\": \"webhooks-v1.0.0\",\n    \"calibration_age_days\": 0,\n    \"site_calibrated\": true,\n    \"provenance\": [\n      \"registry:tenant-2026-04-21\"\n    ],\n    \"request_id\": \"req_01hx29sknd4bqyt8r\",\n    \"latency_ms\": 27\n  }\n}"
            }
          ]
        },
        {
          "name": "Retrieve a single registered webhook",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/webhooks/:webhook_id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "webhooks",
                ":webhook_id"
              ],
              "variable": [
                {
                  "key": "webhook_id",
                  "value": "",
                  "description": ""
                }
              ]
            },
            "description": "Returns the current configuration of one webhook. The signing `secret` is **not**\nreturned — it is only available on the original `POST /webhooks` response. Rotate by\ndeleting and re-registering.\n\n`GET /webhooks/{webhook_id}`\n\n_operationId:_ `getWebhook`",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{api_key}}",
                  "type": "string"
                }
              ]
            }
          },
          "response": [
            {
              "name": "200 Webhook record (without `secret`).",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{base_url}}/webhooks/:webhook_id",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "webhooks",
                    ":webhook_id"
                  ],
                  "variable": [
                    {
                      "key": "webhook_id",
                      "value": "",
                      "description": ""
                    }
                  ]
                },
                "description": "Returns the current configuration of one webhook. The signing `secret` is **not**\nreturned — it is only available on the original `POST /webhooks` response. Rotate by\ndeleting and re-registering.\n\n`GET /webhooks/{webhook_id}`\n\n_operationId:_ `getWebhook`",
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{api_key}}",
                      "type": "string"
                    }
                  ]
                }
              },
              "status": "Webhook record (without `secret`).",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"ok\": true,\n  \"result\": {\n    \"id\": \"whk_01hx2f8q7n3tdvm5j\",\n    \"url\": \"https://api.acme.com/hooks/geog\",\n    \"events\": [\n      \"job.complete\",\n      \"job.failed\",\n      \"webhook.disabled\"\n    ],\n    \"description\": \"Production plume results \\u2192 SOC pipeline\",\n    \"active\": true,\n    \"disabled_at\": null,\n    \"created_at\": \"2026-04-21T03:14:22Z\"\n  },\n  \"meta\": {\n    \"confidence\": 1.0,\n    \"model_version\": \"webhooks-v1.0.0\",\n    \"calibration_age_days\": 0,\n    \"site_calibrated\": true,\n    \"provenance\": [\n      \"registry:tenant-2026-04-21\"\n    ],\n    \"request_id\": \"req_01hx29sknd4bqyt8r\",\n    \"latency_ms\": 19\n  }\n}"
            }
          ]
        },
        {
          "name": "Update a registered webhook",
          "request": {
            "method": "PATCH",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/webhooks/:webhook_id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "webhooks",
                ":webhook_id"
              ],
              "variable": [
                {
                  "key": "webhook_id",
                  "value": "",
                  "description": ""
                }
              ]
            },
            "description": "Partially updates a webhook. Send only the fields you want to change. Common uses:\ntoggling `active` to pause/resume deliveries, re-pointing `url` after a backend\nmigration, or narrowing the subscribed `events`.\n\nThe signing `secret` cannot be changed via this endpoint. To rotate it, `DELETE` the\nwebhook and register a new one with `POST /webhooks` — store the new secret from that\nresponse, then cut over your verification code.\n\n`PATCH /webhooks/{webhook_id}`\n\n_operationId:_ `updateWebhook`",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{api_key}}",
                  "type": "string"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"url\": \"https://api.acme.com/hooks/geog-v2\",\n  \"events\": [\n    \"job.complete\",\n    \"job.failed\",\n    \"webhook.disabled\"\n  ],\n  \"description\": \"Production plume results \\u2192 SOC pipeline (v2)\",\n  \"active\": false\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [
            {
              "name": "200 Updated webhook record (without `secret`).",
              "originalRequest": {
                "method": "PATCH",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{base_url}}/webhooks/:webhook_id",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "webhooks",
                    ":webhook_id"
                  ],
                  "variable": [
                    {
                      "key": "webhook_id",
                      "value": "",
                      "description": ""
                    }
                  ]
                },
                "description": "Partially updates a webhook. Send only the fields you want to change. Common uses:\ntoggling `active` to pause/resume deliveries, re-pointing `url` after a backend\nmigration, or narrowing the subscribed `events`.\n\nThe signing `secret` cannot be changed via this endpoint. To rotate it, `DELETE` the\nwebhook and register a new one with `POST /webhooks` — store the new secret from that\nresponse, then cut over your verification code.\n\n`PATCH /webhooks/{webhook_id}`\n\n_operationId:_ `updateWebhook`",
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{api_key}}",
                      "type": "string"
                    }
                  ]
                },
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"url\": \"https://api.acme.com/hooks/geog-v2\",\n  \"events\": [\n    \"job.complete\",\n    \"job.failed\",\n    \"webhook.disabled\"\n  ],\n  \"description\": \"Production plume results \\u2192 SOC pipeline (v2)\",\n  \"active\": false\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Updated webhook record (without `secret`).",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"ok\": true,\n  \"result\": {\n    \"id\": \"whk_01hx2f8q7n3tdvm5j\",\n    \"url\": \"https://api.acme.com/hooks/geog-v2\",\n    \"events\": [\n      \"job.complete\",\n      \"job.failed\",\n      \"webhook.disabled\"\n    ],\n    \"description\": \"Production plume results \\u2192 SOC pipeline (v2)\",\n    \"active\": false,\n    \"disabled_at\": \"2026-04-21T03:48:11Z\",\n    \"disabled_reason\": \"manual\",\n    \"created_at\": \"2026-04-21T03:14:22Z\"\n  },\n  \"meta\": {\n    \"confidence\": 1.0,\n    \"model_version\": \"webhooks-v1.0.0\",\n    \"calibration_age_days\": 0,\n    \"site_calibrated\": true,\n    \"provenance\": [\n      \"registry:tenant-2026-04-21\"\n    ],\n    \"request_id\": \"req_01hx29sknd4bqyt8r\",\n    \"latency_ms\": 24\n  }\n}"
            }
          ]
        },
        {
          "name": "Delete a registered webhook",
          "request": {
            "method": "DELETE",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/webhooks/:webhook_id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "webhooks",
                ":webhook_id"
              ],
              "variable": [
                {
                  "key": "webhook_id",
                  "value": "",
                  "description": ""
                }
              ]
            },
            "description": "Permanently removes a webhook. Deliveries already in flight may still arrive briefly,\nbut no new deliveries will be queued. Use this to revoke a leaked endpoint or to rotate\nthe signing secret (delete, then `POST /webhooks` to register a fresh one).\n\n`DELETE /webhooks/{webhook_id}`\n\n_operationId:_ `deleteWebhook`",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{api_key}}",
                  "type": "string"
                }
              ]
            }
          },
          "response": []
        },
        {
          "name": "Send a synthetic event to a webhook to verify the receiver",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/webhooks/:id/test",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "webhooks",
                ":id",
                "test"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "",
                  "description": "Webhook identifier returned from `POST /webhooks` (prefix `whk_`)."
                }
              ]
            },
            "description": "Generates a synthetic delivery for the registered webhook and POSTs it to the URL\nexactly as a real event would be sent — same envelope shape, same `X-Geog-Signature`\nHMAC, same retry rules. Designed for day-one verification of a brand-new receiver\nbefore any real job has run: confirm that the URL is reachable, the TLS certificate\nis valid, and the receiver's signature-verification code accepts the payload.\n\n## Distinguishing test deliveries\n\nTest deliveries carry an additional `X-Geog-Test: true` header on the outbound POST,\nand the resulting `WebhookDelivery` record reports `test: true`. The synthetic\n`job_id` is prefixed `job_test_` so it cannot collide with a real job. Either signal\nis safe to gate on; the header is recommended so the receiver can short-circuit\nproduction side-effects (alerting, billing, downstream writes) before parsing the\nbody.\n\nTest deliveries appear in `GET /webhooks/{id}/deliveries` alongside real ones, are\nsubject to the same retry schedule and auto-disable rules, and are throttled to 60\ntest deliveries per webhook per hour (`TEST_RATE_LIMITED`).\n\n`POST /webhooks/{id}/test`\n\n_operationId:_ `sendWebhookTestEvent`",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{api_key}}",
                  "type": "string"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"event\": \"job.complete\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [
            {
              "name": "202 Test delivery accepted and queued. The returned `WebhookDeli",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{base_url}}/webhooks/:id/test",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "webhooks",
                    ":id",
                    "test"
                  ],
                  "variable": [
                    {
                      "key": "id",
                      "value": "",
                      "description": "Webhook identifier returned from `POST /webhooks` (prefix `whk_`)."
                    }
                  ]
                },
                "description": "Generates a synthetic delivery for the registered webhook and POSTs it to the URL\nexactly as a real event would be sent — same envelope shape, same `X-Geog-Signature`\nHMAC, same retry rules. Designed for day-one verification of a brand-new receiver\nbefore any real job has run: confirm that the URL is reachable, the TLS certificate\nis valid, and the receiver's signature-verification code accepts the payload.\n\n## Distinguishing test deliveries\n\nTest deliveries carry an additional `X-Geog-Test: true` header on the outbound POST,\nand the resulting `WebhookDelivery` record reports `test: true`. The synthetic\n`job_id` is prefixed `job_test_` so it cannot collide with a real job. Either signal\nis safe to gate on; the header is recommended so the receiver can short-circuit\nproduction side-effects (alerting, billing, downstream writes) before parsing the\nbody.\n\nTest deliveries appear in `GET /webhooks/{id}/deliveries` alongside real ones, are\nsubject to the same retry schedule and auto-disable rules, and are throttled to 60\ntest deliveries per webhook per hour (`TEST_RATE_LIMITED`).\n\n`POST /webhooks/{id}/test`\n\n_operationId:_ `sendWebhookTestEvent`",
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{api_key}}",
                      "type": "string"
                    }
                  ]
                },
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"event\": \"job.complete\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Test delivery accepted and queued. The returned `WebhookDelivery` reflects the new `pending` state with `test: true`.",
              "code": 202,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"ok\": true,\n  \"result\": {\n    \"id\": \"whd_01hx2g4n8p7rqzm3k\",\n    \"webhook_id\": \"whk_01hx2f8q7n3tdvm5j\",\n    \"event\": \"job.complete\",\n    \"job_id\": \"job_test_01hx2a3f9k8qmzn7p\",\n    \"status\": \"pending\",\n    \"attempt_count\": 1,\n    \"response_code\": null,\n    \"response_ms\": null,\n    \"response_body_excerpt\": null,\n    \"error\": null,\n    \"signature_timestamp\": 1745211262,\n    \"created_at\": \"2026-04-21T03:14:22Z\",\n    \"last_attempt_at\": null,\n    \"delivered_at\": null,\n    \"next_attempt_at\": \"2026-04-21T03:14:22Z\",\n    \"test\": true\n  },\n  \"meta\": {\n    \"confidence\": 1.0,\n    \"model_version\": \"webhooks-v1.0.0\",\n    \"calibration_age_days\": 0,\n    \"site_calibrated\": true,\n    \"provenance\": [\n      \"registry:tenant-2026-04-21\"\n    ],\n    \"request_id\": \"req_01hx29sknd4bqyt8r\",\n    \"latency_ms\": 33\n  }\n}"
            }
          ]
        },
        {
          "name": "List recent deliveries for a webhook",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/webhooks/:id/deliveries",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "webhooks",
                ":id",
                "deliveries"
              ],
              "query": [
                {
                  "key": "status",
                  "value": "failed",
                  "description": "Filter results to a single delivery status. Default returns all statuses.",
                  "disabled": true
                },
                {
                  "key": "event",
                  "value": "job.complete",
                  "description": "Filter results to a single event type.",
                  "disabled": true
                },
                {
                  "key": "test",
                  "value": "True",
                  "description": "Filter by delivery origin. `true` returns only synthetic deliveries produced\nby `POST /webhooks/{id}/test`; `false` returns only real job-driven\ndeliveries. Omit (the default) to return both kinds.\n\nComposes with `status` and `event` using AND semantics — for example,\n`?test=true&status=failed` returns only failed test deliveries, useful when\nverifying a brand-new receiver without scrolling past real job results.\n",
                  "disabled": true
                },
                {
                  "key": "created_after",
                  "value": "2026-04-21T02:00:00Z",
                  "description": "Inclusive lower bound on the delivery's `created_at` timestamp (ISO 8601, UTC).\nOnly deliveries first queued at or after this instant are returned.\n\nComposes with `status`, `event`, and `test` using AND semantics — for example,\n`?status=failed&created_after=2026-04-21T02:00:00Z&created_before=2026-04-21T03:00:00Z`\nreturns only failed deliveries queued during that one-hour window, useful for\nscoping a debug session to a known outage. Bounded by the 30-day retention window.\n",
                  "disabled": true
                },
                {
                  "key": "created_before",
                  "value": "2026-04-21T03:00:00Z",
                  "description": "Exclusive upper bound on the delivery's `created_at` timestamp (ISO 8601, UTC).\nOnly deliveries first queued strictly before this instant are returned.\n\nMay be combined with `created_after` to define a closed-open `[after, before)`\nrange, or used on its own to scope to \"everything older than X\". Composes with\n`status`, `event`, and `test` using AND semantics, identical to the other filters.\n",
                  "disabled": true
                },
                {
                  "key": "limit",
                  "value": "25",
                  "description": "Page size (max 100).",
                  "disabled": true
                },
                {
                  "key": "cursor",
                  "value": "",
                  "description": "Opaque pagination cursor returned as `meta.next_cursor` on the previous page. Omit for the first page.",
                  "disabled": true
                }
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "",
                  "description": "Webhook identifier returned from `POST /webhooks` (prefix `whk_`)."
                }
              ]
            },
            "description": "Returns a paginated list of delivery attempts for the given webhook, newest first.\nMirrors the delivery log shown on the dashboard and is intended for debugging\nreceiver-side bugs without waiting for the next real job.\n\nDeliveries are retained for 30 days; older records return an empty page rather than\nan error. Use the `status` filter to narrow to actively-failing deliveries you may\nwant to replay after fixing your handler.\n\n`GET /webhooks/{id}/deliveries`\n\n_operationId:_ `listWebhookDeliveries`",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{api_key}}",
                  "type": "string"
                }
              ]
            }
          },
          "response": [
            {
              "name": "200 Page of webhook deliveries, newest first.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{base_url}}/webhooks/:id/deliveries",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "webhooks",
                    ":id",
                    "deliveries"
                  ],
                  "query": [
                    {
                      "key": "status",
                      "value": "failed",
                      "description": "Filter results to a single delivery status. Default returns all statuses.",
                      "disabled": true
                    },
                    {
                      "key": "event",
                      "value": "job.complete",
                      "description": "Filter results to a single event type.",
                      "disabled": true
                    },
                    {
                      "key": "test",
                      "value": "True",
                      "description": "Filter by delivery origin. `true` returns only synthetic deliveries produced\nby `POST /webhooks/{id}/test`; `false` returns only real job-driven\ndeliveries. Omit (the default) to return both kinds.\n\nComposes with `status` and `event` using AND semantics — for example,\n`?test=true&status=failed` returns only failed test deliveries, useful when\nverifying a brand-new receiver without scrolling past real job results.\n",
                      "disabled": true
                    },
                    {
                      "key": "created_after",
                      "value": "2026-04-21T02:00:00Z",
                      "description": "Inclusive lower bound on the delivery's `created_at` timestamp (ISO 8601, UTC).\nOnly deliveries first queued at or after this instant are returned.\n\nComposes with `status`, `event`, and `test` using AND semantics — for example,\n`?status=failed&created_after=2026-04-21T02:00:00Z&created_before=2026-04-21T03:00:00Z`\nreturns only failed deliveries queued during that one-hour window, useful for\nscoping a debug session to a known outage. Bounded by the 30-day retention window.\n",
                      "disabled": true
                    },
                    {
                      "key": "created_before",
                      "value": "2026-04-21T03:00:00Z",
                      "description": "Exclusive upper bound on the delivery's `created_at` timestamp (ISO 8601, UTC).\nOnly deliveries first queued strictly before this instant are returned.\n\nMay be combined with `created_after` to define a closed-open `[after, before)`\nrange, or used on its own to scope to \"everything older than X\". Composes with\n`status`, `event`, and `test` using AND semantics, identical to the other filters.\n",
                      "disabled": true
                    },
                    {
                      "key": "limit",
                      "value": "25",
                      "description": "Page size (max 100).",
                      "disabled": true
                    },
                    {
                      "key": "cursor",
                      "value": "",
                      "description": "Opaque pagination cursor returned as `meta.next_cursor` on the previous page. Omit for the first page.",
                      "disabled": true
                    }
                  ],
                  "variable": [
                    {
                      "key": "id",
                      "value": "",
                      "description": "Webhook identifier returned from `POST /webhooks` (prefix `whk_`)."
                    }
                  ]
                },
                "description": "Returns a paginated list of delivery attempts for the given webhook, newest first.\nMirrors the delivery log shown on the dashboard and is intended for debugging\nreceiver-side bugs without waiting for the next real job.\n\nDeliveries are retained for 30 days; older records return an empty page rather than\nan error. Use the `status` filter to narrow to actively-failing deliveries you may\nwant to replay after fixing your handler.\n\n`GET /webhooks/{id}/deliveries`\n\n_operationId:_ `listWebhookDeliveries`",
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{api_key}}",
                      "type": "string"
                    }
                  ]
                }
              },
              "status": "Page of webhook deliveries, newest first.",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"ok\": true,\n  \"result\": [\n    {\n      \"id\": \"whd_01hx2g4n8p7rqzm3k\",\n      \"webhook_id\": \"whk_01hx2f8q7n3tdvm5j\",\n      \"event\": \"job.complete\",\n      \"job_id\": \"job_01hx2a3f9k8qmzn7p\",\n      \"status\": \"failed\",\n      \"attempt_count\": 3,\n      \"response_code\": 502,\n      \"response_ms\": 482,\n      \"response_body_excerpt\": \"<html><head><title>502 Bad Gateway</title></head>...\",\n      \"error\": null,\n      \"signature_timestamp\": 1745211262,\n      \"created_at\": \"2026-04-21T03:14:22Z\",\n      \"last_attempt_at\": \"2026-04-21T03:24:51Z\",\n      \"delivered_at\": null,\n      \"next_attempt_at\": \"2026-04-21T03:34:51Z\",\n      \"test\": false\n    },\n    {\n      \"id\": \"whd_01hx2g4n8p7rqzm3l\",\n      \"webhook_id\": \"whk_01hx2f8q7n3tdvm5j\",\n      \"event\": \"job.complete\",\n      \"job_id\": \"job_01hx2a3f9k8qmzn7q\",\n      \"status\": \"success\",\n      \"attempt_count\": 1,\n      \"response_code\": 200,\n      \"response_ms\": 144,\n      \"response_body_excerpt\": \"{\\\"received\\\":true}\",\n      \"error\": null,\n      \"signature_timestamp\": 1745210500,\n      \"created_at\": \"2026-04-21T03:01:40Z\",\n      \"last_attempt_at\": \"2026-04-21T03:01:40Z\",\n      \"delivered_at\": \"2026-04-21T03:01:40Z\",\n      \"next_attempt_at\": null,\n      \"test\": false\n    }\n  ],\n  \"meta\": {\n    \"request_id\": \"req_01hx2g5p3q8wnzvr4\",\n    \"next_cursor\": \"eyJ0IjoxNzQ1MjEwMDAwLCJpZCI6IndoZF8wMWh4MmcxIn0\"\n  }\n}"
            }
          ]
        },
        {
          "name": "Export filtered deliveries as CSV",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/webhooks/:id/deliveries.csv",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "webhooks",
                ":id",
                "deliveries.csv"
              ],
              "query": [
                {
                  "key": "status",
                  "value": "failed",
                  "description": "Filter results to a single delivery status. Default returns all statuses. Identical semantics to the JSON endpoint.",
                  "disabled": true
                },
                {
                  "key": "event",
                  "value": "job.complete",
                  "description": "Filter results to a single event type. Identical semantics to the JSON endpoint.",
                  "disabled": true
                },
                {
                  "key": "test",
                  "value": "True",
                  "description": "Filter by delivery origin. `true` returns only synthetic deliveries\nproduced by `POST /webhooks/{id}/test`; `false` returns only real\njob-driven deliveries. Omit (the default) to return both kinds.\nComposes with `status` and `event` using AND semantics, identical to\nthe JSON endpoint.\n",
                  "disabled": true
                },
                {
                  "key": "created_after",
                  "value": "2026-04-21T02:00:00Z",
                  "description": "Inclusive lower bound on the delivery's `created_at` timestamp\n(ISO 8601, UTC). Identical semantics to the JSON endpoint —\nfor example, `?status=failed&created_after=2026-04-21T02:00:00Z&created_before=2026-04-21T03:00:00Z`\nexports only failed deliveries queued during that one-hour window,\nuseful for handing a teammate the exact slice that lines up with an\noutage.\n",
                  "disabled": true
                },
                {
                  "key": "created_before",
                  "value": "2026-04-21T03:00:00Z",
                  "description": "Exclusive upper bound on the delivery's `created_at` timestamp\n(ISO 8601, UTC). May be combined with `created_after` to define a\nclosed-open `[after, before)` range. Identical semantics to the JSON\nendpoint.\n",
                  "disabled": true
                },
                {
                  "key": "limit",
                  "value": "25",
                  "description": "Page size (max 100). Identical default and bounds to the JSON endpoint.",
                  "disabled": true
                },
                {
                  "key": "cursor",
                  "value": "",
                  "description": "Opaque pagination cursor returned in the `X-Next-Cursor` response\nheader on the previous page. Omit for the first page. The cursor\nformat is interchangeable with the JSON endpoint's `meta.next_cursor`.\n",
                  "disabled": true
                }
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "",
                  "description": "Webhook identifier returned from `POST /webhooks` (prefix `whk_`)."
                }
              ]
            },
            "description": "Returns the same filtered, paginated rows as `GET /webhooks/{id}/deliveries`,\nserialised as a CSV stream rather than a JSON envelope. Intended for one-off\nops investigations: pipe the response into a file, hand it to a teammate, or\npaste it into a spreadsheet without scripting against the JSON endpoint.\n\nThe response uses `Content-Type: text/csv; charset=utf-8` and is sent with\n`Content-Disposition: attachment; filename=\"deliveries-<webhook_id>.csv\"`\nso browsers and `curl -OJ` save it directly to disk.\n\n## CSV format\n\n- First row is a header. Columns are emitted in this fixed order, matching\n  the JSON `WebhookDelivery` fields:\n\n  `id,webhook_id,event,job_id,status,attempt_count,response_code,response_ms,response_body_excerpt,error,signature_timestamp,created_at,last_attempt_at,delivered_at,next_attempt_at,test`\n\n- Rows are newest-first, identical to the JSON ordering.\n- Values follow [RFC 4180](https://datatracker.ietf.org/doc/html/rfc4180):\n  fields containing commas, quotes, or newlines are wrapped in double quotes,\n  and embedded double quotes are doubled (`\"` → `\"\"`). The\n  `response_body_excerpt` column in particular often needs quoting.\n- JSON `null` values (e.g. `job_id` for non-job events, `delivered_at` while\n  still pending) are emitted as **empty fields**, not the literal string\n  `null`. The `test` boolean is emitted as `true` / `false`.\n- Timestamps are ISO 8601 UTC, identical to the JSON representation.\n- Line terminator is `\\r\\n`.\n\n## Filters\n\nHonours all the same query parameters as the JSON endpoint with identical\nAND semantics: `status`, `event`, `test`, `created_after`, `created_before`,\n`limit`, and `cursor`. The 30-day retention window applies — older rows are\nsimply absent from the CSV rather than producing an error.\n\n## Pagination\n\nCSV bodies cannot carry a JSON `meta` object, so the next-page cursor is\nreturned in the **`X-Next-Cursor` response header**. When there are no more\npages the header is omitted. To export every matching delivery, follow the\ncursor:\n\n```bash\ncursor=\"\"\nwhile :; do\n  resp=$(curl -sS -D - -H \"Authorization: Bearer $GEOG_KEY\" \\\n    \"https://api.geog.ai/v1/webhooks/$ID/deliveries.csv?status=failed${cursor:+&cursor=$cursor}\")\n  # append body (stripping the header row on subsequent pages) to the output file...\n  cursor=$(printf '%s' \"$resp\" | awk 'BEGIN{IGNORECASE=1} /^x-next-cursor:/ {print $2}' | tr -d '\\r')\n  [ -z \"$cursor\" ] && break\ndone\n```\n\nThe same `meta.request_id` value that the JSON endpoint returns is exposed\nas the `X-Request-Id` response header for support tickets.\n\n`GET /webhooks/{id}/deliveries.csv`\n\n_operationId:_ `exportWebhookDeliveriesCsv`",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{api_key}}",
                  "type": "string"
                }
              ]
            }
          },
          "response": []
        },
        {
          "name": "Re-send a previously attempted webhook delivery",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/webhooks/:id/deliveries/:delivery_id/replay",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "webhooks",
                ":id",
                "deliveries",
                ":delivery_id",
                "replay"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "",
                  "description": "Webhook identifier (prefix `whk_`)."
                },
                {
                  "key": "delivery_id",
                  "value": "",
                  "description": "Delivery identifier returned by `GET /webhooks/{id}/deliveries` (prefix `whd_`)."
                }
              ]
            },
            "description": "Re-queues a previously attempted delivery for immediate re-send to the webhook's\ncurrently registered URL. Useful after fixing a receiver-side bug — there is no need\nto wait for the next real job.\n\n**Replays use the original payload and signature timestamp.** The exact bytes that\nwere originally signed are re-sent, and the original `X-Geog-Signature` (including\nits `t=` value) and `X-Geog-Delivery` ID are reused. This means:\n\n- HMAC verification on the receiver behaves identically to the original delivery.\n- The 5-minute replay-window check (`|now - t| > 300`) **will reject the request**\n  if the original signature timestamp is older than 5 minutes. Receivers that need\n  to accept replays of old deliveries should relax this check for requests carrying\n  a known `X-Geog-Delivery` ID.\n- Idempotent receivers keyed on `X-Geog-Delivery` will naturally deduplicate.\n\nThe replay attempt counts toward the webhook's retry budget and the delivery's\n`attempt_count` is incremented. Calling replay on a delivery whose `status` is\nalready `pending` returns `409 DELIVERY_ALREADY_PENDING`.\n\n`POST /webhooks/{id}/deliveries/{delivery_id}/replay`\n\n_operationId:_ `replayWebhookDelivery`",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{api_key}}",
                  "type": "string"
                }
              ]
            }
          },
          "response": [
            {
              "name": "202 Replay accepted and queued. The returned `WebhookDelivery` r",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{base_url}}/webhooks/:id/deliveries/:delivery_id/replay",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "webhooks",
                    ":id",
                    "deliveries",
                    ":delivery_id",
                    "replay"
                  ],
                  "variable": [
                    {
                      "key": "id",
                      "value": "",
                      "description": "Webhook identifier (prefix `whk_`)."
                    },
                    {
                      "key": "delivery_id",
                      "value": "",
                      "description": "Delivery identifier returned by `GET /webhooks/{id}/deliveries` (prefix `whd_`)."
                    }
                  ]
                },
                "description": "Re-queues a previously attempted delivery for immediate re-send to the webhook's\ncurrently registered URL. Useful after fixing a receiver-side bug — there is no need\nto wait for the next real job.\n\n**Replays use the original payload and signature timestamp.** The exact bytes that\nwere originally signed are re-sent, and the original `X-Geog-Signature` (including\nits `t=` value) and `X-Geog-Delivery` ID are reused. This means:\n\n- HMAC verification on the receiver behaves identically to the original delivery.\n- The 5-minute replay-window check (`|now - t| > 300`) **will reject the request**\n  if the original signature timestamp is older than 5 minutes. Receivers that need\n  to accept replays of old deliveries should relax this check for requests carrying\n  a known `X-Geog-Delivery` ID.\n- Idempotent receivers keyed on `X-Geog-Delivery` will naturally deduplicate.\n\nThe replay attempt counts toward the webhook's retry budget and the delivery's\n`attempt_count` is incremented. Calling replay on a delivery whose `status` is\nalready `pending` returns `409 DELIVERY_ALREADY_PENDING`.\n\n`POST /webhooks/{id}/deliveries/{delivery_id}/replay`\n\n_operationId:_ `replayWebhookDelivery`",
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{api_key}}",
                      "type": "string"
                    }
                  ]
                }
              },
              "status": "Replay accepted and queued. The returned `WebhookDelivery` reflects the new `pending` state.",
              "code": 202,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"ok\": true,\n  \"result\": {\n    \"id\": \"whd_01hx2g4n8p7rqzm3k\",\n    \"webhook_id\": \"whk_01hx2f8q7n3tdvm5j\",\n    \"event\": \"job.complete\",\n    \"job_id\": \"job_01hx2a3f9k8qmzn7p\",\n    \"status\": \"pending\",\n    \"attempt_count\": 4,\n    \"response_code\": null,\n    \"response_ms\": null,\n    \"response_body_excerpt\": null,\n    \"error\": null,\n    \"signature_timestamp\": 1745211262,\n    \"created_at\": \"2026-04-21T03:14:22Z\",\n    \"last_attempt_at\": \"2026-04-21T03:24:51Z\",\n    \"delivered_at\": null,\n    \"next_attempt_at\": \"2026-04-21T03:48:31Z\",\n    \"test\": false\n  },\n  \"meta\": {\n    \"confidence\": 1.0,\n    \"model_version\": \"webhooks-v1.0.0\",\n    \"calibration_age_days\": 0,\n    \"site_calibrated\": true,\n    \"provenance\": [\n      \"registry:tenant-2026-04-21\"\n    ],\n    \"request_id\": \"req_01hx29sknd4bqyt8r\",\n    \"latency_ms\": 31\n  }\n}"
            }
          ]
        },
        {
          "name": "Read the rolling-hour delivery health for a webhook",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/webhooks/:id/health",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "webhooks",
                ":id",
                "health"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "",
                  "description": "Webhook identifier returned from `POST /webhooks` (prefix `whk_`)."
                }
              ]
            },
            "description": "Returns the same rolling-window failure-rate counters that drive the platform's\nauto-disable rule, plus the current `active` / `disabled_reason` state. Use this\nendpoint to detect — programmatically, without depending on the account owner's\ninbox — when a webhook has been auto-disabled after sustained delivery failures\n(≥50% failed deliveries in the last hour), or is trending toward it.\n\nTypical patterns:\n\n- **Polling guard.** Call once a minute from the same job that registered the\n  webhook. Alert your own on-call channel as soon as `status == \"degraded\"`\n  (failure rate has crossed 25%) so you can fix the receiver before the platform\n  auto-disables it. Treat `status == \"disabled\"` with `disabled_reason ==\n  \"auto_failure_rate\"` as a hard incident.\n- **Post-mortem.** After receiving a `webhook.disabled` event delivery (or the\n  owner-email alert), call this endpoint to read `failure_rate`, `failed_count`,\n  `undeliverable_count`, and `last_success_at` to understand exactly what tripped\n  the auto-disable rule.\n\nThis endpoint is read-only and cheap — it does not consume webhook delivery quota\nand is rate-limited only by the standard account-level rate limit.\n\n`GET /webhooks/{id}/health`\n\n_operationId:_ `getWebhookHealth`",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{api_key}}",
                  "type": "string"
                }
              ]
            }
          },
          "response": [
            {
              "name": "200 Current health snapshot.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{base_url}}/webhooks/:id/health",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "webhooks",
                    ":id",
                    "health"
                  ],
                  "variable": [
                    {
                      "key": "id",
                      "value": "",
                      "description": "Webhook identifier returned from `POST /webhooks` (prefix `whk_`)."
                    }
                  ]
                },
                "description": "Returns the same rolling-window failure-rate counters that drive the platform's\nauto-disable rule, plus the current `active` / `disabled_reason` state. Use this\nendpoint to detect — programmatically, without depending on the account owner's\ninbox — when a webhook has been auto-disabled after sustained delivery failures\n(≥50% failed deliveries in the last hour), or is trending toward it.\n\nTypical patterns:\n\n- **Polling guard.** Call once a minute from the same job that registered the\n  webhook. Alert your own on-call channel as soon as `status == \"degraded\"`\n  (failure rate has crossed 25%) so you can fix the receiver before the platform\n  auto-disables it. Treat `status == \"disabled\"` with `disabled_reason ==\n  \"auto_failure_rate\"` as a hard incident.\n- **Post-mortem.** After receiving a `webhook.disabled` event delivery (or the\n  owner-email alert), call this endpoint to read `failure_rate`, `failed_count`,\n  `undeliverable_count`, and `last_success_at` to understand exactly what tripped\n  the auto-disable rule.\n\nThis endpoint is read-only and cheap — it does not consume webhook delivery quota\nand is rate-limited only by the standard account-level rate limit.\n\n`GET /webhooks/{id}/health`\n\n_operationId:_ `getWebhookHealth`",
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{api_key}}",
                      "type": "string"
                    }
                  ]
                }
              },
              "status": "Current health snapshot.",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"ok\": true,\n  \"result\": {\n    \"webhook_id\": \"whk_01hx2f8q7n3tdvm5j\",\n    \"active\": false,\n    \"status\": \"disabled\",\n    \"disabled_at\": \"2026-04-21T03:48:11Z\",\n    \"disabled_reason\": \"auto_failure_rate\",\n    \"window_seconds\": 3600,\n    \"as_of\": \"2026-04-21T03:48:11Z\",\n    \"delivery_count\": 42,\n    \"success_count\": 18,\n    \"failed_count\": 3,\n    \"undeliverable_count\": 21,\n    \"pending_count\": 0,\n    \"failure_rate\": 0.571,\n    \"auto_disable_threshold\": 0.5,\n    \"consecutive_failures\": 7,\n    \"last_success_at\": \"2026-04-21T03:11:08Z\",\n    \"last_failure_at\": \"2026-04-21T03:47:54Z\"\n  },\n  \"meta\": {\n    \"confidence\": 1.0,\n    \"model_version\": \"webhooks-v1.0.0\",\n    \"calibration_age_days\": 0,\n    \"site_calibrated\": true,\n    \"provenance\": [\n      \"registry:tenant-2026-04-21\"\n    ],\n    \"request_id\": \"req_01hx29sknd4bqyt8r\",\n    \"latency_ms\": 18\n  }\n}"
            }
          ]
        }
      ]
    },
    {
      "name": "STAC Catalog",
      "description": "",
      "item": [
        {
          "name": "STAC catalog root",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/v1/stac/",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "stac"
              ]
            },
            "description": "STAC-API §1.0.0 catalog root. Carries the conformance set and\nnavigation links. Tenant-scoped: collections listed are filtered\nto the caller's `vertical_ids` and own `tenant_id`.\n\n**Conformance set:** Core, Collections, OGC API Features, Item Search\n(GET + POST). CQL2 filter is intentionally **not** advertised — see\nthe geog.ai roadmap entry `geog-ai-15` for the planned addition.\n\n**Pricing:** $0.002 / call (read family, 2.0 cost units).\n\n`GET /v1/stac/`\n\n_operationId:_ `stacRoot`",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{api_key}}",
                  "type": "string"
                }
              ]
            }
          },
          "response": [
            {
              "name": "200 STAC Catalog object.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{base_url}}/v1/stac/",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "v1",
                    "stac"
                  ]
                },
                "description": "STAC-API §1.0.0 catalog root. Carries the conformance set and\nnavigation links. Tenant-scoped: collections listed are filtered\nto the caller's `vertical_ids` and own `tenant_id`.\n\n**Conformance set:** Core, Collections, OGC API Features, Item Search\n(GET + POST). CQL2 filter is intentionally **not** advertised — see\nthe geog.ai roadmap entry `geog-ai-15` for the planned addition.\n\n**Pricing:** $0.002 / call (read family, 2.0 cost units).\n\n`GET /v1/stac/`\n\n_operationId:_ `stacRoot`",
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{api_key}}",
                      "type": "string"
                    }
                  ]
                }
              },
              "status": "STAC Catalog object.",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"type\": \"Catalog\",\n  \"stac_version\": \"1.0.0\",\n  \"id\": \"geog-ai-catalog\",\n  \"title\": \"geog.ai STAC Catalog\",\n  \"description\": \"Tenant-scoped STAC catalog of completed simulation jobs.\",\n  \"conformsTo\": [\n    \"https://api.stacspec.org/v1.0.0/core\",\n    \"https://api.stacspec.org/v1.0.0/collections\",\n    \"https://api.stacspec.org/v1.0.0/ogcapi-features\",\n    \"https://api.stacspec.org/v1.0.0/item-search\"\n  ],\n  \"links\": [\n    {\n      \"rel\": \"self\",\n      \"href\": \"https://api.geog.ai/v1/stac/\",\n      \"type\": \"application/json\"\n    },\n    {\n      \"rel\": \"root\",\n      \"href\": \"https://api.geog.ai/v1/stac/\",\n      \"type\": \"application/json\"\n    },\n    {\n      \"rel\": \"conformance\",\n      \"href\": \"https://api.geog.ai/v1/stac/conformance\",\n      \"type\": \"application/json\"\n    },\n    {\n      \"rel\": \"data\",\n      \"href\": \"https://api.geog.ai/v1/stac/collections\",\n      \"type\": \"application/json\"\n    },\n    {\n      \"rel\": \"search\",\n      \"href\": \"https://api.geog.ai/v1/stac/search\",\n      \"type\": \"application/geo+json\",\n      \"method\": \"GET\"\n    },\n    {\n      \"rel\": \"search\",\n      \"href\": \"https://api.geog.ai/v1/stac/search\",\n      \"type\": \"application/geo+json\",\n      \"method\": \"POST\"\n    }\n  ]\n}"
            }
          ]
        },
        {
          "name": "STAC conformance classes implemented by this server",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/v1/stac/conformance",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "stac",
                "conformance"
              ]
            },
            "description": "`GET /v1/stac/conformance`\n\n_operationId:_ `stacConformance`",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{api_key}}",
                  "type": "string"
                }
              ]
            }
          },
          "response": [
            {
              "name": "200 STAC §3 Conformance object.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{base_url}}/v1/stac/conformance",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "v1",
                    "stac",
                    "conformance"
                  ]
                },
                "description": "`GET /v1/stac/conformance`\n\n_operationId:_ `stacConformance`",
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{api_key}}",
                      "type": "string"
                    }
                  ]
                }
              },
              "status": "STAC §3 Conformance object.",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"conformsTo\": [\n    \"https://api.stacspec.org/v1.0.0/core\",\n    \"https://api.stacspec.org/v1.0.0/collections\",\n    \"https://api.stacspec.org/v1.0.0/ogcapi-features\",\n    \"https://api.stacspec.org/v1.0.0/item-search\"\n  ]\n}"
            }
          ]
        },
        {
          "name": "List STAC Collections visible to the caller",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/v1/stac/collections",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "stac",
                "collections"
              ]
            },
            "description": "One Collection per `(engine, vertical_id)` tuple the tenant has\nproduced jobs for. Each Collection carries `extent.spatial.bbox`,\n`extent.temporal.interval`, a per-tenant `license` (varies by plan),\nand a `providers` chain naming geog.ai as licensor and the engine\nas processor.\n\n`GET /v1/stac/collections`\n\n_operationId:_ `stacCollections`",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{api_key}}",
                  "type": "string"
                }
              ]
            }
          },
          "response": [
            {
              "name": "200 Collection list.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{base_url}}/v1/stac/collections",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "v1",
                    "stac",
                    "collections"
                  ]
                },
                "description": "One Collection per `(engine, vertical_id)` tuple the tenant has\nproduced jobs for. Each Collection carries `extent.spatial.bbox`,\n`extent.temporal.interval`, a per-tenant `license` (varies by plan),\nand a `providers` chain naming geog.ai as licensor and the engine\nas processor.\n\n`GET /v1/stac/collections`\n\n_operationId:_ `stacCollections`",
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{api_key}}",
                      "type": "string"
                    }
                  ]
                }
              },
              "status": "Collection list.",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"collections\": [\n    {\n      \"type\": \"Collection\",\n      \"stac_version\": \"1.0.0\",\n      \"id\": \"plume_aermod__oilgas\",\n      \"title\": \"AERMOD plume runs (oil & gas vertical)\",\n      \"description\": \"Completed AERMOD plume jobs for the oil & gas vertical.\",\n      \"license\": \"proprietary-professional\",\n      \"providers\": [\n        {\n          \"name\": \"geog.ai\",\n          \"roles\": [\n            \"licensor\",\n            \"host\"\n          ],\n          \"url\": \"https://geog.ai\"\n        },\n        {\n          \"name\": \"aermod\",\n          \"roles\": [\n            \"processor\"\n          ]\n        }\n      ],\n      \"extent\": {\n        \"spatial\": {\n          \"bbox\": [\n            [\n              -104.5,\n              30.5,\n              -94.0,\n              36.5\n            ]\n          ]\n        },\n        \"temporal\": {\n          \"interval\": [\n            [\n              \"2026-01-01T00:00:00Z\",\n              null\n            ]\n          ]\n        }\n      },\n      \"links\": [\n        {\n          \"rel\": \"self\",\n          \"href\": \"https://api.geog.ai/v1/stac/collections/plume_aermod__oilgas\",\n          \"type\": \"application/json\"\n        },\n        {\n          \"rel\": \"items\",\n          \"href\": \"https://api.geog.ai/v1/stac/collections/plume_aermod__oilgas/items\",\n          \"type\": \"application/geo+json\"\n        },\n        {\n          \"rel\": \"parent\",\n          \"href\": \"https://api.geog.ai/v1/stac/\",\n          \"type\": \"application/json\"\n        }\n      ]\n    }\n  ],\n  \"links\": [\n    {\n      \"rel\": \"self\",\n      \"href\": \"https://api.geog.ai/v1/stac/collections\",\n      \"type\": \"application/json\"\n    },\n    {\n      \"rel\": \"root\",\n      \"href\": \"https://api.geog.ai/v1/stac/\",\n      \"type\": \"application/json\"\n    }\n  ]\n}"
            }
          ]
        },
        {
          "name": "Fetch a single STAC Collection",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/v1/stac/collections/:collection_id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "stac",
                "collections",
                ":collection_id"
              ],
              "variable": [
                {
                  "key": "collection_id",
                  "value": "",
                  "description": "Composite collection id — `{engine}__{vertical_id}` (e.g.\n`plume_aermod__oilgas`). Use `_unscoped` as the vertical\nsentinel for legacy rows that carry no vertical_id.\n"
                }
              ]
            },
            "description": "`GET /v1/stac/collections/{collection_id}`\n\n_operationId:_ `stacCollection`",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{api_key}}",
                  "type": "string"
                }
              ]
            }
          },
          "response": [
            {
              "name": "200 STAC Collection.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{base_url}}/v1/stac/collections/:collection_id",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "v1",
                    "stac",
                    "collections",
                    ":collection_id"
                  ],
                  "variable": [
                    {
                      "key": "collection_id",
                      "value": "",
                      "description": "Composite collection id — `{engine}__{vertical_id}` (e.g.\n`plume_aermod__oilgas`). Use `_unscoped` as the vertical\nsentinel for legacy rows that carry no vertical_id.\n"
                    }
                  ]
                },
                "description": "`GET /v1/stac/collections/{collection_id}`\n\n_operationId:_ `stacCollection`",
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{api_key}}",
                      "type": "string"
                    }
                  ]
                }
              },
              "status": "STAC Collection.",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"type\": \"Collection\",\n  \"stac_version\": \"1.0.0\",\n  \"id\": \"plume_aermod__oilgas\",\n  \"title\": \"AERMOD plume runs (oil & gas vertical)\",\n  \"description\": \"Completed AERMOD plume jobs for the oil & gas vertical.\",\n  \"license\": \"proprietary-professional\",\n  \"providers\": [\n    {\n      \"name\": \"geog.ai\",\n      \"roles\": [\n        \"licensor\",\n        \"host\"\n      ],\n      \"url\": \"https://geog.ai\"\n    },\n    {\n      \"name\": \"aermod\",\n      \"roles\": [\n        \"processor\"\n      ]\n    }\n  ],\n  \"extent\": {\n    \"spatial\": {\n      \"bbox\": [\n        [\n          -104.5,\n          30.5,\n          -94.0,\n          36.5\n        ]\n      ]\n    },\n    \"temporal\": {\n      \"interval\": [\n        [\n          \"2026-01-01T00:00:00Z\",\n          null\n        ]\n      ]\n    }\n  },\n  \"links\": [\n    {\n      \"rel\": \"self\",\n      \"href\": \"https://api.geog.ai/v1/stac/collections/plume_aermod__oilgas\",\n      \"type\": \"application/json\"\n    },\n    {\n      \"rel\": \"items\",\n      \"href\": \"https://api.geog.ai/v1/stac/collections/plume_aermod__oilgas/items\",\n      \"type\": \"application/geo+json\"\n    },\n    {\n      \"rel\": \"parent\",\n      \"href\": \"https://api.geog.ai/v1/stac/\",\n      \"type\": \"application/json\"\n    }\n  ]\n}"
            }
          ]
        },
        {
          "name": "List STAC Items within a Collection",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/v1/stac/collections/:collection_id/items",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "stac",
                "collections",
                ":collection_id",
                "items"
              ],
              "query": [
                {
                  "key": "bbox",
                  "value": "",
                  "description": "WGS84 bbox `min_lng,min_lat,max_lng,max_lat`. Pushed into PostGIS via ST_Intersects.",
                  "disabled": true
                },
                {
                  "key": "datetime",
                  "value": "",
                  "description": "ISO 8601 instant (`2024-01-01T00:00:00Z`) or interval (`start/end`, `..` for open ends).",
                  "disabled": true
                },
                {
                  "key": "limit",
                  "value": "50",
                  "description": "",
                  "disabled": true
                },
                {
                  "key": "cursor",
                  "value": "",
                  "description": "Opaque HMAC-signed pagination cursor returned by the previous page's `next` link.",
                  "disabled": true
                }
              ],
              "variable": [
                {
                  "key": "collection_id",
                  "value": "",
                  "description": ""
                }
              ]
            },
            "description": "`GET /v1/stac/collections/{collection_id}/items`\n\n_operationId:_ `stacCollectionItems`",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{api_key}}",
                  "type": "string"
                }
              ]
            }
          },
          "response": []
        },
        {
          "name": "Fetch a single STAC Item",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/v1/stac/collections/:collection_id/items/:item_id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "stac",
                "collections",
                ":collection_id",
                "items",
                ":item_id"
              ],
              "variable": [
                {
                  "key": "collection_id",
                  "value": "",
                  "description": ""
                },
                {
                  "key": "item_id",
                  "value": "",
                  "description": "geo_simulation_jobs.job_id"
                }
              ]
            },
            "description": "`GET /v1/stac/collections/{collection_id}/items/{item_id}`\n\n_operationId:_ `stacItem`",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{api_key}}",
                  "type": "string"
                }
              ]
            }
          },
          "response": []
        },
        {
          "name": "STAC Item Search (GET)",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/v1/stac/search",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "stac",
                "search"
              ],
              "query": [
                {
                  "key": "bbox",
                  "value": "",
                  "description": "",
                  "disabled": true
                },
                {
                  "key": "datetime",
                  "value": "",
                  "description": "",
                  "disabled": true
                },
                {
                  "key": "collections",
                  "value": "",
                  "description": "",
                  "disabled": true
                },
                {
                  "key": "limit",
                  "value": "50",
                  "description": "",
                  "disabled": true
                },
                {
                  "key": "cursor",
                  "value": "",
                  "description": "",
                  "disabled": true
                }
              ]
            },
            "description": "STAC §15 Item Search. Supported predicates:\n  - `bbox` — pushed into PostGIS via `ST_Intersects`.\n  - `datetime` — ISO instant or `start/end` interval.\n  - `collections` — comma-separated `{engine}__{vertical_id}` list.\n  - `limit` / `cursor` — opaque signed pagination.\n\nTenant-scoped: every result row is intersected against the caller's\n`vertical_ids` and `tenant_id` (per Phase 3 §3.11 acceptance\ncriterion 9). CQL2 filtering is **not** supported on this\nendpoint — see roadmap entry `geog-ai-15`.\n\n`GET /v1/stac/search`\n\n_operationId:_ `stacSearchGet`",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{api_key}}",
                  "type": "string"
                }
              ]
            }
          },
          "response": []
        },
        {
          "name": "STAC Item Search (POST)",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/v1/stac/search",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "stac",
                "search"
              ]
            },
            "description": "Identical predicate set to `GET /v1/stac/search`, sent as a JSON\nbody. STAC clients use this surface when query strings would\nexceed proxy URL-length limits, or when posting array-shaped\n`bbox` / `collections` values.\n\n`POST /v1/stac/search`\n\n_operationId:_ `stacSearchPost`",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{api_key}}",
                  "type": "string"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"bbox\": [\n    -100.0,\n    31.0,\n    -99.5,\n    32.0\n  ],\n  \"datetime\": \"2026-04-01T00:00:00Z/2026-04-30T23:59:59Z\",\n  \"collections\": [\n    \"plume_aermod__oilgas\"\n  ],\n  \"limit\": 50\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": []
        }
      ]
    }
  ],
  "auth": {
    "type": "bearer",
    "bearer": [
      {
        "key": "token",
        "value": "{{api_key}}",
        "type": "string"
      }
    ]
  },
  "variable": [
    {
      "key": "base_url",
      "value": "https://api.geog.ai/v1",
      "type": "string"
    },
    {
      "key": "api_key",
      "value": "geog_test_sk_replace_me",
      "type": "string"
    }
  ]
}
