{"openapi":"3.1.0","info":{"title":"Mapulus API","description":"\n# Mapulus API\n\nMapulus is a location intelligence platform for Australian geographies. This API\nlets you manage maps and locations, look up statistical boundaries, query\ndemographic data from the ABS Census, and batch-enrich records with geographic context.\n\n## Authentication\n\nAll endpoints require a Bearer token:\n\n```\nAuthorization: Bearer <your_api_key>\n```\n\nAPI keys can be managed from your Mapulus account under **Profile > API Keys**.\nEach key can be scoped to specific resources and given an expiration date.\nKeep keys secure — never commit them to repositories.\n\n## Base URLs\n\n| Service | Base URL |\n|---------|----------|\n| Studio  | `https://api.mapulus.com/v1/studio` |\n| Data    | `https://api.mapulus.com/v1/data`   |\n\n## Rate limits\n\nRate limits are per API key. Headers are included on every response:\n\n| Header | Description |\n|--------|-------------|\n| `X-RateLimit-Limit` | Requests allowed per window |\n| `X-RateLimit-Remaining` | Requests remaining |\n| `X-RateLimit-Reset` | Unix timestamp when the window resets |\n\n---\n\n# Studio endpoints\n\nThe **Maps** and **Locations** endpoints let you manage your maps, pins, layers,\nand travel boundaries (isochrones).\n\n## Core concepts\n\n- **Maps** — A map is a container that holds one or more layers of locations\n- **Layers** — Each map has layers that group locations together. Expand layer details with `expand[]=layer`\n- **Locations** — Pins on a map with coordinates, address, and custom attributes\n- **Travel contours** — Isochrone boundaries around a location based on drive, cycle, or walk time\n- **Custom attributes** — User-defined key/value metadata on locations (e.g. \"Location Type\": \"Store\")\n- **Nearest search** — Find the closest locations to a point by distance or travel time, with routing profiles (`driving`, `cycling`, `walking`)\n\n## Pagination\n\nList endpoints return paginated results with `pages` metadata:\n\n```json\n{\n  \"object\": \"list\",\n  \"data\": [...],\n  \"pages\": {\n    \"object\": \"pages\",\n    \"total_pages\": 5,\n    \"current_page\": 1,\n    \"next_page\": 2,\n    \"prev_page\": null\n  },\n  \"total_count\": 120\n}\n```\n\n## Errors\n\nStudio endpoints return errors in the following format:\n\n```json\n{\n  \"errors\": {\n    \"unauthorized\": [\"You are not authorized to perform this action\"]\n  }\n}\n```\n\nCommon error keys: `unauthorized` (401), `404` (not found), `UnprocessableEntity` (422),\n`TooManyRequests` (429).\n\n---\n\n# Data endpoints\n\nThe **Boundaries**, **Demographics**, and **Enrich** endpoints provide\nAustralian statistical geography lookups, ABS Census data, and batch enrichment.\n\n## Core concepts\n\n- **Boundaries** — Australian statistical geography areas (SA1–SA4, LGA, postcode, suburb, etc.)\n- **H3 indices** — Uber's hexagonal grid at resolutions 3–9 for fast spatial lookups\n- **Demographics** — Census-derived data attached to boundaries (population, income, housing, etc.)\n- **Field selection** — Use `fields` to request specific data (e.g. `summary.population.persons,medians.age`)\n- **Topics** — Groups of related fields (e.g. `age`, `income`, `housing`) for convenient data retrieval\n- **Boundary IDs** — Use `type:code` format (e.g. `sa2:117011325`, `lga:17200`, `poa:2000`)\n\n### Boundary types\n\n`sa1`, `sa2`, `sa3`, `sa4`, `lga`, `poa`, `sal`, `ced`, `sed`, `gccsa`, `ste`,\n`sua`, `ucl`, `ra`, `sos`, `sosr`, `iloc`, `iare`, `ireg`, `flood`\n\n## Demographics queries\n\nThe unified `GET /v1/data/demographics` and `POST /v1/data/demographics` endpoints cover all\ndemographic queries. Combine parameters to express what you need:\n\n| Mode | Parameters | Description |\n|------|-----------|-------------|\n| Point lookup | `lat`, `lng` | Demographics for the boundary containing a point (default SA1) |\n| Single boundary | `boundary_id=sa2:117011325` | Demographics for one boundary |\n| Multiple boundaries | `boundary_id=sa1:123,sa1:456` | Individual results or `aggregate=true` |\n| Browse by type | `boundary_type=sa2` | Paginated list with `filter`, `sort`, `contained_by` |\n| Segment query | `boundary_id` + `topics` + `sex`/`age_min`/`age_max` | Cross-tab breakdown for a single boundary |\n| Polygon query (POST) | `geometry` (GeoJSON body) | Boundaries intersecting a polygon, with area-weighted overlap |\n\n### Segment queries\n\nAdd `sex`, `age_min`, `age_max` to any single-boundary query to get a cross-tab\nbreakdown. Requires exactly one `topics` value:\n\n```\nGET /v1/data/demographics?boundary_id=sa1:123&topics=income&sex=female&age_min=25&age_max=44\n```\n\n### Polygon queries (POST)\n\nSend a GeoJSON polygon in the request body. Add `aggregate=true` for area-weighted totals:\n\n```json\nPOST /v1/data/demographics\n{\"geometry\": {\"type\": \"Polygon\", \"coordinates\": [...]},\n \"boundary_type\": \"sa2\", \"topics\": \"income\", \"aggregate\": true}\n```\n\n## Filtering\n\nUse the `filter` parameter on data list endpoints to filter by field values:\n\n| Operator | Example | Description |\n|----------|---------|-------------|\n| `eq` | `summary.population.persons.eq.10000` | Equals |\n| `neq` | `summary.population.persons.neq.0` | Not equals |\n| `gt` / `gte` | `summary.population.persons.gt.10000` | Greater than (or equal) |\n| `lt` / `lte` | `medians.age.lt.30` | Less than (or equal) |\n| `between` | `medians.age.between.25,40` | Between (inclusive) |\n| `in` | `summary.population.persons.in.100,200,300` | In set |\n\n**Multiple filters** (AND logic): separate with `;`\n\n```\n?filter=summary.population.persons.gte.10000;medians.age.lt.40\n```\n\n## Sorting\n\n```\n?sort=summary.population.persons.desc\n?sort=medians.age.asc\n```\n\n## Pagination\n\nData list endpoints use `limit` and `offset`. Response includes `meta.pagination`:\n\n```json\n{\n  \"meta\": {\n    \"pagination\": {\n      \"total\": 2310,\n      \"limit\": 25,\n      \"offset\": 0,\n      \"has_more\": true\n    }\n  }\n}\n```\n\n## Errors\n\nData endpoints return a consistent error shape:\n\n```json\n{\n  \"error\": {\n    \"type\": \"invalid_request_error\",\n    \"code\": \"invalid_parameters\",\n    \"message\": \"A human-readable description of what went wrong.\",\n    \"param\": \"lat\"\n  }\n}\n```\n\nError types: `authentication_error`, `invalid_request_error`, `validation_error`,\n`not_found_error`, `rate_limit_error`, `api_error`.\n\nValidation errors include field-level detail:\n\n```json\n{\n  \"error\": {\n    \"type\": \"validation_error\",\n    \"code\": \"invalid_parameters\",\n    \"message\": \"Request validation failed.\",\n    \"errors\": [\n      {\"field\": \"lat\", \"message\": \"value is not a valid float\"},\n      {\"field\": \"lng\", \"message\": \"ensure this value is less than or equal to 180\"}\n    ]\n  }\n}\n```\n","version":"0.1.0"},"paths":{"/v1/data/health":{"get":{"tags":["Health"],"summary":"Service health check","description":"Returns the current health status and version of the API.\n\nThis endpoint does not require authentication. When the sync daemon is\nenabled, includes per-source sync health in the response. When the request\narrives via a known API domain (or a Studio health URL is configured),\nproxies Studio's health status.","operationId":"health_v1_data_health_get","responses":{"200":{"description":"Returns service status and version.","content":{"application/json":{"schema":{}}}}}}},"/v1/data/health/sync":{"get":{"tags":["Health"],"summary":"Sync source health","description":"Returns sync daemon health, optionally filtered to a single source.\n\nUse ``?source=qld_traffic`` to get a single source's status — ideal for\nkeyword monitoring (match ``\"status\":\"ok\"``).  Omit the parameter to get\nall sources with a top-level aggregate status.\n\nReturns 503 when the sync daemon is not enabled, 404 for unknown sources.","operationId":"sync_health_v1_data_health_sync_get","parameters":[{"name":"source","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source"}}],"responses":{"200":{"description":"Per-source sync health for monitoring.","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/data/boundaries":{"get":{"tags":["Boundaries"],"summary":"Lookup boundaries by coordinates","description":"Resolve a latitude/longitude point to its containing statistical boundaries.\n\nReturns all boundary types (SA1-SA4, LGA, postcode, suburb, etc.) that contain the\ngiven point, along with H3 hexagonal grid indices at resolutions 3-9 and any\nmatching planning regions.\n\nUses an H3 crosswalk table for fast lookups with a spatial query fallback.","operationId":"boundaries_lookup_v1_data_boundaries_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"lat","in":"query","required":true,"schema":{"type":"number","maximum":90,"minimum":-90,"description":"Latitude in decimal degrees.","title":"Lat"},"description":"Latitude in decimal degrees.","examples":{"sydney":{"summary":"Sydney CBD","value":-33.8688},"melbourne":{"summary":"Melbourne CBD","value":-37.8136}}},{"name":"lng","in":"query","required":true,"schema":{"type":"number","maximum":180,"minimum":-180,"description":"Longitude in decimal degrees.","title":"Lng"},"description":"Longitude in decimal degrees.","examples":{"sydney":{"summary":"Sydney CBD","value":151.2093},"melbourne":{"summary":"Melbourne CBD","value":144.9631}}},{"name":"types","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated boundary types to return (e.g. `sa2,lga`). Returns all types if omitted.","title":"Types"},"description":"Comma-separated boundary types to return (e.g. `sa2,lga`). Returns all types if omitted."}],"responses":{"200":{"description":"Matching boundaries, planning regions, and H3 indices for the given point.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResponseEnvelope_BoundaryLookupResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/data/boundaries/types":{"get":{"tags":["Boundaries"],"summary":"List available boundary types","description":"List all available boundary types grouped by country.\n\nReturns type codes, human-readable labels, and country codes for all\nsupported boundary geographies (20 Australian + 20 US types).","operationId":"boundaries_types_v1_data_boundaries_types_get","responses":{"200":{"description":"Available boundary types grouped by country.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResponseEnvelope_BoundaryTypesResponse_"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/data/boundaries/search":{"post":{"tags":["Boundaries"],"summary":"Batch lookup boundaries","description":"Resolve multiple locations to their containing boundaries in a single request.\n\nAccepts up to 100 locations. Each location is resolved independently.","operationId":"boundaries_search_v1_data_boundaries_search_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BoundarySearchRequest"}}},"required":true},"responses":{"200":{"description":"Boundary results for each location in the batch.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResponseEnvelope_BoundarySearchResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/data/boundaries/geojson":{"post":{"tags":["Boundaries"],"summary":"Batch export boundaries as GeoJSON","description":"Export specific boundaries by ID as a GeoJSON FeatureCollection.\n\nAccepts up to 500 boundary IDs. Returns a streamed GeoJSON FeatureCollection\nwith geometry, bbox, centroid, and properties for each boundary.","operationId":"boundaries_geojson_batch_v1_data_boundaries_geojson_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GeoJSONExportRequest"}}},"required":true},"responses":{"200":{"description":"GeoJSON FeatureCollection of the requested boundaries.","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/data/boundaries/{boundary_type}":{"get":{"tags":["Boundaries"],"summary":"List boundaries of a type","description":"List all boundaries of a given type.\n\nUse `contained_by` to answer spatial questions like \"what SA1s are in postcode 2000?\"\n\n**Examples:**\n- `GET /v1/data/boundaries/sa2` — list all SA2s\n- `GET /v1/data/boundaries/sa1?contained_by=poa:2000` — SA1s in postcode 2000\n- `GET /v1/data/boundaries/sa2?contained_by=lga:17200` — SA2s in Sydney LGA\n- `GET /v1/data/boundaries/lga?search=melbourne` — LGAs matching \"melbourne\"\n- `GET /v1/data/boundaries/poa?code_prefix=40` — postcodes starting with 40","operationId":"boundaries_list_v1_data_boundaries__boundary_type__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"boundary_type","in":"path","required":true,"schema":{"$ref":"#/components/schemas/BoundaryType","description":"Boundary type (e.g. `sa2`, `lga`, `poa`)."},"description":"Boundary type (e.g. `sa2`, `lga`, `poa`)."},{"name":"contained_by","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Spatial filter: parent boundary_id (e.g. `poa:2000`). Returns child boundaries whose centroid falls within.","title":"Contained By"},"description":"Spatial filter: parent boundary_id (e.g. `poa:2000`). Returns child boundaries whose centroid falls within."},{"name":"search","in":"query","required":false,"schema":{"anyOf":[{"type":"string","minLength":1,"maxLength":100},{"type":"null"}],"description":"Search boundary names (case-insensitive substring match).","title":"Search"},"description":"Search boundary names (case-insensitive substring match)."},{"name":"code_prefix","in":"query","required":false,"schema":{"anyOf":[{"type":"string","minLength":1,"maxLength":20},{"type":"null"}],"description":"Filter by code prefix (e.g. '40' for postcodes 4000-4099).","title":"Code Prefix"},"description":"Filter by code prefix (e.g. '40' for postcodes 4000-4099)."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"description":"Page size.","default":25,"title":"Limit"},"description":"Page size."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Pagination offset.","default":0,"title":"Offset"},"description":"Pagination offset."}],"responses":{"200":{"description":"Paginated list of boundaries.","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/data/boundaries/{boundary_type}/geojson":{"get":{"tags":["Boundaries"],"summary":"Export all boundaries of a type as GeoJSON","description":"Download all boundaries of a type as a streamed GeoJSON FeatureCollection.\n\nUses server-side streaming to handle large result sets (e.g. ~62K SA1 boundaries)\nwithout loading all features into memory.\n\n**Simplification levels:**\n- `full` — no simplification (analysis, data export)\n- `medium` — ~100m tolerance (choropleth maps) — **default**\n- `low` — ~500m tolerance (thumbnails, overview maps)","operationId":"boundaries_geojson_by_type_v1_data_boundaries__boundary_type__geojson_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"boundary_type","in":"path","required":true,"schema":{"$ref":"#/components/schemas/BoundaryType","description":"Boundary type (e.g. `sa2`, `lga`)."},"description":"Boundary type (e.g. `sa2`, `lga`)."},{"name":"simplify","in":"query","required":false,"schema":{"type":"string","pattern":"^(full|medium|low)$","description":"Geometry simplification: full (none), medium (~100m), low (~500m).","default":"medium","title":"Simplify"},"description":"Geometry simplification: full (none), medium (~100m), low (~500m)."},{"name":"state","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by state code (e.g. `NSW`, `QLD`).","title":"State"},"description":"Filter by state code (e.g. `NSW`, `QLD`)."},{"name":"contained_by","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Spatial filter: parent boundary_id (centroid within parent).","title":"Contained By"},"description":"Spatial filter: parent boundary_id (centroid within parent)."},{"name":"intersects","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Spatial filter: parent boundary_id (geometry intersects parent).","title":"Intersects"},"description":"Spatial filter: parent boundary_id (geometry intersects parent)."},{"name":"search","in":"query","required":false,"schema":{"anyOf":[{"type":"string","minLength":1,"maxLength":100},{"type":"null"}],"description":"Search boundary names (case-insensitive substring match).","title":"Search"},"description":"Search boundary names (case-insensitive substring match)."},{"name":"code_prefix","in":"query","required":false,"schema":{"anyOf":[{"type":"string","minLength":1,"maxLength":20},{"type":"null"}],"description":"Filter by code prefix.","title":"Code Prefix"},"description":"Filter by code prefix."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100000,"minimum":1,"description":"Max features to return.","default":10000,"title":"Limit"},"description":"Max features to return."}],"responses":{"200":{"description":"Streamed GeoJSON FeatureCollection.","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/data/boundaries/{boundary_type}/{code}":{"get":{"tags":["Boundaries"],"summary":"Get a single boundary","description":"Get metadata for a single boundary by type and code.","operationId":"boundary_detail_v1_data_boundaries__boundary_type___code__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"boundary_type","in":"path","required":true,"schema":{"$ref":"#/components/schemas/BoundaryType","description":"Boundary type (e.g. `sa2`, `lga`)."},"description":"Boundary type (e.g. `sa2`, `lga`)."},{"name":"code","in":"path","required":true,"schema":{"type":"string","description":"Boundary code (e.g. `117011325`).","title":"Code"},"description":"Boundary code (e.g. `117011325`)."}],"responses":{"200":{"description":"Boundary metadata.","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/data/boundaries/{boundary_type}/{code}/geojson":{"get":{"tags":["Boundaries"],"summary":"Export a single boundary as GeoJSON","description":"Download a single boundary as a GeoJSON Feature with full geometry.\n\nDefault simplification is `full` (no simplification) for single boundaries.","operationId":"boundary_geojson_single_v1_data_boundaries__boundary_type___code__geojson_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"boundary_type","in":"path","required":true,"schema":{"$ref":"#/components/schemas/BoundaryType","description":"Boundary type (e.g. `sa2`, `lga`)."},"description":"Boundary type (e.g. `sa2`, `lga`)."},{"name":"code","in":"path","required":true,"schema":{"type":"string","description":"Boundary code (e.g. `117011325`).","title":"Code"},"description":"Boundary code (e.g. `117011325`)."},{"name":"simplify","in":"query","required":false,"schema":{"type":"string","pattern":"^(full|medium|low)$","description":"Geometry simplification: full (none), medium (~100m), low (~500m).","default":"full","title":"Simplify"},"description":"Geometry simplification: full (none), medium (~100m), low (~500m)."}],"responses":{"200":{"description":"GeoJSON Feature with geometry.","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/data/demographics/topics":{"get":{"tags":["Demographics"],"summary":"List demographic topics","description":"List all available demographic topics.\n\nTopics group related census fields into categories like `age`, `income`,\n`housing`, etc. Use topic IDs with the `?topics=` parameter on the\ndemographics data endpoint to request all fields in a topic at once.\n\n**16 standard topics** (available at all geographies):\n`summary`, `age`, `income`, `housing`, `education`, `employment`,\n`transport`, `family`, `language`, `ancestry`, `religion`,\n`birthplace`, `health`, `internet`, `volunteering`, `unpaid_work`\n\n**9 Indigenous Profile topics** (ILOC/IARE/IREG only):\n`ip_summary`, `ip_age`, `ip_language`, `ip_education`, `ip_income`,\n`ip_health`, `ip_housing`, `ip_family`, `ip_employment`\n\n**Usage with demographics endpoint:**\n- `GET /v1/data/demographics?boundary_id=sa2:117011325&topics=income` — all income fields\n- `GET /v1/data/demographics?lat=-33.87&lng=151.21&topics=age,income` — multiple topics\n- `POST /v1/data/demographics` with `\"topics\": \"summary\"` — polygon query with topic expansion","operationId":"demographics_topics_endpoint_v1_data_demographics_topics_get","responses":{"200":{"description":"List of all demographic topics.","content":{"application/json":{"schema":{},"examples":{"topics_list":{"summary":"All topics","value":{"data":[{"id":"summary","label":"Key Statistics","description":"Population totals, medians, and headline figures.","field_count":52},{"id":"age","label":"Age","description":"Detailed single-year and 5-year age breakdowns.","field_count":303},{"id":"income","label":"Income","description":"Personal, family, and household income brackets.","field_count":456},{"id":"housing","label":"Housing","description":"Dwelling structure, tenure, mortgage, and rent.","field_count":280},{"id":"education","label":"Education","description":"School completion, qualification level, field of study.","field_count":195},{"id":"ip_summary","label":"Indigenous Profile Summary","description":"Key stats for Indigenous geographies (ILOC/IARE/IREG only).","field_count":48}]}}}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/data/demographics/derived":{"get":{"tags":["Demographics"],"summary":"List derived percentage fields","description":"List all available derived percentage fields.\n\nDerived fields are computed at query time from raw census data. Use them\nwith `?fields=derived.pct_indigenous` on the demographics endpoint.\n\n**63 static fields**, always available, no extra params needed. Covers:\n- **Population** (G01): indigenous, born overseas/australia, english/other language,\n  citizen, children, working age, seniors, education attendance, school completion\n- **Age brackets** (G01): 11 fields for each G01 age bracket (0-4 through 85+)\n- **Motor vehicles** (G34): no car, 1/2/3+ cars\n- **Dwelling structure** (G42): separate house, semi-detached, flat/apartment, other\n- **Labour force** (G43): unemployed, full/part-time, in/not in labour force\n- **Qualifications** (G43): postgrad, bachelor, grad diploma, adv diploma, cert III/IV, I/II\n- **Migration** (G43): moved 1yr/5yr ago, same address\n- **Household income** (G33): negative/nil, under $650, $1k-2k, $2k+/week\n- **Rent** (G40): under $200, $200-449, $450+/week\n- **Mortgage** (G38): under $600, $600-999, $1000+/month\n- **Household composition** (G35): lone person, large (5+), family household","operationId":"demographics_derived_endpoint_v1_data_demographics_derived_get","responses":{"200":{"description":"All available derived percentage fields.","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/data/demographics/fields/{api_path}":{"get":{"tags":["Demographics"],"summary":"Get field metadata","description":"Get detailed metadata for a single field, including related fields.\n\n**Field types:**\n\n- **Count fields** (`unit: \"count\"`) — raw census counts (e.g. `summary.population.persons`).\n  Use directly with `?fields=` on the demographics endpoint.\n- **Median fields** (`unit: \"years\"`, `\"dollars_weekly\"`, etc.) — pre-computed medians\n  from the ABS (e.g. `medians.age`, `medians.personal_income_weekly`).\n- **Derived percentage fields** (`unit: \"percentage\"`, `is_derived: true`) — computed at\n  query time as `(numerator / denominator) * 100`. Request with `?fields=derived.pct_indigenous`.\n  Returns a value between 0 and 100. 63 static fields covering population, age brackets,\n  housing, employment, qualifications, and more.\n  Use `GET /v1/data/demographics/derived` to list all available fields with labels.\n\n**Dimensions:**\n\nFields with `dimensions` like `{\"sex\": \"female\", \"age_min\": 25, \"age_max\": 34}` are\nused by segment queries. Add `&sex=female&age_min=25&age_max=34` to a demographics\nrequest to get a cross-tab breakdown filtered to that segment.\n\n**Mixing field types:**\n\nYou can request regular counts, medians, and derived percentages together:\n```\n?fields=summary.population.persons,medians.age,derived.pct_indigenous\n```","operationId":"demographics_field_detail_endpoint_v1_data_demographics_fields__api_path__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"api_path","in":"path","required":true,"schema":{"type":"string","description":"Full API path (e.g. `summary.population.persons`)","title":"Api Path"},"description":"Full API path (e.g. `summary.population.persons`)"}],"responses":{"200":{"description":"Field metadata with related fields.","content":{"application/json":{"schema":{},"examples":{"count_field":{"summary":"Count field (population total)","description":"A raw count field. Use with `?fields=summary.population.persons` on the demographics endpoint.","value":{"data":{"api_path":"summary.population.persons","label":"Total Population - Persons","topic":"summary","unit":"count","table_id":"G01","abs_column":"Tot_P_P","dimensions":{"sex":"persons"},"is_total":true,"is_derived":false,"related_fields":["summary.population.male","summary.population.female"]}}},"median_field":{"summary":"Median field (dollars/years)","description":"A pre-computed median. Unit tells you how to interpret the value.","value":{"data":{"api_path":"medians.personal_income_weekly","label":"Median Personal Income - Weekly","topic":"summary","unit":"dollars_weekly","table_id":"G02","abs_column":"Median_tot_prsnl_inc_weekly","dimensions":{},"is_total":true,"is_derived":false,"related_fields":["medians.age","medians.household_income_weekly"]}}},"derived_percentage":{"summary":"Derived percentage field","description":"Computed at query time from raw census counts. Request with `?fields=derived.pct_indigenous`. Returns a percentage (0-100).","value":{"data":{"api_path":"derived.pct_indigenous","label":"% Aboriginal and/or Torres Strait Islander","topic":"summary","unit":"percentage","table_id":"G01","dimensions":{},"is_total":false,"is_derived":true,"related_fields":["derived.pct_born_overseas","derived.pct_citizen","derived.pct_children_0_14","derived.pct_seniors_65_plus","derived.pct_rent_450_plus","derived.pct_mortgage_1000_plus","derived.pct_hh_income_2000_plus"]}}},"segment_field":{"summary":"Segment-dimensioned field (sex + age)","description":"Fields with `sex`/`age_min`/`age_max` dimensions are used by segment queries. Add `&sex=female&age_min=25&age_max=34` to filter.","value":{"data":{"api_path":"income.personal_weekly.bracket_1_149.female.age_25_34","label":"Income $1-149 Weekly - Female 25-34","topic":"income","unit":"count","table_id":"G17","abs_column":"F_1_149_25_34_yrs","dimensions":{"sex":"female","age_min":25,"age_max":34,"income_bracket":"1_149"},"is_total":false,"is_derived":false,"related_fields":["income.personal_weekly.bracket_150_299.female.age_25_34","income.personal_weekly.bracket_300_399.female.age_25_34"]}}}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/data/demographics/fields":{"get":{"tags":["Demographics"],"summary":"Search demographic fields","description":"Browse and search the demographic field catalog.\n\nUse `topic` to filter by category, `search` for free-text matching.\nThe catalog contains 13,498 fields across 25 topics.\n\n**Common workflows:**\n\n1. **Discover what's available:** `GET /v1/data/demographics/fields?topic=income`\n2. **Search by keyword:** `GET /v1/data/demographics/fields?search=median`\n3. **Get field detail:** `GET /v1/data/demographics/fields/medians.age`\n4. **Use in a query:** `GET /v1/data/demographics?boundary_id=sa2:117011325&fields=medians.age`\n5. **Use derived percentages:** `GET /v1/data/demographics?lat=-33.87&lng=151.21&fields=derived.pct_indigenous,derived.pct_seniors_65_plus`","operationId":"demographics_fields_endpoint_v1_data_demographics_fields_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"topic","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by topic (e.g. `income`, `age`).","title":"Topic"},"description":"Filter by topic (e.g. `income`, `age`)."},{"name":"search","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Search fields by name or label (e.g. `median`, `population`).","title":"Search"},"description":"Search fields by name or label (e.g. `median`, `population`)."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"description":"Maximum results to return.","default":50,"title":"Limit"},"description":"Maximum results to return."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Pagination offset.","default":0,"title":"Offset"},"description":"Pagination offset."}],"responses":{"200":{"description":"Matching fields from the catalog.","content":{"application/json":{"schema":{},"examples":{"search_by_topic":{"summary":"Browse fields in a topic","description":"GET /v1/data/demographics/fields?topic=income — lists all income-related fields.","value":{"data":[{"api_path":"income.personal_weekly.bracket_1_149.male","label":"Income $1-149 Weekly - Male","topic":"income","unit":"count","table_id":"G17","abs_column":"M_1_149_Tot","dimensions":{"sex":"male"},"is_total":true,"is_derived":false},{"api_path":"income.personal_weekly.bracket_1_149.female","label":"Income $1-149 Weekly - Female","topic":"income","unit":"count","table_id":"G17","abs_column":"F_1_149_Tot","dimensions":{"sex":"female"},"is_total":true,"is_derived":false}],"meta":{"pagination":{"total":456,"limit":50,"offset":0,"has_more":true}}}},"search_by_keyword":{"summary":"Free-text search","description":"GET /v1/data/demographics/fields?search=median — finds fields matching 'median'.","value":{"data":[{"api_path":"medians.age","label":"Median Age - Persons","topic":"summary","unit":"years","table_id":"G02","abs_column":"Median_age_persons","dimensions":{},"is_total":true,"is_derived":false},{"api_path":"medians.personal_income_weekly","label":"Median Personal Income - Weekly","topic":"summary","unit":"dollars_weekly","table_id":"G02","abs_column":"Median_tot_prsnl_inc_weekly","dimensions":{},"is_total":true,"is_derived":false}],"meta":{"pagination":{"total":5,"limit":50,"offset":0,"has_more":false}}}}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/data/demographics":{"get":{"tags":["Demographics"],"summary":"Query demographics","description":"Unified demographics endpoint. Combine parameters to express what you want.\n\n**Point lookup:** `?lat=-33.87&lng=151.21` (defaults to SA1, use `boundary_type` to change)\n\n**Single boundary:** `?boundary_id=sa2:117011325`\n\n**Multiple boundaries:** `?boundary_id=sa1:123,sa1:456` (add `&aggregate=true` to aggregate)\n\n**Browse by type:** `?boundary_type=sa2` (paginated, supports filter/sort/contained_by)\n\n**Segment query:** Add `sex`, `age_min`, `age_max` to any single-boundary query with a `topics` value.\nReturns `segment_pct` (percentage of boundary population in the segment).","operationId":"demographics_unified_get_v1_data_demographics_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"lat","in":"query","required":false,"schema":{"anyOf":[{"type":"number","maximum":90,"minimum":-90},{"type":"null"}],"description":"Latitude of the point.","title":"Lat"},"description":"Latitude of the point."},{"name":"lng","in":"query","required":false,"schema":{"anyOf":[{"type":"number","maximum":180,"minimum":-180},{"type":"null"}],"description":"Longitude of the point.","title":"Lng"},"description":"Longitude of the point."},{"name":"boundary_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Boundary ID(s), comma-separated (e.g. `sa2:117011325` or `sa1:123,sa1:456`). Max 100.","title":"Boundary Id"},"description":"Boundary ID(s), comma-separated (e.g. `sa2:117011325` or `sa1:123,sa1:456`). Max 100."},{"name":"boundary_type","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/BoundaryType"},{"type":"null"}],"description":"Boundary type for point resolution or browse mode (e.g. `sa2`, `lga`).","title":"Boundary Type"},"description":"Boundary type for point resolution or browse mode (e.g. `sa2`, `lga`)."},{"name":"topics","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated topic IDs (e.g. `age,income`). Use `all` for everything. Default: `summary`.","title":"Topics"},"description":"Comma-separated topic IDs (e.g. `age,income`). Use `all` for everything. Default: `summary`."},{"name":"fields","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated API field paths (e.g. `summary.population.persons,medians.age`). Overrides `topics`.","title":"Fields"},"description":"Comma-separated API field paths (e.g. `summary.population.persons,medians.age`). Overrides `topics`."},{"name":"census_year","in":"query","required":false,"schema":{"type":"integer","description":"Census year.","default":2021,"title":"Census Year"},"description":"Census year."},{"name":"sex","in":"query","required":false,"schema":{"enum":["male","female","persons"],"type":"string","description":"Sex filter: `male`, `female`, or `persons`.","default":"persons","title":"Sex"},"description":"Sex filter: `male`, `female`, or `persons`."},{"name":"age_min","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":120,"minimum":0},{"type":"null"}],"description":"Minimum age (inclusive).","title":"Age Min"},"description":"Minimum age (inclusive)."},{"name":"age_max","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":999,"minimum":0},{"type":"null"}],"description":"Maximum age (inclusive).","title":"Age Max"},"description":"Maximum age (inclusive)."},{"name":"aggregate","in":"query","required":false,"schema":{"type":"boolean","description":"Aggregate results across multiple boundaries.","default":false,"title":"Aggregate"},"description":"Aggregate results across multiple boundaries."},{"name":"contained_by","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Spatial filter: parent boundary_id (e.g. `lga:17200`).","title":"Contained By"},"description":"Spatial filter: parent boundary_id (e.g. `lga:17200`)."},{"name":"filter","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter expression: `field.op.value` (semicolon-separated).","title":"Filter"},"description":"Filter expression: `field.op.value` (semicolon-separated)."},{"name":"sort","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Sort: `field.direction` (e.g. `summary.population.persons.desc`).","title":"Sort"},"description":"Sort: `field.direction` (e.g. `summary.population.persons.desc`)."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"description":"Page size (browse mode).","default":25,"title":"Limit"},"description":"Page size (browse mode)."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Pagination offset.","default":0,"title":"Offset"},"description":"Pagination offset."}],"responses":{"200":{"description":"Demographic data (shape varies by query mode).","content":{"application/json":{"schema":{},"examples":{"point_lookup":{"summary":"Point lookup","description":"GET /v1/data/demographics?lat=-33.87&lng=151.21","value":{"data":{"boundary_id":"sa1:11703136526","boundary_name":"SA1 11703136526","census_year":2021,"summary":{"population":{"persons":410,"male":205,"female":205}}},"meta":{"demographics":{"topics_included":["summary"],"topics_available":["age","income","housing"]}}}},"segment_query":{"summary":"Segment query","description":"GET /v1/data/demographics?boundary_id=sa1:123&topics=income&sex=female&age_min=25&age_max=44","value":{"data":{"boundary_id":"sa1:11703136526","segment":{"topic":"income","sex":"female","age_range":[25,44]},"total_in_segment":85,"total_boundary_population":410,"segment_pct":20.73,"values":{"$1_149_per_week":12,"$150_299_per_week":18,"$300_399_per_week":22}}}},"aggregate":{"summary":"Aggregate by boundary type","description":"GET /v1/data/demographics?boundary_type=sa2&aggregate=true&fields=summary.population.persons","value":{"data":{"boundary_type":"sa2","boundary_count":2310,"fields":{"summary.population.persons":{"count":2310,"sum":25700000,"mean":11126.0,"median":9800,"min":0,"max":85000,"p25":5200,"p75":15400}}}}},"derived_percentages":{"summary":"Derived percentages","description":"GET /v1/data/demographics?boundary_id=sa2:117011325&fields=summary.population.persons,derived.pct_indigenous,derived.pct_seniors_65_plus","value":{"data":{"boundary_id":"sa2:117011325","boundary_name":"Sydney - Haymarket - The Rocks","census_year":2021,"summary":{"population":{"persons":32000}},"derived":{"pct_indigenous":1.8,"pct_seniors_65_plus":12.4}},"meta":{"demographics":{"topics_included":["summary"],"topics_available":["age","income","housing"]}}}},"browse_list":{"summary":"Browse by type (paginated)","description":"GET /v1/data/demographics?boundary_type=sa2&limit=2","value":{"data":[{"boundary_id":"sa2:101011001","boundary_name":"Queanbeyan","census_year":2021,"summary":{"population":{"persons":14200}}},{"boundary_id":"sa2:101011002","boundary_name":"Canberra East","census_year":2021,"summary":{"population":{"persons":11800}}}],"meta":{"pagination":{"total":2310,"limit":2,"offset":0,"has_more":true}}}}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["Demographics"],"summary":"Query demographics for a polygon","description":"Query demographic data for boundaries intersecting a GeoJSON polygon.\n\nDraw a polygon on a map and get demographics for the area.\nReturns either individual boundary results (with `overlap_fraction`) or\narea-weighted aggregated statistics (`aggregate: true`).\n\nAccepts the same field/topic/output-control parameters as the GET endpoint\nfor schema parity. Segment filters (`sex`, `age_min`, `age_max`) are not\nsupported for polygon queries and will return 400 if set.\n\nUse `topics` or `fields` to control which data is returned.\nUse `limit`/`offset` to paginate non-aggregate boundary results.","operationId":"demographics_unified_post_v1_data_demographics_post","security":[{"HTTPBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnifiedPolygonRequest"}}}},"responses":{"200":{"description":"Demographic data for boundaries intersecting the polygon.","content":{"application/json":{"schema":{},"examples":{"polygon_individual":{"summary":"Individual boundary results","description":"Non-aggregate polygon query returns each intersecting boundary with its overlap fraction.","value":{"data":{"boundary_type":"sa2","boundary_count":3,"boundaries":[{"boundary_id":"sa2:117011325","boundary_name":"Sydney - Haymarket - The Rocks","overlap_fraction":0.852,"summary":{"population":{"persons":32000}}},{"boundary_id":"sa2:117011326","boundary_name":"Darlinghurst","overlap_fraction":0.415,"summary":{"population":{"persons":18500}}},{"boundary_id":"sa2:117011327","boundary_name":"Surry Hills","overlap_fraction":0.123,"summary":{"population":{"persons":22000}}}]}}},"polygon_aggregate":{"summary":"Aggregated polygon results","description":"Area-weighted aggregate. Count fields are multiplied by overlap_fraction; medians use population-weighted averages.","value":{"data":{"boundary_type":"sa2","boundary_count":3,"fields":{"summary.population.persons":{"value":42946.0},"medians.age":{"value":33.2}}}}}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/data/enrich":{"post":{"tags":["Enrich"],"summary":"Enrich locations with boundary and datapack data","description":"Batch-enrich locations with boundary resolution and datapack data.\n\nFor each location, resolves the containing boundaries and attaches enrichment\ndata from the requested datapacks.\n\n**Datapacks available**: `demographics`, `fundraising`.\n\n**Limits**: Up to 100 locations per request.\n\n**Example request body**:\n```json\n{\n  \"locations\": [\n    {\"id\": \"loc1\", \"location\": {\"lng\": 151.2093, \"lat\": -33.8688}}\n  ],\n  \"resolve\": [\"sa2\", \"lga\"],\n  \"enrich\": [{\"datapack\": \"demographics\", \"fields\": \"population.total\"}],\n  \"output_boundary\": \"sa2\"\n}\n```","operationId":"enrich_endpoint_v1_data_enrich_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnrichLocationsRequest"}}},"required":true},"responses":{"200":{"description":"Enriched location results with resolved boundaries and attached datapack data.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResponseEnvelope_EnrichLocationsResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/data/incidents":{"get":{"tags":["Incidents"],"summary":"List incidents","description":"List and filter real-time incidents.\n\nSupports hierarchical filtering: `type` (incident category), `event_type` (specific\nevent category), `event_subtype` (granular subtype), plus status, state, severity,\nsource, boundary intersection, radius search, and time range.\n\nBoth `type` and `status` accept comma-separated values for multi-value filtering\n(e.g. `?status=active,upcoming` or `?type=traffic,fire`).\n\n**Ordering**: Radius queries default to closest-first (`sort=distance`) and include\n`distance_km` in each result. Use `sort=newest` to revert to newest-first ordering.\nNon-spatial queries always order by newest first.\n\nTime range filters: `since`/`until` filter on `started_at`, `ends_after`/`ends_before`\nfilter on `expected_end_at` (useful for finding planned outages within a window).\n\nEach incident includes structured location fields: `locality` (suburb/area name),\n`road_name` (affected road), and `location_detail` (free-text location description).\n\nSet `detail=true` to include full geometry, description, and raw source data per\nincident (same fields as the single-incident detail endpoint).","operationId":"incidents_list_endpoint_v1_data_incidents_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"type","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by incident type (traffic, fire, power, weather). Comma-separated for multiple.","title":"Type"},"description":"Filter by incident type (traffic, fire, power, weather). Comma-separated for multiple."},{"name":"event_type","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by event type (e.g. roadworks, crash, flood, fire_vegetation).","title":"Event Type"},"description":"Filter by event type (e.g. roadworks, crash, flood, fire_vegetation)."},{"name":"event_subtype","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by event subtype (e.g. flash_flood, planned_roadworks, multi_vehicle).","title":"Event Subtype"},"description":"Filter by event subtype (e.g. flash_flood, planned_roadworks, multi_vehicle)."},{"name":"status","in":"query","required":false,"schema":{"type":"string","description":"Filter by status (active, upcoming, resolved, expired). Comma-separated for multiple.","default":"active","title":"Status"},"description":"Filter by status (active, upcoming, resolved, expired). Comma-separated for multiple."},{"name":"state","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by state (QLD, NSW, etc.).","title":"State"},"description":"Filter by state (QLD, NSW, etc.)."},{"name":"severity","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by severity (minor, moderate, major, extreme).","title":"Severity"},"description":"Filter by severity (minor, moderate, major, extreme)."},{"name":"source","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by source_id.","title":"Source"},"description":"Filter by source_id."},{"name":"boundary_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Incidents intersecting this boundary (e.g. `lga:17200`).","title":"Boundary Id"},"description":"Incidents intersecting this boundary (e.g. `lga:17200`)."},{"name":"lat","in":"query","required":false,"schema":{"anyOf":[{"type":"number","maximum":90,"minimum":-90},{"type":"null"}],"description":"Latitude for radius search.","title":"Lat"},"description":"Latitude for radius search."},{"name":"lng","in":"query","required":false,"schema":{"anyOf":[{"type":"number","maximum":180,"minimum":-180},{"type":"null"}],"description":"Longitude for radius search.","title":"Lng"},"description":"Longitude for radius search."},{"name":"radius_km","in":"query","required":false,"schema":{"anyOf":[{"type":"number","maximum":500,"exclusiveMinimum":0},{"type":"null"}],"description":"Search radius in km (requires lat, lng).","title":"Radius Km"},"description":"Search radius in km (requires lat, lng)."},{"name":"since","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Incidents started after this ISO datetime.","title":"Since"},"description":"Incidents started after this ISO datetime."},{"name":"until","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Incidents started before this ISO datetime.","title":"Until"},"description":"Incidents started before this ISO datetime."},{"name":"ends_after","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Incidents with expected_end_at after this ISO datetime.","title":"Ends After"},"description":"Incidents with expected_end_at after this ISO datetime."},{"name":"ends_before","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Incidents with expected_end_at before this ISO datetime.","title":"Ends Before"},"description":"Incidents with expected_end_at before this ISO datetime."},{"name":"detail","in":"query","required":false,"schema":{"type":"boolean","description":"Include full detail per incident (geometry, description, source data).","default":false,"title":"Detail"},"description":"Include full detail per incident (geometry, description, source data)."},{"name":"sort","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Sort order: 'distance' (closest first) or 'newest' (most recent first). Default: 'distance' for radius queries, 'newest' otherwise.","title":"Sort"},"description":"Sort order: 'distance' (closest first) or 'newest' (most recent first). Default: 'distance' for radius queries, 'newest' otherwise."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"description":"Page size.","default":50,"title":"Limit"},"description":"Page size."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Pagination offset.","default":0,"title":"Offset"},"description":"Pagination offset."}],"responses":{"200":{"description":"Paginated list of incidents. Use detail=true for full geometry and source data.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResponseEnvelope_Union_list_IncidentSummary___list_IncidentDetail___"},"examples":{"summary":{"summary":"Default (detail=false)","value":{"data":[{"incident_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","source_id":"qld_traffic","incident_type":"traffic","event_type":"roadworks","event_subtype":"planned_roadworks","severity":"moderate","status":"active","title":"Planned roadworks — Bruce Highway (Caboolture)","state":"QLD","locality":"Caboolture","road_name":"Bruce Highway","location_detail":"Between exits 41 and 45","centroid":{"type":"Point","coordinates":[153.035,-27.465]},"started_at":"2026-02-17T10:30:00Z","expected_end_at":"2026-02-17T18:00:00Z"}],"meta":{"pagination":{"total":42,"limit":50,"offset":0,"has_more":false}}}},"detail":{"summary":"With detail=true","value":{"data":[{"incident_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","source_id":"energex_outages","source_incident_id":"energex_EVT-12345","incident_type":"power","event_type":"unplanned","severity":"moderate","status":"active","title":"Unplanned power outage — PADDINGTON, RED HILL","description":"Status: In Progress. Storm damage","state":"QLD","locality":"PADDINGTON, RED HILL","location_detail":"Latrobe Tce, Given Tce","geometry":{"type":"Polygon","coordinates":[[[153.0,-27.46],[153.02,-27.46],[153.02,-27.48],[153.0,-27.48],[153.0,-27.46]]]},"centroid":{"type":"Point","coordinates":[153.01,-27.47]},"data":{"EVENT_ID":"EVT-12345","TYPE":"Unplanned","STATUS":"In Progress","CUSTOMERS_AFFECTED":350,"SUBURBS":"PADDINGTON, RED HILL","STREETS":"Latrobe Tce, Given Tce","REASON":"Storm damage"},"started_at":"2026-02-17T06:00:00Z","expected_end_at":"2026-02-17T14:00:00Z","created_at":"2026-02-17T06:01:00Z","updated_at":"2026-02-17T08:30:00Z"}],"meta":{"pagination":{"total":42,"limit":50,"offset":0,"has_more":false}}}}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/data/incidents/sources":{"get":{"tags":["Incidents"],"summary":"List incident sources","description":"List all available incident data sources.\n\nEach source represents a government or utility data feed (e.g. QLD Traffic,\nQFD Fire, Energex/Ergon Outages, BOM Weather). Includes sync status information.","operationId":"incidents_sources_endpoint_v1_data_incidents_sources_get","responses":{"200":{"description":"All registered incident data sources.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResponseEnvelope_list_IncidentSource__"},"example":{"data":[{"source_id":"qld_traffic","source_type":"traffic","state":"QLD","label":"QLD Traffic","description":"Real-time traffic incidents from QLD Traffic","api_url":"https://api.qldtraffic.qld.gov.au/v2/events","sync_interval_seconds":300,"active":true,"last_synced_at":"2026-02-17T03:45:01Z","last_sync_status":"success"}],"meta":{}}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/data/incidents/summary":{"get":{"tags":["Incidents"],"summary":"Incident summary counts","description":"Get aggregated incident counts by type hierarchy.\n\nReturns counts grouped by `incident_type` → `event_type` → `event_subtype`.\nSupports the same filters as the list endpoint (type, status, severity, spatial, time range)\nbut without pagination — the response is a single summary object. Both `type` and `status`\naccept comma-separated values (e.g. `?status=active,upcoming`).\n\nThe response includes two top-level keys:\n\n- **`types`** — filtered counts matching the current query parameters.\n- **`catalog`** — an **unfiltered** list of every `incident_type` / `event_type` /\n  `event_subtype` combination that exists in the database. This is always the full\n  set regardless of filters, so UIs can render complete filter menus (including\n  categories with a zero count in the current view).","operationId":"incidents_summary_endpoint_v1_data_incidents_summary_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"type","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by incident type (traffic, fire, power, weather). Comma-separated for multiple.","title":"Type"},"description":"Filter by incident type (traffic, fire, power, weather). Comma-separated for multiple."},{"name":"event_type","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by event type (e.g. roadworks, crash, flood, fire_vegetation).","title":"Event Type"},"description":"Filter by event type (e.g. roadworks, crash, flood, fire_vegetation)."},{"name":"event_subtype","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by event subtype (e.g. flash_flood, planned_roadworks, multi_vehicle).","title":"Event Subtype"},"description":"Filter by event subtype (e.g. flash_flood, planned_roadworks, multi_vehicle)."},{"name":"status","in":"query","required":false,"schema":{"type":"string","description":"Filter by status (active, upcoming, resolved, expired). Comma-separated for multiple.","default":"active","title":"Status"},"description":"Filter by status (active, upcoming, resolved, expired). Comma-separated for multiple."},{"name":"state","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by state (QLD, NSW, etc.).","title":"State"},"description":"Filter by state (QLD, NSW, etc.)."},{"name":"severity","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by severity (minor, moderate, major, extreme).","title":"Severity"},"description":"Filter by severity (minor, moderate, major, extreme)."},{"name":"source","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by source_id.","title":"Source"},"description":"Filter by source_id."},{"name":"boundary_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Incidents intersecting this boundary (e.g. `lga:17200`).","title":"Boundary Id"},"description":"Incidents intersecting this boundary (e.g. `lga:17200`)."},{"name":"lat","in":"query","required":false,"schema":{"anyOf":[{"type":"number","maximum":90,"minimum":-90},{"type":"null"}],"description":"Latitude for radius search.","title":"Lat"},"description":"Latitude for radius search."},{"name":"lng","in":"query","required":false,"schema":{"anyOf":[{"type":"number","maximum":180,"minimum":-180},{"type":"null"}],"description":"Longitude for radius search.","title":"Lng"},"description":"Longitude for radius search."},{"name":"radius_km","in":"query","required":false,"schema":{"anyOf":[{"type":"number","maximum":500,"exclusiveMinimum":0},{"type":"null"}],"description":"Search radius in km (requires lat, lng).","title":"Radius Km"},"description":"Search radius in km (requires lat, lng)."},{"name":"since","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Incidents started after this ISO datetime.","title":"Since"},"description":"Incidents started after this ISO datetime."},{"name":"until","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Incidents started before this ISO datetime.","title":"Until"},"description":"Incidents started before this ISO datetime."},{"name":"ends_after","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Incidents with expected_end_at after this ISO datetime.","title":"Ends After"},"description":"Incidents with expected_end_at after this ISO datetime."},{"name":"ends_before","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Incidents with expected_end_at before this ISO datetime.","title":"Ends Before"},"description":"Incidents with expected_end_at before this ISO datetime."}],"responses":{"200":{"description":"Aggregated counts by incident_type, event_type, and event_subtype.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResponseEnvelope_IncidentSummaryResponse_"},"example":{"data":{"total":42,"types":[{"incident_type":"fire","count":5,"event_types":[{"event_type":"fire_vegetation","count":3,"subtypes":[{"event_subtype":"going","count":2},{"event_subtype":"controlled","count":1}]},{"event_type":"fire_structure","count":2,"subtypes":[]}]},{"incident_type":"traffic","count":37,"event_types":[{"event_type":"crash","count":12,"subtypes":[{"event_subtype":"multi_vehicle","count":8},{"count":4}]},{"event_type":"roadworks","count":25,"subtypes":[{"event_subtype":"planned_roadworks","count":25}]}]}],"catalog":[{"incident_type":"fire","event_types":[{"event_type":"fire_structure","subtypes":[null]},{"event_type":"fire_vegetation","subtypes":["controlled","going"]}]},{"incident_type":"power","event_types":[{"event_type":"planned","subtypes":[null]},{"event_type":"unplanned","subtypes":[null]}]},{"incident_type":"traffic","event_types":[{"event_type":"crash","subtypes":["multi_vehicle",null]},{"event_type":"roadworks","subtypes":["planned_roadworks"]}]}]},"meta":{}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/data/incidents/{incident_id}":{"get":{"tags":["Incidents"],"summary":"Get incident detail","description":"Get full detail for a single incident.\n\nIncludes geometry, raw source data, structured location fields (`locality`,\n`road_name`, `location_detail`), and full description with impact details.","operationId":"incidents_detail_endpoint_v1_data_incidents__incident_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"incident_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Incident Id"}}],"responses":{"200":{"description":"Full incident detail including geometry and source data.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResponseEnvelope_IncidentDetail_"},"example":{"data":{"incident_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","source_id":"energex_outages","source_incident_id":"energex_EVT-12345","incident_type":"power","event_type":"unplanned","severity":"moderate","status":"active","title":"Unplanned power outage — PADDINGTON, RED HILL","description":"Status: In Progress. Storm damage","state":"QLD","locality":"PADDINGTON, RED HILL","location_detail":"Latrobe Tce, Given Tce","geometry":{"type":"Polygon","coordinates":[[[153.0,-27.46],[153.02,-27.46],[153.02,-27.48],[153.0,-27.48],[153.0,-27.46]]]},"centroid":{"type":"Point","coordinates":[153.01,-27.47]},"data":{"EVENT_ID":"EVT-12345","TYPE":"Unplanned","STATUS":"In Progress","CUSTOMERS_AFFECTED":350,"SUBURBS":"PADDINGTON, RED HILL","STREETS":"Latrobe Tce, Given Tce","REASON":"Storm damage"},"started_at":"2026-02-17T06:00:00Z","expected_end_at":"2026-02-17T14:00:00Z","created_at":"2026-02-17T06:01:00Z","updated_at":"2026-02-17T08:30:00Z"},"meta":{}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/data/incidents/search":{"post":{"tags":["Incidents"],"summary":"Search incidents by polygon","description":"Search for incidents intersecting a GeoJSON geometry.\n\nSend a GeoJSON Polygon or MultiPolygon in the request body. Optionally filter\nby incident type, status, and severity. Both `type` and `status` accept\ncomma-separated values (e.g. `\"status\": \"active,upcoming\"`). Results include\nstructured location fields (`locality`, `road_name`, `location_detail`).\n\n**Ordering**: Defaults to closest-first (`sort: \"distance\"`) based on the polygon\ncentroid, with `distance_km` in each result. Use `sort: \"newest\"` for newest-first.\n\nSet `detail: true` in the body to include full geometry, description, and\nraw source data per incident.","operationId":"incidents_search_endpoint_v1_data_incidents_search_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncidentSearchRequest"}}},"required":true},"responses":{"200":{"description":"Incidents intersecting the provided geometry. Use detail=true for full data.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResponseEnvelope_Union_list_IncidentSummary___list_IncidentDetail___"},"examples":{"summary":{"summary":"Default (detail=false)","value":{"data":[{"incident_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","source_id":"qld_traffic","incident_type":"traffic","event_type":"roadworks","event_subtype":"planned_roadworks","severity":"moderate","status":"active","title":"Planned roadworks — Bruce Highway (Caboolture)","state":"QLD","locality":"Caboolture","road_name":"Bruce Highway","location_detail":"Between exits 41 and 45","centroid":{"type":"Point","coordinates":[153.035,-27.465]},"started_at":"2026-02-17T10:30:00Z","expected_end_at":"2026-02-17T18:00:00Z"}],"meta":{"pagination":{"total":42,"limit":50,"offset":0,"has_more":false}}}},"detail":{"summary":"With detail=true","value":{"data":[{"incident_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","source_id":"energex_outages","source_incident_id":"energex_EVT-12345","incident_type":"power","event_type":"unplanned","severity":"moderate","status":"active","title":"Unplanned power outage — PADDINGTON, RED HILL","description":"Status: In Progress. Storm damage","state":"QLD","locality":"PADDINGTON, RED HILL","location_detail":"Latrobe Tce, Given Tce","geometry":{"type":"Polygon","coordinates":[[[153.0,-27.46],[153.02,-27.46],[153.02,-27.48],[153.0,-27.48],[153.0,-27.46]]]},"centroid":{"type":"Point","coordinates":[153.01,-27.47]},"data":{"EVENT_ID":"EVT-12345","TYPE":"Unplanned","STATUS":"In Progress","CUSTOMERS_AFFECTED":350,"SUBURBS":"PADDINGTON, RED HILL","STREETS":"Latrobe Tce, Given Tce","REASON":"Storm damage"},"started_at":"2026-02-17T06:00:00Z","expected_end_at":"2026-02-17T14:00:00Z","created_at":"2026-02-17T06:01:00Z","updated_at":"2026-02-17T08:30:00Z"}],"meta":{"pagination":{"total":42,"limit":50,"offset":0,"has_more":false}}}}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/data/targeting/meta":{"get":{"tags":["Targeting"],"summary":"Generate Meta Ads targeting circles","description":"Generate Meta Ads targeting circles from boundary polygons.\n\nDecomposes one or more statistical boundaries into a set of inclusion\n(positive) and exclusion (negative) circles that approximate the boundary\nshape for use with Meta Ads Manager custom location targeting.\n\n**Caching:** Results are cached by boundary hash. Repeat requests return\ninstantly from cache regardless of boundary size. Pass `nocache=true` to\nforce recomputation.\n\n**Async for large boundaries:** Boundaries with total area > 100 km² are\nautomatically offloaded to a background worker. The endpoint returns 202\nwith a `poll_url` to check progress.\n\n**How it works:**\n\n1. Fetches and unions the requested boundary geometries\n2. Analyses shape complexity (concavity ratio)\n3. Auto-sizes the circle radius based on total area and complexity\n4. Generates inclusion circles via grid sampling inside the boundary\n5. Generates exclusion circles for overshoot areas outside the boundary\n6. Ensures total circles stay within Meta's 200-location limit\n\n**Output formats:**\n\n- `json` (default): structured response with inclusion/exclusion arrays\n- `csv`: downloadable CSV with type, latitude, longitude, radius, distance_unit columns\n\n**Limits:**\n\n- 1–20 boundary IDs per request\n- Combined output capped at 200 circles (Meta's limit)\n- Radius range: 1.0–80 km (0.62–50 miles)","operationId":"meta_targeting_endpoint_v1_data_targeting_meta_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"boundary_id","in":"query","required":true,"schema":{"type":"string","description":"Comma-separated boundary IDs to target (e.g. 'sa2:117011325,lga:17200'). Max 20.","title":"Boundary Id"},"description":"Comma-separated boundary IDs to target (e.g. 'sa2:117011325,lga:17200'). Max 20."},{"name":"radius_unit","in":"query","required":false,"schema":{"enum":["kilometer","mile"],"type":"string","description":"Unit for output radius values.","default":"kilometer","title":"Radius Unit"},"description":"Unit for output radius values."},{"name":"mode","in":"query","required":false,"schema":{"enum":["circles","postal"],"type":"string","description":"Targeting mode: 'circles' (default) or 'postal' (ZIP/postcode inclusion + exclusion circles).","default":"circles","title":"Mode"},"description":"Targeting mode: 'circles' (default) or 'postal' (ZIP/postcode inclusion + exclusion circles)."},{"name":"format","in":"query","required":false,"schema":{"enum":["json","csv"],"type":"string","description":"Output format: json or csv.","default":"json","title":"Format"},"description":"Output format: json or csv."},{"name":"nocache","in":"query","required":false,"schema":{"type":"boolean","description":"Skip cache and recompute (dev/debug only).","default":false,"title":"Nocache"},"description":"Skip cache and recompute (dev/debug only)."}],"responses":{"200":{"description":"Meta Ads targeting circles.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResponseEnvelope_MetaTargetingResult_"},"examples":{"basic":{"summary":"Targeting circles for an SA2","value":{"data":{"inclusion":[{"latitude":-27.4698,"longitude":153.0251,"radius":3.2,"distance_unit":"kilometer"},{"latitude":-27.475,"longitude":153.03,"radius":1.6,"distance_unit":"kilometer"}],"exclusion":[],"total_circles":2,"inclusion_count":2,"exclusion_count":0,"radius_km":3.2,"radius_min_km":1.6,"boundary_ids":["sa2:117011325"],"area_km2":42.5,"concavity_ratio":0.95}}}}}}},"202":{"description":"Job created for large boundary (poll for result)."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/data/targeting/meta/jobs":{"post":{"tags":["Targeting"],"summary":"Create async targeting job","description":"Create an async targeting job (explicit async path).\n\nAlways creates a background job regardless of boundary size.\nIf the result is already cached, returns 200 with the completed result.","operationId":"create_targeting_job_v1_data_targeting_meta_jobs_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"boundary_id","in":"query","required":true,"schema":{"type":"string","description":"Comma-separated boundary IDs to target (e.g. 'sa2:117011325,lga:17200'). Max 20.","title":"Boundary Id"},"description":"Comma-separated boundary IDs to target (e.g. 'sa2:117011325,lga:17200'). Max 20."},{"name":"radius_unit","in":"query","required":false,"schema":{"enum":["kilometer","mile"],"type":"string","description":"Unit for output radius values.","default":"kilometer","title":"Radius Unit"},"description":"Unit for output radius values."},{"name":"mode","in":"query","required":false,"schema":{"enum":["circles","postal"],"type":"string","description":"Targeting mode: 'circles' (default) or 'postal' (ZIP/postcode inclusion + exclusion circles).","default":"circles","title":"Mode"},"description":"Targeting mode: 'circles' (default) or 'postal' (ZIP/postcode inclusion + exclusion circles)."}],"responses":{"202":{"description":"Job created for background processing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResponseEnvelope_TargetingJobCreated_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/data/targeting/meta/jobs/{job_id}":{"get":{"tags":["Targeting"],"summary":"Poll targeting job status","description":"Poll the status of a targeting job.\n\nReturns the job status, and the result when completed.\nJobs are account-scoped — you can only access jobs created by your account.","operationId":"targeting_job_status_v1_data_targeting_meta_jobs__job_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}}],"responses":{"200":{"description":"Current status and result of a targeting job.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResponseEnvelope_TargetingJobStatus_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/tiles/{layer}/{z}/{x}/{y}.pbf":{"get":{"tags":["Tiles"],"summary":"Vector tile for a boundary layer","description":"Serve MVT vector tiles for any boundary type.\n\n**URL template:** `/v1/tiles/{layer}/{z}/{x}/{y}.pbf?apikey=YOUR_KEY`\n\nReturns a protobuf-encoded Mapbox Vector Tile containing boundary polygons\nthat intersect the requested tile. Each feature includes properties:\n`boundary_id`, `name`, `state`, and (for flood layers) `flood_risk` and `flood_type`.\n\nResponses are cached for 1 hour and gzip-compressed when accepted.\nEmpty tiles return 204 No Content.","operationId":"get_tile_v1_tiles__layer___z___x___y__pbf_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"layer","in":"path","required":true,"schema":{"type":"string","description":"Boundary type to serve as tile layer. AU: `sa1`–`sa4`, `lga`, `poa`, `sal`, `ced`, `sed`, `gccsa`, `ste`, `sua`, `ucl`, `ra`, `sos`, `sosr`, `iloc`, `iare`, `ireg`, `flood`. US: `us_state`, `us_county`, `us_tract`, `us_bg`, `us_place`, `us_cousub`, `us_cd`, `us_sldu`, `us_sldl`, `us_cbsa`, `us_csa`, `us_unsd`, `us_elsd`, `us_scsd`, `us_aiannh`, `us_region`, `us_division`, `us_zcta`, `us_ua`, `us_puma`.","title":"Layer"},"description":"Boundary type to serve as tile layer. AU: `sa1`–`sa4`, `lga`, `poa`, `sal`, `ced`, `sed`, `gccsa`, `ste`, `sua`, `ucl`, `ra`, `sos`, `sosr`, `iloc`, `iare`, `ireg`, `flood`. US: `us_state`, `us_county`, `us_tract`, `us_bg`, `us_place`, `us_cousub`, `us_cd`, `us_sldu`, `us_sldl`, `us_cbsa`, `us_csa`, `us_unsd`, `us_elsd`, `us_scsd`, `us_aiannh`, `us_region`, `us_division`, `us_zcta`, `us_ua`, `us_puma`."},{"name":"z","in":"path","required":true,"schema":{"type":"integer","maximum":22,"minimum":0,"description":"Zoom level","title":"Z"},"description":"Zoom level"},{"name":"x","in":"path","required":true,"schema":{"type":"integer","minimum":0,"description":"Tile column","title":"X"},"description":"Tile column"},{"name":"y","in":"path","required":true,"schema":{"type":"integer","minimum":0,"description":"Tile row","title":"Y"},"description":"Tile row"},{"name":"apikey","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key (for tile URL templates)","title":"Apikey"},"description":"API key (for tile URL templates)"}],"responses":{"200":{"description":"Mapbox Vector Tile (MVT) protobuf.","content":{"application/json":{"schema":{}},"application/x-protobuf":{}}},"204":{"description":"Empty tile (no features)"},"400":{"description":"Invalid tile coordinates or layer"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/maps":{"get":{"summary":"List maps","tags":["Maps"],"security":[{"bearerAuth":[]}],"description":"This endpoint returns all maps in the account. You can expand the results to include layer details with `expand[\"layer\"]`. Results paginated.\n\nExample request:\n```\ncurl --location --request GET 'https://api.mapulus.com/api/v1/maps' \\\n--header 'Content-Type: application/json' \\\n--header 'Authorization: Bearer <your-token>' \\\n--data '{\n          \"expand\": [\"layer\"]\n        }'\n}'","parameters":[{"name":"expand[]","in":"query","description":"expand layers (Optional)","required":false,"enum":["layer"],"schema":{"type":"string"}}],"responses":{"200":{"description":"Success: Returns all maps in account. Results paginated.","content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","example":"list"},"data":{"type":"array","items":{"type":"object","properties":{"object":{"type":"string","example":"map"},"id":{"type":"string","format":"uuid"},"title":{"type":"string"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["object","id","title","created_at","updated_at"]}},"pages":{"type":"object","properties":{"object":{"type":"string","example":"pages"},"total_pages":{"type":"number","example":1},"current_page":{"type":"number","example":1},"next_page":{"nullable":true,"type":"number","example":null},"prev_page":{"nullable":true,"type":"number","example":null}},"required":["object","total_pages","current_page"]},"total_count":{"type":"integer","example":1}},"required":["object","data","pages","total_count"]}}}},"401":{"description":"Unauthorized: Invalid API Key or does not have the correct permission to access resource.","content":{"application/json":{"schema":{"type":"object","properties":{"errors":{"type":"object","properties":{"unauthorized":{"type":"array","items":{"type":"string","example":"You are not authorized to perform this action"}}},"required":["unauthorized"]}},"required":["errors"]}}}}}}},"/api/v1/maps/{id}":{"get":{"summary":"Retrieve a map","tags":["Maps"],"security":[{"bearerAuth":[]}],"description":"This endpoint returns a single locations on a map when provided a valid map id. You can expand the results to include layer details with `expand[\"layer\"]`.\n\nExample request:\n```\ncurl --location --request GET 'https://api.mapulus.com/api/v1/maps/<map-id>' \\\n--header 'Content-Type: application/json' \\\n--header 'Authorization: Bearer <your-token>' \\\n--data '{\n          \"expand\": [\"layer\"]\n        }'\n}'","parameters":[{"name":"id","in":"path","description":"Map ID (Required)","required":true,"schema":{"type":"string"}},{"name":"expand[]","in":"query","description":"expand layers (Optional)","required":false,"enum":["layer"],"schema":{"type":"string"}}],"responses":{"200":{"description":"Succcess: Returns map","content":{"application/json":{"schema":{"properties":{"object":{"type":"string","example":"map"},"id":{"type":"string","format":"uuid"},"title":{"type":"string"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["object","id","title","created_at","updated_at"]}}}},"401":{"description":"Unauthorized: Invalid API Key or does not have the correct permission to access resource.","content":{"application/json":{"schema":{"type":"object","properties":{"errors":{"type":"object","properties":{"unauthorized":{"type":"array","items":{"type":"string","example":"You are not authorized to perform this action"}}},"required":["unauthorized"]}},"required":["errors"]}}}},"404":{"description":"RecordNotFound: Location not found in account.","content":{"application/json":{"schema":{"type":"object","properties":{"errors":{"type":"object","properties":{"404":{"type":"array","items":{"type":"string","example":"Not found"}}}}},"required":["errors"]}}}}}}},"/api/v1/locations":{"get":{"summary":"List locations","tags":["Locations"],"security":[{"bearerAuth":[]}],"description":"This endpoint returns all locations in the account. <br>\n         <br>\n        The results can be filtered by:  <br>\n        <ul>\n        <li>Map ID</li>\n        <li>Layer ID</li>\n        <li>External ID</li>\n        <li>Nearest: Returns up to the 24 closest locations from a provided <b>latitude</b> and <b>longitude</b> or <b>address</b> and travel <b>profile</b> (\"driving\", \"cycling\", \"walking\"). This can be sorted by <b>time</b> or <b>distance</b>. Note: If the source location is on water or inaccessible, the server will respond with the nearest locations by direct line and not include a duration or distance.</li>\n        </ul>\n        Example request:\n```\ncurl --location --request GET 'https://api.mapulus.com/api/v1/locations' \\\n--header 'Content-Type: application/json' \\\n--header 'Authorization: Bearer <your-token>' \\\n--data '{\n    \"map_id\": \"<your-map-id>\",\n    \"nearest\": {\n      \"lat\": \"-27.52851640781164\",\n      \"lon\": \"152.97921775875503\",\n      \"sort_by\": \"time\",\n      \"profile\": \"driving\",\n      \"limit\": \"10\"\n    }\n}'","parameters":[{"name":"map_id","in":"query","description":"Filter: Map ID","required":false,"schema":{"type":"string"}},{"name":"layer_id","in":"query","description":"Filter: Layer ID","required":false,"schema":{"type":"string"}},{"name":"external_id","in":"query","description":"Filter: External ID","required":false,"schema":{"type":"string"}},{"name":"nearest[lat]","in":"query","description":"Latitude for nearest filter","required":false,"schema":{"type":"number"}},{"name":"nearest[lon]","in":"query","description":"Longitude for nearest filter","required":false,"schema":{"type":"number"}},{"name":"nearest[address]","in":"query","description":"Address for nearest filter (must have either a lat/lon or an address)","required":false,"schema":{"type":"number"}},{"name":"nearest[sort_by]","in":"query","description":"Sort by \"distance\" or \"time\" for nearest filter","required":false,"schema":{"type":"string"}},{"name":"nearest[profile]","in":"query","description":"Profile for routing (\"driving\", \"cycling\", \"walking\") for nearest filter","required":false,"schema":{"type":"string"}},{"name":"nearest[live_traffic]","in":"query","description":"Include live traffic (\"true\" or \"false\") for nearest filter","required":false,"schema":{"type":"string"}},{"name":"nearest[limit]","in":"query","description":"Limit the number of locations returned for nearest filter. Max 24.","required":false,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Succcess: Returns all locations in account.","content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","example":"list"},"data":{"type":"array","items":{"type":"object","properties":{"object":{"type":"string","example":"location"},"id":{"type":"string","format":"uuid"},"lat":{"type":"number","format":"float","nullable":true,"example":-27.4704528},"lon":{"type":"number","format":"float","nullable":true,"example":153.0260341},"label":{"nullable":true,"type":"string","example":null},"title":{"nullable":true,"type":"string","example":"Head Office"},"address":{"nullable":true,"type":"string","example":"Brisbane, Australia"},"external_id":{"nullable":true,"type":"string","example":null},"geocoding_error":{"nullable":true,"type":"boolean","example":false},"geocoding_error_type":{"nullable":true,"type":"string","example":null},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"travel_contour":{"nullable":true,"type":"boolean"},"contour_mode":{"nullable":true,"type":"string","example":"driving"},"contour_metric":{"nullable":true,"type":"string","example":"minutes"},"contour_style":{"nullable":true,"type":"string","example":"polygons"},"contour_minutes":{"nullable":true,"type":"string","example":"15"},"map_id":{"type":"string","format":"uuid"},"layer_id":{"type":"string","format":"uuid"},"custom_attributes":{"type":"array","items":{"type":"object","properties":{"object":{"type":"string","example":"custom_attribute"},"name":{"type":"string","example":"Location Type"},"value":{"nullable":true,"type":"string","example":"Public Store"},"custom_attribute_id":{"type":"string","format":"uuid"},"custom_attribute_value_id":{"type":"string","format":"uuid"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["name","name","value","custom_attribute_id","object","custom_attribute_value_id","updated_at","created_at"]}}},"required":["object","id","lat","lon","created_at","updated_at","custom_attributes","map_id","layer_id"]}},"pages":{"type":"object","properties":{"object":{"type":"string","example":"pages"},"total_pages":{"type":"number","example":1},"current_page":{"type":"number","example":1},"next_page":{"nullable":true,"type":"number","example":null},"prev_page":{"nullable":true,"type":"number","example":null}},"required":["object","total_pages","current_page"]},"total_count":{"type":"integer","example":1}},"required":["object","data"]}}}},"401":{"description":"Unauthorized: Invalid API Key or does not have the correct perimission to access resource.","content":{"application/json":{"schema":{"type":"object","properties":{"errors":{"type":"object","properties":{"unauthorized":{"type":"array","items":{"type":"string","example":"You are not authorized to perform this action"}}},"required":["unauthorized"]}},"required":["errors"]}}}},"422":{"description":"Unprocessable Entity: The request because the request was well-formed, but for example the map_id or layer_id is not valid.","content":{"application/json":{"schema":{"type":"object","properties":{"errors":{"type":"object","properties":{"UnprocessableEntity":{"type":"array","items":{"type":"string","example":"Layer ID '6786b817-814c-4845-bf48-d43878f42ae6' not valid"}}}}},"required":["errors"]}}}}}},"post":{"summary":"Create a location.","tags":["Locations"],"security":[{"bearerAuth":[]}],"description":"This endpoint creates a single location when provided a valid layer_id in the JSON body. Locations must also have either a valid address or latitude and longitude. When adding `custom_attributes`, if the custom_attribute does not already exist on the layer (based on name), you can set the `create_or_update_custom_attributes` in the main body of the JSON or `create_or_update_custom_attribute` in the nested attribute object to create or ignore it. Without this flag, new custom_attributes will return an error.\nExample request:\n```\ncurl --location 'https://api.mapulus.com/api/v1/locations' \\\n--header 'Content-Type: application/json' \\\n--header 'Authorization: Bearer <your-token>' \\\n--data '{\n  \"lat\": -27.4704528,\n  \"lon\": 153.0260341,\n  \"label\": null,\n  \"title\": \"Head Office\",\n  \"address\": \"Brisbane, Australia\",\n  \"external_id\": null,\n  \"travel_contour\": true,\n  \"contour_mode\": \"driving\",\n  \"contour_metric\": \"minutes\",\n  \"contour_style\": \"polygons\",\n  \"contour_minutes\": \"15\",\n  \"layer_id\": \"<layer-id>\",\n  \"create_or_update_custom_attributes\": true,\n  \"custom_attributes\": [\n    {\n      \"object\": \"custom_attribute\",\n      \"name\": \"Location Type\",\n      \"value\": \"Public Store\",\n      \"create_or_update_custom_attribute\": false\n    }\n  ]\n}'\n","parameters":[],"responses":{"200":{"description":"Success: Creates a single location.","content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","example":"location"},"id":{"type":"string","format":"uuid"},"lat":{"type":"number","format":"float","nullable":true,"example":-27.4704528},"lon":{"type":"number","format":"float","nullable":true,"example":153.0260341},"label":{"nullable":true,"type":"string","example":null},"title":{"nullable":true,"type":"string","example":"Head Office"},"address":{"nullable":true,"type":"string","example":"Brisbane, Australia"},"external_id":{"nullable":true,"type":"string","example":null},"geocoding_error":{"nullable":true,"type":"boolean","example":false},"geocoding_error_type":{"nullable":true,"type":"string","example":null},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"travel_contour":{"nullable":true,"type":"boolean"},"contour_mode":{"nullable":true,"type":"string","example":"driving"},"contour_metric":{"nullable":true,"type":"string","example":"minutes"},"contour_style":{"nullable":true,"type":"string","example":"polygons"},"contour_minutes":{"nullable":true,"type":"string","example":"15"},"map_id":{"type":"string","format":"uuid"},"layer_id":{"type":"string","format":"uuid"},"custom_attributes":{"type":"array","items":{"type":"object","properties":{"object":{"type":"string","example":"custom_attribute"},"name":{"type":"string","example":"Location Type"},"value":{"nullable":true,"type":"string","example":"Public Store"},"custom_attribute_id":{"type":"string","format":"uuid"},"custom_attribute_value_id":{"type":"string","format":"uuid"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["name","name","value","custom_attribute_id","object","custom_attribute_value_id","updated_at","created_at"]}}},"required":["object","id","lat","lon","created_at","updated_at","custom_attributes","map_id","layer_id"]}}}},"422":{"description":"Unprocessable Entity: The request because the request was well-formed, but the custom attribute does not exist.","content":{"application/json":{"schema":{"type":"object","properties":{"errors":{"type":"object","properties":{"UnprocessableEntity":{"type":"array","items":{"type":"string","example":"Custom attribute 'Location Type' not found on the defined layer. You can automatically create or ignore the missing attributes by adding the `create_or_update_custom_attributes` flag in the main body or `create_or_update_custom_attribute` on the individual custom attribute."}}}}},"required":["errors"]}}}},"401":{"description":"Unauthorized: Invalid API Key or does not have the correct permission to access resource.","content":{"application/json":{"schema":{"type":"object","properties":{"errors":{"type":"object","properties":{"unauthorized":{"type":"array","items":{"type":"string","example":"You are not authorized to perform this action"}}},"required":["unauthorized"]}},"required":["errors"]}}}}},"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","example":"location"},"lat":{"type":"number","format":"float","nullable":true,"example":-27.4704528},"lon":{"type":"number","format":"float","nullable":true,"example":153.0260341},"label":{"nullable":true,"type":"string","example":null},"title":{"nullable":true,"type":"string","example":"Head Office"},"address":{"nullable":true,"type":"string","example":"Brisbane, Australia"},"external_id":{"nullable":true,"type":"string","example":null},"travel_contour":{"nullable":true,"type":"boolean"},"contour_mode":{"nullable":true,"type":"string","example":"driving"},"contour_metric":{"nullable":true,"type":"string","example":"minutes"},"contour_style":{"nullable":true,"type":"string","example":"polygons"},"contour_minutes":{"nullable":true,"type":"string","example":"15"},"layer_id":{"type":"string","format":"uuid"},"create_or_update_custom_attributes":{"type":"boolen","example":true},"custom_attributes":{"type":"array","items":{"type":"object","properties":{"object":{"type":"string","example":"custom_attribute"},"name":{"type":"string","example":"Location Type"},"value":{"nullable":true,"type":"string","example":"Public Store"},"create_or_update_custom_attribute":{"type":"boolen","example":false}},"required":["name","id","object"]}}},"required":["layer_id"]}}},"description":"Body."}}},"/api/v1/locations/{id}":{"get":{"summary":"Retrieve a location","tags":["Locations"],"security":[{"bearerAuth":[]}],"description":"This endpoint returns a single location on a map when provided a valid location id.\n        Example Request:\n\n```\ncurl --location 'https://api.mapulus.com/api/v1/locations/<location-id>' \\\n--header 'Authorization: Bearer <your-token>' \\\n","parameters":[{"name":"id","in":"path","description":"Location ID (Required)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Success: Returns single location.","content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","example":"location"},"id":{"type":"string","format":"uuid"},"lat":{"type":"number","format":"float","nullable":true,"example":-27.4704528},"lon":{"type":"number","format":"float","nullable":true,"example":153.0260341},"label":{"nullable":true,"type":"string","example":null},"title":{"nullable":true,"type":"string","example":"Head Office"},"address":{"nullable":true,"type":"string","example":"Brisbane, Australia"},"external_id":{"nullable":true,"type":"string","example":null},"geocoding_error":{"nullable":true,"type":"boolean","example":false},"geocoding_error_type":{"nullable":true,"type":"string","example":null},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"travel_contour":{"nullable":true,"type":"boolean"},"contour_mode":{"nullable":true,"type":"string","example":"driving"},"contour_metric":{"nullable":true,"type":"string","example":"minutes"},"contour_style":{"nullable":true,"type":"string","example":"polygons"},"contour_minutes":{"nullable":true,"type":"string","example":"15"},"map_id":{"type":"string","format":"uuid"},"layer_id":{"type":"string","format":"uuid"},"custom_attributes":{"type":"array","items":{"type":"object","properties":{"object":{"type":"string","example":"custom_attribute"},"name":{"type":"string","example":"Location Type"},"value":{"nullable":true,"type":"string","example":"Public Store"},"custom_attribute_id":{"type":"string","format":"uuid"},"custom_attribute_value_id":{"type":"string","format":"uuid"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["name","name","value","custom_attribute_id","object","custom_attribute_value_id","updated_at","created_at"]}}},"required":["object","id","lat","lon","created_at","updated_at","custom_attributes","map_id","layer_id"]}}}},"401":{"description":"Unauthorized: Invalid API Key or does not have the correct perimission to access resource.","content":{"application/json":{"schema":{"type":"object","properties":{"errors":{"type":"object","properties":{"unauthorized":{"type":"array","items":{"type":"string","example":"You are not authorized to perform this action"}}},"required":["unauthorized"]}},"required":["errors"]}}}},"404":{"description":"RecordNotFound: Location not found in account.","content":{"application/json":{"schema":{"type":"object","properties":{"errors":{"type":"object","properties":{"404":{"type":"array","items":{"type":"string","example":"Not found"}}}}},"required":["errors"]}}}}}},"delete":{"summary":"Delete a location.","tags":["Locations"],"security":[{"bearerAuth":[]}],"description":"This endpoint delete a single location.\nExample request:\n```\ncurl --location --request DELETE 'https://api.mapulus.com/api/v1/locations/<location-id>' \\\n--header 'Content-Type: application/json' \\\n--header 'Authorization: Bearer <your-token>' \\\n","parameters":[{"name":"id","in":"path","description":"Location ID (Required)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Success: Deletes a single Location.","content":{"application/json":{"schema":{"type":"object","required":["object","id","deleted"],"properties":{"object":{"type":"string","example":"location"},"id":{"type":"string","format":"uuid","example":"eff2db83-c82f-4ce3-af4b-90d46c7615ec"},"deleted":{"type":"boolean","example":true}}}}}}}},"put":{"summary":"Update a location.","tags":["Locations"],"security":[{"bearerAuth":[]}],"description":"This endpoint updates a location. Locations must also have either a valid `address` or `lat` and `lon`. When adding `custom_attributes`, if the custom_attribute does not already exist on the layer (based on name), you can set the `create_or_update_custom_attributes` in the main body of the JSON or `create_or_update_custom_attribute` in the nested attribute object to create or ignore it. Without this flag, new custom_attributes will return an error. Moving the location to new layers is possible by passing a new `layer_id` in the JSON body.\nExample request:\n\n```\ncurl --location --request PUT 'https://api.mapulus.com/api/v1/locations/<location-id>' \\\n--header 'Content-Type: application/json' \\\n--header 'Authorization: Bearer <your-token>' \\\n--data '{\n  \"object\": \"location\",\n  \"lat\": -27.4704528,\n  \"lon\": 153.0260341,\n  \"label\": null,\n  \"title\": \"Head Office\",\n  \"address\": \"Brisbane, Australia\",\n  \"external_id\": null,\n  \"travel_contour\": true,\n  \"contour_mode\": \"driving\",\n  \"contour_metric\": \"minutes\",\n  \"contour_style\": \"polygons\",\n  \"contour_minutes\": \"15\",\n  \"layer_id\": \"0b942634-814f-42f7-82f5-7f4d06213275\",\n  \"create_or_update_custom_attributes\": true,\n  \"custom_attributes\": [\n    {\n      \"object\": \"custom_attribute\",\n      \"name\": \"Location Type\",\n      \"value\": \"Public Store\",\n      \"create_or_update_custom_attribute\": false\n    }\n  ]\n}'\n","parameters":[{"name":"id","in":"path","description":"Location ID (Required)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Success: Updates a single location.","content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","example":"location"},"id":{"type":"string","format":"uuid"},"lat":{"type":"number","format":"float","nullable":true,"example":-27.4704528},"lon":{"type":"number","format":"float","nullable":true,"example":153.0260341},"label":{"nullable":true,"type":"string","example":null},"title":{"nullable":true,"type":"string","example":"Head Office"},"address":{"nullable":true,"type":"string","example":"Brisbane, Australia"},"external_id":{"nullable":true,"type":"string","example":null},"geocoding_error":{"nullable":true,"type":"boolean","example":false},"geocoding_error_type":{"nullable":true,"type":"string","example":null},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"travel_contour":{"nullable":true,"type":"boolean"},"contour_mode":{"nullable":true,"type":"string","example":"driving"},"contour_metric":{"nullable":true,"type":"string","example":"minutes"},"contour_style":{"nullable":true,"type":"string","example":"polygons"},"contour_minutes":{"nullable":true,"type":"string","example":"15"},"map_id":{"type":"string","format":"uuid"},"layer_id":{"type":"string","format":"uuid"},"custom_attributes":{"type":"array","items":{"type":"object","properties":{"object":{"type":"string","example":"custom_attribute"},"name":{"type":"string","example":"Location Type"},"value":{"nullable":true,"type":"string","example":"Public Store"},"custom_attribute_id":{"type":"string","format":"uuid"},"custom_attribute_value_id":{"type":"string","format":"uuid"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["name","name","value","custom_attribute_id","object","custom_attribute_value_id","updated_at","created_at"]}}},"required":["object","id","lat","lon","created_at","updated_at","custom_attributes","map_id","layer_id"]}}}},"401":{"description":"Unauthorized: Invalid API Key or does not have the correct permission to access resource.","content":{"application/json":{"schema":{"type":"object","properties":{"errors":{"type":"object","properties":{"unauthorized":{"type":"array","items":{"type":"string","example":"You are not authorized to perform this action"}}},"required":["unauthorized"]}},"required":["errors"]}}}},"404":{"description":"RecordNotFound: Location not found.","content":{"application/json":{"schema":{"type":"object","properties":{"errors":{"type":"object","properties":{"404":{"type":"array","items":{"type":"string","example":"Not found"}}}}},"required":["errors"]}}}},"422":{"description":"Unprocessable Entity: The server was unable to understand or process the entity. For example an invalid layer_id.","content":{"application/json":{"schema":{"type":"object","properties":{"errors":{"type":"object","properties":{"UnprocessableEntity":{"type":"array","items":{"type":"string","example":"Layer ID '6786b817-814c-4845-bf48-d43878f42ae6' not valid"}}}}},"required":["errors"]}}}}},"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","example":"location"},"lat":{"type":"number","format":"float","nullable":true,"example":-27.4704528},"lon":{"type":"number","format":"float","nullable":true,"example":153.0260341},"label":{"nullable":true,"type":"string","example":null},"title":{"nullable":true,"type":"string","example":"Head Office"},"address":{"nullable":true,"type":"string","example":"Brisbane, Australia"},"external_id":{"nullable":true,"type":"string","example":null},"travel_contour":{"nullable":true,"type":"boolean"},"contour_mode":{"nullable":true,"type":"string","example":"driving"},"contour_metric":{"nullable":true,"type":"string","example":"minutes"},"contour_style":{"nullable":true,"type":"string","example":"polygons"},"contour_minutes":{"nullable":true,"type":"string","example":"15"},"layer_id":{"type":"string","format":"uuid"},"create_or_update_custom_attributes":{"type":"boolen","example":true},"custom_attributes":{"type":"array","items":{"type":"object","properties":{"object":{"type":"string","example":"custom_attribute"},"name":{"type":"string","example":"Location Type"},"value":{"nullable":true,"type":"string","example":"Public Store"},"create_or_update_custom_attribute":{"type":"boolen","example":false}},"required":["name","id","object"]}}},"required":["layer_id"]}}},"description":"Body"}}}},"components":{"schemas":{"BoundaryLookupResponse":{"properties":{"location":{"$ref":"#/components/schemas/PointLocation","description":"The queried point."},"boundaries":{"additionalProperties":{"$ref":"#/components/schemas/BoundaryRef"},"type":"object","title":"Boundaries","description":"Containing boundaries keyed by type (e.g. `sa2`, `lga`)."},"planning_regions":{"items":{"$ref":"#/components/schemas/PlanningRegionRef"},"type":"array","title":"Planning Regions","description":"Matching planning regions."},"h3_indices":{"additionalProperties":{"type":"string"},"type":"object","title":"H3 Indices","description":"H3 hexagonal indices at resolutions 3-9."}},"type":"object","required":["location"],"title":"BoundaryLookupResponse","description":"Result of resolving a point to its containing boundaries."},"BoundaryRef":{"properties":{"id":{"type":"string","title":"Id","description":"Boundary identifier (e.g. `sa2:117011325`)."},"name":{"type":"string","title":"Name","description":"Human-readable boundary name."}},"type":"object","required":["id","name"],"title":"BoundaryRef","description":"Reference to a statistical boundary."},"BoundarySearchItem":{"properties":{"id":{"type":"string","title":"Id","description":"Client-provided identifier for this location."},"location":{"$ref":"#/components/schemas/PointLocation"}},"type":"object","required":["id","location"],"title":"BoundarySearchItem","description":"A single location in a batch search request."},"BoundarySearchRequest":{"properties":{"locations":{"items":{"$ref":"#/components/schemas/BoundarySearchItem"},"type":"array","maxItems":100,"title":"Locations","description":"Locations to resolve (max 100)."}},"type":"object","required":["locations"],"title":"BoundarySearchRequest","description":"Request body for batch boundary search."},"BoundarySearchResponse":{"properties":{"results":{"items":{"$ref":"#/components/schemas/BoundarySearchResultItem"},"type":"array","title":"Results","description":"Boundary results for each input location."}},"type":"object","required":["results"],"title":"BoundarySearchResponse","description":"Response containing boundary results for each location."},"BoundarySearchResultItem":{"properties":{"id":{"type":"string","title":"Id","description":"Client-provided identifier."},"location":{"$ref":"#/components/schemas/PointLocation"},"boundaries":{"additionalProperties":{"$ref":"#/components/schemas/BoundaryRef"},"type":"object","title":"Boundaries","description":"Containing boundaries keyed by type."},"planning_regions":{"items":{"$ref":"#/components/schemas/PlanningRegionRef"},"type":"array","title":"Planning Regions","description":"Matching planning regions."},"h3_indices":{"additionalProperties":{"type":"string"},"type":"object","title":"H3 Indices","description":"H3 hexagonal indices."}},"type":"object","required":["id","location"],"title":"BoundarySearchResultItem","description":"Result for a single location in a batch search."},"BoundaryType":{"type":"string","enum":["sa1","sa2","sa3","sa4","lga","poa","sal","ced","sed","gccsa","ste","sua","ucl","ra","sos","sosr","iloc","iare","ireg","flood","us_state","us_county","us_tract","us_bg","us_place","us_cousub","us_cd","us_sldu","us_sldl","us_cbsa","us_csa","us_unsd","us_elsd","us_scsd","us_aiannh","us_region","us_division","us_zcta","us_ua","us_puma"],"title":"BoundaryType","description":"Statistical and administrative boundary types (AU + US)."},"BoundaryTypeInfo":{"properties":{"type":{"type":"string","title":"Type","description":"Boundary type code (e.g. `sa2`, `us_county`)."},"label":{"type":"string","title":"Label","description":"Human-readable label."},"country_code":{"type":"string","title":"Country Code","description":"ISO 3166-1 alpha-2 country code (AU or US)."}},"type":"object","required":["type","label","country_code"],"title":"BoundaryTypeInfo","description":"Metadata for a single boundary type."},"BoundaryTypesResponse":{"properties":{"AU":{"items":{"$ref":"#/components/schemas/BoundaryTypeInfo"},"type":"array","title":"Au","description":"Australian boundary types."},"US":{"items":{"$ref":"#/components/schemas/BoundaryTypeInfo"},"type":"array","title":"Us","description":"US boundary types."}},"type":"object","required":["AU","US"],"title":"BoundaryTypesResponse","description":"Available boundary types grouped by country."},"DemographicsMeta":{"properties":{"topics_included":{"items":{"type":"string"},"type":"array","title":"Topics Included","description":"Topics included in the response."},"topics_available":{"items":{"type":"string"},"type":"array","title":"Topics Available","description":"Additional topics available but not requested."}},"type":"object","required":["topics_included"],"title":"DemographicsMeta","description":"Demographics-specific metadata returned with census data endpoints."},"EnrichLayerConfig":{"properties":{"datapack":{"type":"string","enum":["demographics","fundraising"],"title":"Datapack","description":"Datapack name: `demographics` or `fundraising`."},"fields":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Fields","description":"Comma-separated field paths to include (e.g. `population.total`)."}},"type":"object","required":["datapack"],"title":"EnrichLayerConfig","description":"Configuration for a single enrichment datapack."},"EnrichLocationItem":{"properties":{"id":{"type":"string","title":"Id","description":"Client-provided identifier for this location."},"location":{"$ref":"#/components/schemas/PointLocation"}},"type":"object","required":["id","location"],"title":"EnrichLocationItem","description":"A single location to enrich."},"EnrichLocationsRequest":{"properties":{"locations":{"items":{"$ref":"#/components/schemas/EnrichLocationItem"},"type":"array","maxItems":100,"title":"Locations","description":"Locations to enrich (max 100)."},"resolve":{"items":{"$ref":"#/components/schemas/BoundaryType"},"type":"array","title":"Resolve","description":"Boundary types to resolve for each location."},"enrich":{"items":{"$ref":"#/components/schemas/EnrichLayerConfig"},"type":"array","title":"Enrich","description":"Datapacks to attach to each location."},"output_boundary":{"$ref":"#/components/schemas/BoundaryType","description":"Boundary type to use as the key for enrichment data lookups.","default":"sa2"}},"type":"object","required":["locations"],"title":"EnrichLocationsRequest","description":"Request body for batch location enrichment.","examples":[{"enrich":[{"datapack":"demographics","fields":"population.total"}],"locations":[{"id":"loc1","location":{"lat":-33.8688,"lng":151.2093}}],"output_boundary":"sa2","resolve":["sa2","lga"]}]},"EnrichLocationsResponse":{"properties":{"locations":{"items":{"$ref":"#/components/schemas/EnrichedLocationItem"},"type":"array","title":"Locations","description":"Enriched results for each input location."},"total":{"type":"integer","title":"Total","description":"Total number of input locations."},"enriched":{"type":"integer","title":"Enriched","description":"Number of successfully enriched locations."},"failed":{"type":"integer","title":"Failed","description":"Number of locations that failed enrichment."}},"type":"object","required":["locations","total","enriched","failed"],"title":"EnrichLocationsResponse","description":"Response containing enriched location results."},"EnrichedLocationItem":{"properties":{"id":{"type":"string","title":"Id","description":"Client-provided identifier."},"location":{"$ref":"#/components/schemas/PointLocation"},"boundaries":{"additionalProperties":{"$ref":"#/components/schemas/BoundaryRef"},"type":"object","title":"Boundaries","description":"Resolved boundary references by type (e.g. `{\"sa2\": {\"id\": \"sa2:117011325\", \"name\": \"...\"}}`)."},"enrichment":{"additionalProperties":{"additionalProperties":true,"type":"object"},"type":"object","title":"Enrichment","description":"Attached datapack data keyed by datapack name (e.g. `{\"demographics\": {...}}`)."},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error","description":"Error message if enrichment failed for this location."}},"type":"object","required":["id","location"],"title":"EnrichedLocationItem","description":"A single enriched location result."},"GeoJSONExportRequest":{"properties":{"boundary_ids":{"items":{"type":"string"},"type":"array","maxItems":500,"title":"Boundary Ids","description":"Boundary IDs to export (max 500)."},"simplify":{"type":"string","pattern":"^(full|medium|low)$","title":"Simplify","description":"Simplification level: full, medium, or low.","default":"medium"}},"type":"object","required":["boundary_ids"],"title":"GeoJSONExportRequest","description":"Request body for batch GeoJSON export by specific boundary IDs."},"GeoJSONGeometry":{"properties":{"type":{"type":"string","title":"Type","description":"GeoJSON geometry type (Polygon, MultiPolygon, etc.)."},"coordinates":{"items":{},"type":"array","title":"Coordinates","description":"GeoJSON coordinates array."}},"type":"object","required":["type","coordinates"],"title":"GeoJSONGeometry","description":"GeoJSON geometry for search request body."},"GeoJsonGeometry":{"properties":{"type":{"type":"string","enum":["Polygon","MultiPolygon"],"title":"Type","description":"GeoJSON geometry type."},"coordinates":{"items":{},"type":"array","title":"Coordinates","description":"GeoJSON coordinates array."}},"type":"object","required":["type","coordinates"],"title":"GeoJsonGeometry","description":"A GeoJSON geometry (Polygon or MultiPolygon)."},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"IncidentDetail":{"properties":{"incident_id":{"type":"string","title":"Incident Id"},"source_id":{"type":"string","title":"Source Id"},"source_incident_id":{"type":"string","title":"Source Incident Id"},"incident_type":{"type":"string","title":"Incident Type"},"event_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Event Type"},"event_subtype":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Event Subtype"},"severity":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Severity"},"status":{"type":"string","title":"Status"},"title":{"type":"string","title":"Title"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"state":{"type":"string","title":"State"},"locality":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Locality","description":"Suburb or locality name."},"road_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Road Name","description":"Affected road name."},"location_detail":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Location Detail","description":"Free-text location description."},"geometry":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Geometry","description":"GeoJSON geometry object."},"centroid":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Centroid","description":"GeoJSON point (centroid)."},"data":{"additionalProperties":true,"type":"object","title":"Data","description":"Source-specific properties."},"started_at":{"type":"string","format":"date-time","title":"Started At"},"expected_end_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Expected End At"},"resolved_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Resolved At"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"distance_km":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Distance Km","description":"Distance in km from the query point."}},"type":"object","required":["incident_id","source_id","source_incident_id","incident_type","status","title","state","started_at","created_at","updated_at"],"title":"IncidentDetail","description":"Full detail for a single incident."},"IncidentEventTypeCount":{"properties":{"event_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Event Type"},"count":{"type":"integer","title":"Count"},"subtypes":{"items":{"$ref":"#/components/schemas/IncidentSubtypeCount"},"type":"array","title":"Subtypes","default":[]}},"type":"object","required":["count"],"title":"IncidentEventTypeCount","description":"Count for a single event_type within an incident_type."},"IncidentSearchRequest":{"properties":{"geometry":{"$ref":"#/components/schemas/GeoJSONGeometry","description":"GeoJSON geometry to search within."},"type":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Type","description":"Filter by incident types."},"event_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Event Type","description":"Filter by event type (e.g. roadworks, crash, flood)."},"event_subtype":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Event Subtype","description":"Filter by event subtype (e.g. flash_flood, planned_roadworks)."},"status":{"type":"string","title":"Status","description":"Filter by status (active, upcoming, resolved, expired). Comma-separated for multiple.","default":"active"},"severity":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Severity","description":"Filter by severity."},"source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source","description":"Filter by source_id."},"state":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"State","description":"Filter by state (QLD, NSW, etc.)."},"since":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Since","description":"Incidents started after this ISO datetime."},"until":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Until","description":"Incidents started before this ISO datetime."},"ends_after":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ends After","description":"Incidents with expected_end_at after this ISO datetime."},"ends_before":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ends Before","description":"Incidents with expected_end_at before this ISO datetime."},"detail":{"type":"boolean","title":"Detail","description":"Include full detail (geometry, description, source data).","default":false},"sort":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sort","description":"Sort order: 'distance' or 'newest'. Default: 'distance'."},"limit":{"type":"integer","maximum":500.0,"minimum":1.0,"title":"Limit","default":50},"offset":{"type":"integer","minimum":0.0,"title":"Offset","default":0}},"type":"object","required":["geometry"],"title":"IncidentSearchRequest","description":"Request body for POST /incidents/search."},"IncidentSource":{"properties":{"source_id":{"type":"string","title":"Source Id"},"source_type":{"type":"string","title":"Source Type"},"state":{"type":"string","title":"State"},"label":{"type":"string","title":"Label"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"api_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Api Url"},"sync_interval_seconds":{"type":"integer","title":"Sync Interval Seconds"},"active":{"type":"boolean","title":"Active"},"last_synced_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Synced At"},"last_sync_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Sync Status"}},"type":"object","required":["source_id","source_type","state","label","sync_interval_seconds","active"],"title":"IncidentSource","description":"An incident data source."},"IncidentSubtypeCatalog":{"properties":{"event_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Event Type"},"subtypes":{"items":{"anyOf":[{"type":"string"},{"type":"null"}]},"type":"array","title":"Subtypes","default":[]}},"type":"object","title":"IncidentSubtypeCatalog","description":"Known subtypes within an event_type (for UI toggles)."},"IncidentSubtypeCount":{"properties":{"event_subtype":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Event Subtype"},"count":{"type":"integer","title":"Count"}},"type":"object","required":["count"],"title":"IncidentSubtypeCount","description":"Count for a single event_subtype within an event_type."},"IncidentSummary":{"properties":{"incident_id":{"type":"string","title":"Incident Id"},"source_id":{"type":"string","title":"Source Id"},"incident_type":{"type":"string","title":"Incident Type"},"event_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Event Type"},"event_subtype":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Event Subtype"},"severity":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Severity"},"status":{"type":"string","title":"Status"},"title":{"type":"string","title":"Title"},"state":{"type":"string","title":"State"},"locality":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Locality","description":"Suburb or locality name."},"road_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Road Name","description":"Affected road name."},"location_detail":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Location Detail","description":"Free-text location description."},"centroid":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Centroid","description":"GeoJSON point (centroid)."},"started_at":{"type":"string","format":"date-time","title":"Started At"},"expected_end_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Expected End At"},"resolved_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Resolved At"},"distance_km":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Distance Km","description":"Distance in km from the query point."}},"type":"object","required":["incident_id","source_id","incident_type","status","title","state","started_at"],"title":"IncidentSummary","description":"Summary for list responses (no raw geometry — just centroid)."},"IncidentSummaryResponse":{"properties":{"total":{"type":"integer","title":"Total","description":"Total number of matching incidents."},"types":{"items":{"$ref":"#/components/schemas/IncidentTypeSummaryCount"},"type":"array","title":"Types","description":"Filtered counts grouped by incident_type → event_type → event_subtype.","default":[]},"catalog":{"items":{"$ref":"#/components/schemas/IncidentTypeCatalog"},"type":"array","title":"Catalog","description":"Unfiltered list of all known incident_type → event_type → event_subtype combinations in the database. Always returned regardless of query filters, so UIs can render complete filter menus including zero-count categories.","default":[]}},"type":"object","required":["total"],"title":"IncidentSummaryResponse","description":"Aggregated incident counts grouped by incident_type → event_type → event_subtype.\n\nThe ``types`` array contains counts matching the current filters.\nThe ``catalog`` array is **always unfiltered** — it lists every\nincident_type / event_type / event_subtype combination that has ever\nappeared in the database, regardless of the query filters applied to\n``types``. This is useful for building UI filter toggles that show all\npossible categories (including those with a zero count in the current view)."},"IncidentTypeCatalog":{"properties":{"incident_type":{"type":"string","title":"Incident Type"},"event_types":{"items":{"$ref":"#/components/schemas/IncidentSubtypeCatalog"},"type":"array","title":"Event Types","default":[]}},"type":"object","required":["incident_type"],"title":"IncidentTypeCatalog","description":"Known event_type → subtypes for an incident_type (for UI toggles)."},"IncidentTypeSummaryCount":{"properties":{"incident_type":{"type":"string","title":"Incident Type"},"count":{"type":"integer","title":"Count"},"event_types":{"items":{"$ref":"#/components/schemas/IncidentEventTypeCount"},"type":"array","title":"Event Types","default":[]}},"type":"object","required":["incident_type","count"],"title":"IncidentTypeSummaryCount","description":"Count for a single incident_type."},"MetaCircle":{"properties":{"latitude":{"type":"number","title":"Latitude","description":"Circle centre latitude."},"longitude":{"type":"number","title":"Longitude","description":"Circle centre longitude."},"radius":{"type":"number","title":"Radius","description":"Circle radius."},"distance_unit":{"type":"string","title":"Distance Unit","description":"Radius unit (kilometer or mile)."},"address":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Address","description":"Reverse-geocoded address of circle center."}},"type":"object","required":["latitude","longitude","radius","distance_unit"],"title":"MetaCircle","description":"A single targeting circle for Meta Ads."},"MetaPostalTarget":{"properties":{"key":{"type":"string","title":"Key","description":"Meta Ads key (e.g. 'US:90210' or '2000')."},"code":{"type":"string","title":"Code","description":"Postal code (e.g. '90210')."},"name":{"type":"string","title":"Name","description":"Postal area name."},"boundary_id":{"type":"string","title":"Boundary Id","description":"Mapulus boundary_id (e.g. 'us_zcta:90210')."}},"type":"object","required":["key","code","name","boundary_id"],"title":"MetaPostalTarget","description":"A postal area used as a Meta Ads location target."},"MetaTargetingResult":{"properties":{"mode":{"type":"string","title":"Mode","description":"Targeting mode: 'circles' or 'postal'.","default":"circles"},"inclusion":{"items":{"$ref":"#/components/schemas/MetaCircle"},"type":"array","title":"Inclusion","description":"Inclusion (positive) circles."},"exclusion":{"items":{"$ref":"#/components/schemas/MetaCircle"},"type":"array","title":"Exclusion","description":"Exclusion (negative) circles."},"postal_targets":{"anyOf":[{"items":{"$ref":"#/components/schemas/MetaPostalTarget"},"type":"array"},{"type":"null"}],"title":"Postal Targets","description":"Postal inclusion targets (only in postal mode)."},"total_circles":{"type":"integer","title":"Total Circles","description":"Total number of circles (inclusion + exclusion)."},"inclusion_count":{"type":"integer","title":"Inclusion Count","description":"Number of inclusion circles."},"exclusion_count":{"type":"integer","title":"Exclusion Count","description":"Number of exclusion circles."},"postal_count":{"type":"integer","title":"Postal Count","description":"Number of postal inclusion targets.","default":0},"radius_km":{"type":"number","title":"Radius Km","description":"Maximum circle radius used (in km, regardless of output unit)."},"radius_min_km":{"type":"number","title":"Radius Min Km","description":"Minimum circle radius used (in km)."},"boundary_ids":{"items":{"type":"string"},"type":"array","title":"Boundary Ids","description":"Input boundary IDs."},"area_km2":{"type":"number","title":"Area Km2","description":"Total area of unioned boundaries in km²."},"concavity_ratio":{"type":"number","title":"Concavity Ratio","description":"Shape complexity (1.0 = convex, lower = more complex)."}},"type":"object","required":["inclusion","exclusion","total_circles","inclusion_count","exclusion_count","radius_km","radius_min_km","boundary_ids","area_km2","concavity_ratio"],"title":"MetaTargetingResult","description":"Result of Meta Ads targeting circle generation."},"PaginationMeta":{"properties":{"total":{"type":"integer","title":"Total","description":"Total number of matching records."},"limit":{"type":"integer","title":"Limit","description":"Maximum records returned per page."},"offset":{"type":"integer","title":"Offset","description":"Number of records skipped."},"has_more":{"type":"boolean","title":"Has More","description":"Whether more records exist beyond this page."}},"type":"object","required":["total","limit","offset","has_more"],"title":"PaginationMeta","description":"Pagination metadata for list responses."},"PlanningRegionRef":{"properties":{"region_id":{"type":"string","title":"Region Id","description":"Planning region identifier."},"region_type":{"type":"string","title":"Region Type","description":"Planning region type (e.g. `phn`)."},"name":{"type":"string","title":"Name","description":"Planning region name."},"state":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"State","description":"State or territory code."}},"type":"object","required":["region_id","region_type","name"],"title":"PlanningRegionRef","description":"Reference to a planning region."},"PointLocation":{"properties":{"lng":{"type":"number","maximum":180.0,"minimum":-180.0,"title":"Lng","description":"Longitude in decimal degrees."},"lat":{"type":"number","maximum":90.0,"minimum":-90.0,"title":"Lat","description":"Latitude in decimal degrees."}},"type":"object","required":["lng","lat"],"title":"PointLocation","description":"A geographic point as longitude/latitude."},"ResponseEnvelope_BoundaryLookupResponse_":{"properties":{"data":{"$ref":"#/components/schemas/BoundaryLookupResponse","description":"Response payload."},"meta":{"anyOf":[{"$ref":"#/components/schemas/ResponseMeta"},{"type":"null"}],"description":"Response metadata (pagination, request ID)."}},"type":"object","required":["data"],"title":"ResponseEnvelope[BoundaryLookupResponse]"},"ResponseEnvelope_BoundarySearchResponse_":{"properties":{"data":{"$ref":"#/components/schemas/BoundarySearchResponse","description":"Response payload."},"meta":{"anyOf":[{"$ref":"#/components/schemas/ResponseMeta"},{"type":"null"}],"description":"Response metadata (pagination, request ID)."}},"type":"object","required":["data"],"title":"ResponseEnvelope[BoundarySearchResponse]"},"ResponseEnvelope_BoundaryTypesResponse_":{"properties":{"data":{"$ref":"#/components/schemas/BoundaryTypesResponse","description":"Response payload."},"meta":{"anyOf":[{"$ref":"#/components/schemas/ResponseMeta"},{"type":"null"}],"description":"Response metadata (pagination, request ID)."}},"type":"object","required":["data"],"title":"ResponseEnvelope[BoundaryTypesResponse]"},"ResponseEnvelope_EnrichLocationsResponse_":{"properties":{"data":{"$ref":"#/components/schemas/EnrichLocationsResponse","description":"Response payload."},"meta":{"anyOf":[{"$ref":"#/components/schemas/ResponseMeta"},{"type":"null"}],"description":"Response metadata (pagination, request ID)."}},"type":"object","required":["data"],"title":"ResponseEnvelope[EnrichLocationsResponse]"},"ResponseEnvelope_IncidentDetail_":{"properties":{"data":{"$ref":"#/components/schemas/IncidentDetail","description":"Response payload."},"meta":{"anyOf":[{"$ref":"#/components/schemas/ResponseMeta"},{"type":"null"}],"description":"Response metadata (pagination, request ID)."}},"type":"object","required":["data"],"title":"ResponseEnvelope[IncidentDetail]"},"ResponseEnvelope_IncidentSummaryResponse_":{"properties":{"data":{"$ref":"#/components/schemas/IncidentSummaryResponse","description":"Response payload."},"meta":{"anyOf":[{"$ref":"#/components/schemas/ResponseMeta"},{"type":"null"}],"description":"Response metadata (pagination, request ID)."}},"type":"object","required":["data"],"title":"ResponseEnvelope[IncidentSummaryResponse]"},"ResponseEnvelope_MetaTargetingResult_":{"properties":{"data":{"$ref":"#/components/schemas/MetaTargetingResult","description":"Response payload."},"meta":{"anyOf":[{"$ref":"#/components/schemas/ResponseMeta"},{"type":"null"}],"description":"Response metadata (pagination, request ID)."}},"type":"object","required":["data"],"title":"ResponseEnvelope[MetaTargetingResult]"},"ResponseEnvelope_TargetingJobCreated_":{"properties":{"data":{"$ref":"#/components/schemas/TargetingJobCreated","description":"Response payload."},"meta":{"anyOf":[{"$ref":"#/components/schemas/ResponseMeta"},{"type":"null"}],"description":"Response metadata (pagination, request ID)."}},"type":"object","required":["data"],"title":"ResponseEnvelope[TargetingJobCreated]"},"ResponseEnvelope_TargetingJobStatus_":{"properties":{"data":{"$ref":"#/components/schemas/TargetingJobStatus","description":"Response payload."},"meta":{"anyOf":[{"$ref":"#/components/schemas/ResponseMeta"},{"type":"null"}],"description":"Response metadata (pagination, request ID)."}},"type":"object","required":["data"],"title":"ResponseEnvelope[TargetingJobStatus]"},"ResponseEnvelope_Union_list_IncidentSummary___list_IncidentDetail___":{"properties":{"data":{"anyOf":[{"items":{"$ref":"#/components/schemas/IncidentSummary"},"type":"array"},{"items":{"$ref":"#/components/schemas/IncidentDetail"},"type":"array"}],"title":"Data","description":"Response payload."},"meta":{"anyOf":[{"$ref":"#/components/schemas/ResponseMeta"},{"type":"null"}],"description":"Response metadata (pagination, request ID)."}},"type":"object","required":["data"],"title":"ResponseEnvelope[Union[list[IncidentSummary], list[IncidentDetail]]]"},"ResponseEnvelope_list_IncidentSource__":{"properties":{"data":{"items":{"$ref":"#/components/schemas/IncidentSource"},"type":"array","title":"Data","description":"Response payload."},"meta":{"anyOf":[{"$ref":"#/components/schemas/ResponseMeta"},{"type":"null"}],"description":"Response metadata (pagination, request ID)."}},"type":"object","required":["data"],"title":"ResponseEnvelope[list[IncidentSource]]"},"ResponseMeta":{"properties":{"request_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Request Id"},"pagination":{"anyOf":[{"$ref":"#/components/schemas/PaginationMeta"},{"type":"null"}]},"demographics":{"anyOf":[{"$ref":"#/components/schemas/DemographicsMeta"},{"type":"null"}],"description":"Demographics metadata (topics_included, topics_available)."},"sources":{"anyOf":[{"additionalProperties":{"$ref":"#/components/schemas/SourceFreshness"},"type":"object"},{"type":"null"}],"title":"Sources"}},"type":"object","title":"ResponseMeta","description":"Response metadata."},"SourceFreshness":{"properties":{"healthy":{"type":"boolean","title":"Healthy"},"last_synced_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Synced At"}},"type":"object","required":["healthy"],"title":"SourceFreshness","description":"Sync health for a single incident data source."},"TargetingJobCreated":{"properties":{"job_id":{"type":"string","title":"Job Id","description":"UUID of the created job."},"status":{"type":"string","title":"Status","description":"Job status (queued, processing, completed, failed)."},"poll_url":{"type":"string","title":"Poll Url","description":"URL to poll for job status."},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"When the job was created."}},"type":"object","required":["job_id","status","poll_url","created_at"],"title":"TargetingJobCreated","description":"Response when an async targeting job is created."},"TargetingJobStatus":{"properties":{"job_id":{"type":"string","title":"Job Id","description":"UUID of the job."},"status":{"type":"string","title":"Status","description":"Job status (queued, processing, completed, failed)."},"result":{"anyOf":[{"$ref":"#/components/schemas/MetaTargetingResult"},{"type":"null"}],"description":"Result when completed."},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error","description":"Error message when failed."},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"When the job was created."},"started_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Started At","description":"When processing started."},"completed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Completed At","description":"When the job completed."}},"type":"object","required":["job_id","status","created_at"],"title":"TargetingJobStatus","description":"Response when polling a targeting job."},"UnifiedPolygonRequest":{"properties":{"geometry":{"$ref":"#/components/schemas/GeoJsonGeometry","description":"GeoJSON polygon to query."},"boundary_type":{"$ref":"#/components/schemas/BoundaryType","description":"Boundary type to intersect (default: sa1).","default":"sa1"},"fields":{"anyOf":[{"items":{"type":"string"},"type":"array","maxItems":100},{"type":"null"}],"title":"Fields","description":"API field paths to return."},"topics":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Topics","description":"Comma-separated topic IDs (e.g. `age,income`)."},"census_year":{"type":"integer","title":"Census Year","description":"Census year.","default":2021},"sex":{"type":"string","enum":["male","female","persons"],"title":"Sex","description":"Sex filter: `male`, `female`, or `persons`.","default":"persons"},"age_min":{"anyOf":[{"type":"integer","maximum":120.0,"minimum":0.0},{"type":"null"}],"title":"Age Min","description":"Minimum age (inclusive)."},"age_max":{"anyOf":[{"type":"integer","maximum":999.0,"minimum":0.0},{"type":"null"}],"title":"Age Max","description":"Maximum age (inclusive)."},"aggregate":{"type":"boolean","title":"Aggregate","description":"If true, return area-weighted aggregated stats.","default":false},"limit":{"type":"integer","maximum":1000.0,"minimum":1.0,"title":"Limit","description":"Max boundaries to return (non-aggregate).","default":25},"offset":{"type":"integer","minimum":0.0,"title":"Offset","description":"Pagination offset for boundary results.","default":0}},"type":"object","required":["geometry"],"title":"UnifiedPolygonRequest","description":"Request body for POST /demographics (polygon query)."},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}},"securitySchemes":{"HTTPBearer":{"type":"http","scheme":"bearer"},"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}}},"tags":[{"name":"Boundaries","description":"Australian statistical boundaries: point lookup, spatial queries, and boundary listing."},{"name":"Demographics","description":"Query demographic data (ABS Census) by boundary. Supports topic expansion, field selection, filtering, sorting, and aggregation."},{"name":"Enrich","description":"Batch-enrich locations with boundary resolution and datapack data (demographics, fundraising)."},{"name":"Incidents","description":"Real-time traffic, fire, power outage, and weather incidents with spatial queries."},{"name":"Targeting","description":"Generate ad platform targeting circles from boundary geometry. Small boundaries compute synchronously; large boundaries (>100 km²) are offloaded to async jobs with polling. Results are cached by boundary hash."},{"name":"Tiles","description":"Mapbox Vector Tiles (MVT) for boundary layers. Supports `?apikey=` for map library tile URL templates.\n\n**Available layers:**\n\n| Layer | Description |\n|-------|-------------|\n| `sa1` | Statistical Area Level 1 (finest ABS mesh block aggregation) |\n| `sa2` | Statistical Area Level 2 (suburbs / localities) |\n| `sa3` | Statistical Area Level 3 (regional groupings) |\n| `sa4` | Statistical Area Level 4 (labour market regions) |\n| `lga` | Local Government Areas |\n| `poa` | Postal Areas (postcodes) |\n| `sal` | Suburbs and Localities |\n| `ced` | Commonwealth Electoral Divisions |\n| `sed` | State Electoral Divisions |\n| `gccsa` | Greater Capital City Statistical Areas |\n| `ste` | States and Territories |\n| `sua` | Significant Urban Areas |\n| `ucl` | Urban Centres and Localities |\n| `ra` | Remoteness Areas |\n| `sos` | Section of State |\n| `sosr` | Section of State Range |\n| `iloc` | Indigenous Locations |\n| `iare` | Indigenous Areas |\n| `ireg` | Indigenous Regions |\n| `flood` | Brisbane flood zones (risk levels + flood types) |\n\n**Tile properties:** `boundary_id`, `name`, `state`, `flood_risk`, `flood_type`"},{"name":"Health","description":"Service health check."},{"name":"Locations"},{"name":"Maps"}],"x-tagGroups":[{"name":"Studio","tags":["Maps","Locations"]},{"name":"Data","tags":["Boundaries","Demographics","Enrich","Incidents","Targeting","Tiles"]},{"name":"System","tags":["Health"]}],"servers":[{"url":"https://api.mapulus.com"}]}