# DataQuoll API Reference

Base URL: `https://dataquoll.io/api/v1`

DataQuoll turns fragmented Australian public data into answers about locations, events and assets.

## Endpoints

### GET /incidents

List all current incidents

Returns a GeoJSON FeatureCollection of all current emergency incidents, with support for filtering, pagination, and bounding box queries.

Parameters:

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `state` | query | no | `string` | Comma-separated state codes (e.g. nsw,vic,qld) |
| `eventType` | query | no | `string` | Comma-separated event types (bushfire, burn_off, fire_ban, structure_fire, vehicle_fire, grass_fire, other_fire, hazmat, rescue, flood, storm, tree_down, cyclone, earthquake, extreme_heat, vehicle_accident, medical, alarm, other). For every kind of fire, use category=fire. |
| `category` | query | no | `string` | Comma-separated event categories. Groups related event types (e.g. fire includes bushfire, structure_fire, grass_fire, vehicle_fire, other_fire (a fire of another or unstated kind) and fire_ban). burn_off is its own category (planned). See /api/v1/schema for the full mapping. |
| `featureType` | query | no | `string` | Comma-separated feature types. Defaults to 'incident' (point incidents only), so boundary polygons never appear unless requested. Request them explicitly: incident_area, warning_area, fire_ban_area, road_disruption. See /api/v1/schema. |
| `severity` | query | no | `string` | CAP-AU severity levels (Extreme, Severe, Moderate, Minor, Unknown) |
| `urgency` | query | no | `string` | CAP-AU urgency levels (Immediate, Expected, Future, Past, Unknown) |
| `certainty` | query | no | `string` | CAP-AU certainty levels (Observed, Likely, Possible, Unlikely, Unknown) |
| `warningLevel` | query | no | `string` | Australian Warning System levels |
| `status` | query | no | `string` | Incident status filter |
| `agency` | query | no | `string` | Source agency filter |
| `official` | query | no | `boolean` | Filter by source provenance. `true` excludes sources the feed registry marks unofficial (today the four South Australian community-decoded pager feeds); `false` returns only those sources. Omit it to return everything, which is the default and unchanged behaviour. Read the semantics before relying on it: `official` defaults to true in our feed configuration and is declared explicitly on only the unofficial sources, so `official=true` means "not marked unofficial", not "verified government source". An official feed can still carry individual ambulance dispatches. Use `/attribution` to see the flag per source. |
| `bbox` | query | no | `string` | Bounding box: minLon,minLat,maxLon,maxLat. Records at precision 'state' (not placed) are never inside a box, so a bbox query leaves them out. |
| `limit` | query | no | `integer` | Results per page (default 100, max 500) |
| `cursor` | query | no | `string` | Opaque pagination cursor, taken from meta.next_cursor of the previous response. Absent next_cursor means there are no further pages. |
| `after` | query | no | `string` | Alias for cursor. This is the parameter name emitted in links.next, and is accepted for backward compatibility. If both are supplied, after wins. |
| `format` | query | no | `string` | Response format. CSV includes columns: id, state, agency, feed_id, title, event_type, status, warning_level, severity, urgency, certainty, lng, lat, address, suburb, lga, location_state, reported_at, updated_at, fetched_at, is_retracted, retracted_at, retraction_reason. cap-atom returns a standards-validated CAP Atom feed (each entry inlines a CAP-AU alert in <content>; incidents retracted in the last 7 days appear as Cancel messages). cap-au is the deprecated legacy <alerts> wrapper, kept for backward compatibility; new consumers should use cap-atom. CSV, cap-atom and cap-au require the Developer plan or above; requesting one on a lower plan returns 403. |
| `include_retracted` | query | no | `boolean` | Include retracted incidents (default false). Retracted incidents are marked when upstream feeds stop publishing them. |
| `include_boundary` | query | no | `boolean` | Set true to add properties.boundary: the area (Polygon or MultiPolygon) the agency published for each incident, or null when it published none. Off by default because polygons make list responses much larger. /incidents/{id} always includes it. |

Responses:

| Status | Description |
| --- | --- |
| `200` | A GeoJSON FeatureCollection of incidents |
| `429` | Rate limit exceeded |

Example request:

```bash
curl "https://dataquoll.io/api/v1/incidents?state=nsw%2Cvic&eventType=bushfire%2Cflood" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

Example response:

```json
{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "id": "nsw-rfs-1234567",
      "geometry": {
        "type": "Point",
        "coordinates": [
          150.604,
          -33.883
        ]
      },
      "properties": {
        "source": {
          "state": "nsw",
          "agency": "RFS",
          "feedId": "1234567"
        },
        "title": "Bush Fire - Warragamba",
        "eventType": "bushfire",
        "status": "active",
        "warningLevel": "watch_and_act",
        "severity": "Severe",
        "urgency": "Expected",
        "certainty": "Observed",
        "location": {
          "address": "Warragamba Dam Rd, Warragamba NSW",
          "suburb": "Warragamba",
          "state": "NSW",
          "latitude": -33.883,
          "longitude": 150.604
        },
        "details": {
          "description": "Bush fire burning in a south-easterly direction"
        },
        "timestamps": {
          "reported": "2026-04-07T14:30:00+10:00",
          "updated": "2026-04-07T16:45:00+10:00",
          "fetched": "2026-04-07T16:46:12+10:00"
        },
        "retraction": {
          "retracted": true,
          "retractedAt": "2026-04-07T18:00:00+10:00",
          "reason": "upstream_removed"
        }
      }
    }
  ],
  "meta": {
    "total_count": 245,
    "has_more": true,
    "next_cursor": "cursor_xyz789",
    "generatedAt": "2026-04-07T16:46:12+10:00"
  },
  "links": {
    "self": "/v1/incidents?limit=100",
    "next": "/v1/incidents?limit=100&after=cursor_xyz789"
  },
  "attribution": "https://dataquoll.io/api/v1/attribution"
}
```

### GET /incidents/{id}

Get a single incident

Returns a single incident as a GeoJSON Feature.

Parameters:

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `id` | path | yes | `string` | Incident ID (e.g. nsw-rfs-1234567) |
| `format` | query | no | `string` | Response format. Default geojson returns a GeoJSON Feature. cap-au returns the incident as a single standards-valid CAP-AU <alert> document (Content-Type application/cap+xml), validated against the OASIS CAP 1.2 schema and the CAP-AU Profile v3.0. CSV, cap-atom and cap-au require the Developer plan or above; requesting one on a lower plan returns 403. |

Responses:

| Status | Description |
| --- | --- |
| `200` | A GeoJSON Feature, or a CAP-AU alert document when format=cap-au |
| `404` | Incident not found |

Example request:

```bash
curl "https://dataquoll.io/api/v1/incidents/{id}" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

### GET /incidents/nearby

Find incidents near a location

Returns incidents within a radius (km) of a given lat/lng coordinate, sorted by distance. Records at precision 'state' are left out: their point only stands for somewhere in the state.

Parameters:

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `lat` | query | yes | `number` | Latitude |
| `lng` | query | yes | `number` | Longitude |
| `radius` | query | yes | `number` | Radius in kilometres (max 500) |
| `limit` | query | no | `integer` |  |
| `state` | query | no | `string` |  |
| `eventType` | query | no | `string` |  |
| `severity` | query | no | `string` |  |
| `eventCategory` | query | no | `string` |  |
| `urgency` | query | no | `string` |  |
| `certainty` | query | no | `string` |  |
| `warningLevel` | query | no | `string` |  |
| `agency` | query | no | `string` |  |
| `official` | query | no | `boolean` | Filter by source provenance. `true` excludes sources the feed registry marks unofficial (today the four South Australian community-decoded pager feeds); `false` returns only those sources. Omit it to return everything, which is the default and unchanged behaviour. Read the semantics before relying on it: `official` defaults to true in our feed configuration and is declared explicitly on only the unofficial sources, so `official=true` means "not marked unofficial", not "verified government source". An official feed can still carry individual ambulance dispatches. Use `/attribution` to see the flag per source. |
| `status` | query | no | `string` | Comma-separated incident statuses (active, contained, controlled, safe, completed). Defaults to all. |
| `include_retracted` | query | no | `boolean` | Set true to include retracted incidents. Default false; retracted incidents are hidden, matching /incidents. |
| `include_boundary` | query | no | `boolean` | Set true to add properties.boundary: the area (Polygon or MultiPolygon) the agency published for each incident, or null when it published none. Off by default because polygons make list responses much larger. /incidents/{id} always includes it. |

Responses:

| Status | Description |
| --- | --- |
| `200` | Nearby incidents as GeoJSON FeatureCollection |
| `400` | Missing or invalid parameters |

Example request:

```bash
curl "https://dataquoll.io/api/v1/incidents/nearby?lat=-33.87&lng=151.21" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

### GET /incidents/snapshot

Audit trail snapshot

Returns the incidents that were active at a specific point in time. Recent datetimes are reconstructed from live and lifecycle data. Datetimes before 2026-04-08 are reconstructed from the historical archive (4.9M records) and are gated by the same tier lookback as /incidents/history (free has no archive access; Starter 1 year, Developer and Business 5 years, Pro and Enterprise unlimited). Archive (pre-2026-04-08) snapshots require a state filter, and meta.source indicates whether the result came from "live" or "archive". The answer ends at about 4 MB (archive flood extents come back whole): meta.size_limited and meta.truncated are then true, so narrow by state or event_type.

Parameters:

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `datetime` | query | yes | `string` | ISO 8601 datetime to query (cannot be in the future) |
| `state` | query | no | `string` | Filter by state code. Required for archive (pre-2026-04-08) snapshots. |
| `event_type` | query | no | `string` | Filter by event type |
| `limit` | query | no | `integer` | Max results (default 500) |
| `include_boundary` | query | no | `boolean` | Set true to add properties.boundary: the area (Polygon or MultiPolygon) the agency published for each incident, or null when it published none. Off by default because polygons make list responses much larger. /incidents/{id} always includes it. |

Responses:

| Status | Description |
| --- | --- |
| `200` | Incidents active at the requested datetime |
| `400` | Missing or invalid datetime, or an archive (pre-2026-04-08) snapshot requested without the required state filter |
| `403` | Archive access requires a paid plan, or the datetime predates your tier's lookback window |

Example request:

```bash
curl "https://dataquoll.io/api/v1/incidents/snapshot?datetime=2026-04-20T14%3A30%3A00%2B09%3A30&state=sa" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

### GET /incidents/history

Historical incident data (paid tier)

Returns historical emergency incidents from two sources, merged and ordered newest first: the imported archive (1840 to 1 May 2026, 4.9M records) and the records our own pollers have written since April 2026, which carry `boundary` where an agency published an area. `meta.sources` names which answered. Free tier is blocked. Starter is limited to 1 year of lookback, Developer and Business to 5 years, Pro, Organisation and Enterprise unlimited. A window too large to answer within the database budget returns 400 asking you to narrow it. Engine-era records also carry `featureType` (incidents by default; pass `featureType` to ask for warning_area or incident_area markers) and a `retraction` object only when an agency withdrew the record rather than letting it end: leaving the agency's live feed is the normal end of an incident and is not reported as a retraction here. Records are ordered by `reported_at` newest first, undated records last. PAGE WITH `cursor`: pass `meta.next_cursor` from one response as `cursor` on the next, or follow `links.next`. `before` and `after` bound the WINDOW and are not a paging mechanism: thousands of blocks of records share an identical `reported_at` (the largest holding 634,813), and advancing `before` past a page would skip the rest of that block. Records sharing an instant have no natural order; the order given is stable across pages, which is what the cursor relies on. A PAGE ALSO ENDS AT ABOUT 4 MB: archive polygons are returned whole (a single mapped flood extent can run to megabytes), so a page stops adding records once its size passes the cap, always serving at least one record. `meta.size_limited` is then true and `meta.has_more` true; keep following the cursor.

Parameters:

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `state` | query | no | `string` | Comma-separated state codes |
| `eventType` | query | no | `string` | Comma-separated event types |
| `official` | query | no | `boolean` | Filter by source provenance. `true` excludes sources the feed registry marks unofficial (today the four South Australian community-decoded pager feeds); `false` returns only those sources. Omit it to return everything, which is the default and unchanged behaviour. Read the semantics before relying on it: `official` defaults to true in our feed configuration and is declared explicitly on only the unofficial sources, so `official=true` means "not marked unofficial", not "verified government source". An official feed can still carry individual ambulance dispatches. Use `/attribution` to see the flag per source. |
| `after` | query | no | `string` | Start of date range (ISO 8601, inclusive). Tier-limited. |
| `before` | query | no | `string` | End of date range (ISO 8601, exclusive). Defaults to now. |
| `cursor` | query | no | `string` | Opaque pagination cursor. Pass `meta.next_cursor` from the previous response, or follow `links.next`. Use this rather than advancing `before`, which cannot page through records sharing one `reported_at`. |
| `limit` | query | no | `integer` | Max results per page (1-500, default 100) |

Responses:

| Status | Description |
| --- | --- |
| `200` | Historical incidents matching filters |
| `403` | Free tier blocked or depth limit exceeded |

Example request:

```bash
curl "https://dataquoll.io/api/v1/incidents/history?state=wa%2Csa&eventType=bushfire%2Cflood" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

### GET /states

Feed health by state

Returns the status of each state feed, including last poll time, health, and incident count.

Responses:

| Status | Description |
| --- | --- |
| `200` | Feed status for all states |

Example request:

```bash
curl "https://dataquoll.io/api/v1/states" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

### GET /declarations/postcode/{postcode}

Disaster declaration status for a postcode

Returns the declaration STATUS for a postcode: declared, partial, activation_only, not_declared, uncertain, or unknown_postcode, with per-LGA detail and official source links. Reports declared-area status only; the billing/eligibility decision rests with the practitioner. Built for Medicare disaster telehealth checks.

Parameters:

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `postcode` | path | yes | `string` |  |
| `as_at` | query | no | `string` | Point-in-time check (YYYY-MM-DD). Defaults to today. |
| `include_expired` | query | no | `boolean` | Include expired records in the per-LGA lists. Never changes matchStatus. |
| `instrument_type` | query | no | `string` | Trim the returned record lists to one instrument type. Never changes matchStatus. |
| `suburb` | query | no | `string` | Optional suburb/locality name (ABS SAL) to narrow the result to the local government areas that suburb falls in, within this postcode only. Matching is exact after normalisation; there is no fuzzy matching. An unmatched suburb never fails the lookup: the full-postcode result is returned with narrowing.applied=false, a reason, and the postcode's known suburbs. Narrowing can legitimately change matchStatus (for example partial to declared); a suburb that itself spans two LGAs stays partial, and a bare name that denotes suburbs on both sides of a border (Mingoola in 4380) matches all of them. |

Responses:

| Status | Description |
| --- | --- |
| `200` | Declaration status (including unknown_postcode for an absent postcode) |
| `400` | Malformed postcode or as_at |
| `401` | Missing or invalid API key |
| `403` | The declarations API is not on this account (it comes with the Organisation licence) |
| `429` | Rate limit exceeded |

Example request:

```bash
curl "https://dataquoll.io/api/v1/declarations/postcode/4380?suburb=Stanthorpe" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

### POST /declarations/point

Disaster declaration status for an exact point

Returns the declaration STATUS for the local government area containing a lat/lng point, resolved against ABS LGA 2022 (ASGS Edition 3) boundary polygons at full resolution. POST with a JSON body is used deliberately so coordinates never appear in URLs or request logs; the request is read-only and safe to retry. Coordinates are never stored, logged, or echoed back, and the response is Cache-Control: no-store. Reports declared-area status only; the billing decision rests with the practitioner. A point outside every Australian LGA returns unknown_location. A point exactly on a shared LGA boundary returns every covering area with onBoundary=true. LGA matching is at ABS code level. ABS gives each state one catch-all code for land outside councils, which joins separate places (Unincorporated NSW is the Far West, Lord Howe Island and parts of Sydney Harbour). Where sources name those places (NSW and VIC), the matched LGA carries the part the point is in as area, and records placed in another part are left out; a record published for a whole catch-all without naming a part carries scope part_not_stated.

Responses:

| Status | Description |
| --- | --- |
| `200` | Declaration status for the covering LGA (including unknown_location when no LGA covers the point) |
| `400` | Invalid body, lat, lng, or as_at. Error detail never repeats submitted values. |
| `401` | Missing or invalid API key |
| `403` | The declarations API is not on this account (it comes with the Organisation licence) |
| `429` | Rate limit exceeded |

Example request:

```bash
curl "https://dataquoll.io/api/v1/declarations/point" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

### POST /hazard-history/point

Observed record and declared status for an exact point

What official sources recorded near a location, unioned with the disaster declarations that covered its local government area. Two lanes are returned because both are required: the observed lane (historical archive plus live-era incident history within a radius) and the declared lane (declarations for the covering ABS LGA, counted once per AGRN even when several authorities recorded the same event). A feed that republishes another feed's incidents is left out of the observed lane so they are not counted twice (today nsw-rfs-cap, which repeats nsw-rfs). Medical calls are left out for privacy, alarm calls because an alarm is not a recorded hazard (the agency either found no fire or did not record the outcome), and road and traffic feeds because they record roadworks, closures and traffic rather than hazards. Mapped areas (fire footprints, official warning areas) stay in, because they record what reached a place, so one fire can count once per source that recorded it. Measured example: a Lismore address returns the February 2022 flood only through the declared lane, because the spatial lane holds no record for it at address precision. POST with a JSON body is used deliberately so coordinates never appear in URLs or request logs; the request is read-only and safe to retry. Coordinates are never stored, logged, or echoed back, and the response is Cache-Control: no-store. This reports a RECORD and a declared STATUS. It is not an assessment of risk, insurability, or any obligation, and absence of a record is not evidence that nothing happened. Precision is reported per record: a record at postcode precision sits at a postcode centroid, which can be kilometres from the event.

Responses:

| Status | Description |
| --- | --- |
| `200` | The observed record and declared status for the point. A point outside every Australian LGA returns a null location and an empty declared lane. This response uses one hazard history lookup. |
| `400` | Invalid body, lat, lng, radiusKm, or records. Error detail never repeats submitted values. |
| `401` | Missing or invalid API key |
| `403` | The account has used its hazard history lookups for the month (100 free, then blocks of 1,000) |
| `429` | Rate limit exceeded |

Example request:

```bash
curl "https://dataquoll.io/api/v1/hazard-history/point" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

### GET /declarations

List/filter declarations

Browse and historically report on declaration records. Filters and keyset (cursor) pagination. Record status is derived at query time.

Parameters:

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `jurisdiction` | query | no | `string` |  |
| `status` | query | no | `string` |  |
| `instrument_type` | query | no | `string` |  |
| `disaster_type` | query | no | `string` |  |
| `active_on` | query | no | `string` |  |
| `limit` | query | no | `integer` |  |
| `cursor` | query | no | `string` | Opaque pagination cursor from links.next. |

Responses:

| Status | Description |
| --- | --- |
| `200` | A page of declaration records |
| `400` | Invalid active_on date, status, limit, or cursor |
| `401` | Missing or invalid API key |
| `403` | The declarations API is not on this account (it comes with the Organisation licence) |
| `429` | Rate limit exceeded |

Example request:

```bash
curl "https://dataquoll.io/api/v1/declarations" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

### GET /declarations/agrn/{agrn}

One disaster event by AGRN (across sources)

The declaration/activation for an Australian Government Reference Number, merged across sources with the full affected-LGA list.

Parameters:

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `agrn` | path | yes | `string` |  |

Responses:

| Status | Description |
| --- | --- |
| `200` | The merged declaration record |
| `400` | Malformed AGRN (must be numeric) |
| `401` | Missing or invalid API key |
| `403` | The declarations API is not on this account (it comes with the Organisation licence) |
| `404` | No declaration found for the AGRN |
| `429` | Rate limit exceeded |

Example request:

```bash
curl "https://dataquoll.io/api/v1/declarations/agrn/1284" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

### GET /status

API health check

Returns API health, version, uptime, and a summary of feed statuses.

Responses:

| Status | Description |
| --- | --- |
| `200` | API health status |

Example request:

```bash
curl "https://dataquoll.io/api/v1/status"
```

### GET /attribution

Data source attributions

Returns attribution information for all data sources, including licence details. Required for CC BY compliance.

Responses:

| Status | Description |
| --- | --- |
| `200` | Attribution data for all sources |

Example request:

```bash
curl "https://dataquoll.io/api/v1/attribution"
```

### GET /events

List clustered events (incident intelligence)

Returns spatially clustered emergency events as a GeoJSON FeatureCollection.
Events group related incidents using PostGIS ST_ClusterDBSCAN spatial clustering.
Each event has a boundary polygon, centroid, affected suburbs, contributing agencies,
and auto-generated title and summary. Only active events are returned by default.


Parameters:

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `limit` | query | no | `integer` | Maximum events to return (default 50, max 200) |
| `state` | query | no | `string` | Comma-separated state codes to filter by (e.g. nsw,vic). Uses array overlap matching. |
| `eventType` | query | no | `string` | Comma-separated event types (e.g. bushfire,flood) |
| `severity` | query | no | `string` | Comma-separated max severity levels |
| `warningLevel` | query | no | `string` | Comma-separated max warning levels |

Responses:

| Status | Description |
| --- | --- |
| `200` | A GeoJSON FeatureCollection of clustered events |
| `401` | Missing or invalid API key |
| `429` | Rate limit exceeded |

Example request:

```bash
curl "https://dataquoll.io/api/v1/events?state=nsw%2Cvic&eventType=bushfire%2Cflood" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

### GET /events/{id}

Get a single event with optional linked incidents

Returns a single clustered event by ID. Use `include_incidents=true` to also
retrieve all incidents that belong to this event cluster.


Parameters:

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `id` | path | yes | `string` | Event UUID |
| `include_incidents` | query | no | `boolean` | Include linked incidents in the response |

Responses:

| Status | Description |
| --- | --- |
| `200` | A single event as a GeoJSON Feature |
| `401` | Missing or invalid API key |
| `404` | Event not found |

Example request:

```bash
curl "https://dataquoll.io/api/v1/events/{id}" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

### GET /schema

API schema and valid enum values

Returns all valid enum values for event types, categories, states, warning levels, and other filterable fields. Use this to discover what values are accepted by filter parameters. No authentication required.

Responses:

| Status | Description |
| --- | --- |
| `200` | All valid enum values and category mappings |

Example request:

```bash
curl "https://dataquoll.io/api/v1/schema" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

### GET /gauges

River gauge stations with live flood status

Returns river gauge stations with their latest water level, the Bureau of Meteorology flood classification thresholds for each gauge, and a derived floodClass (below_minor, minor, moderate, major, or unclassified) computed from the latest reading against the published thresholds. Water-level readings are in metres relative to each gauge's local datum (each gauge carries its own unit, since some report in AHD). readingStatus flags stale data (bom-kiwis sourced stations are a 1-2 day archive, stale horizon 72 hours; bcc-telemetry are event-driven council ALERT loggers, stale horizon 48 hours; telemetry sources 24 hours). Defaults to water-level gauges; pass variable=rainfall for observed rainfall gauges, which report incremental millimetres and carry no flood classification. Status reporting, not flood prediction.

Parameters:

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `variable` | query | no | `string` | Measured variable. Defaults to water_level; rainfall returns observed rain gauges (millimetres, incremental, no flood class). |
| `state` | query | no | `string` | Lowercase state code (nsw, vic, qld, sa, wa, tas, nt, act) |
| `floodClass` | query | no | `string` | Filter to gauges at or above this class (>= semantics: minor matches moderate and major too). Water-level only; cannot combine with variable=rainfall. |
| `lga` | query | no | `string` | ABS LGA code (the same LGA_2022 vocabulary as the declarations API) |
| `source` | query | no | `string` | Polling source (hydstra-nsw, hydstra-vic, hydstra-qld, aquarius-sa, aquarius-tas, aquarius-nt, bom-kiwis, bcc-telemetry) |
| `bbox` | query | no | `string` | Bounding box minLng,minLat,maxLng,maxLat (within Australia) |
| `limit` | query | no | `integer` | Max results per page (1-500, default 100) |
| `cursor` | query | no | `string` | Pagination cursor from meta.nextCursor |

Responses:

| Status | Description |
| --- | --- |
| `200` | Gauge stations with latest readings and flood status |
| `401` | Missing or invalid API key |

Example request:

```bash
curl "https://dataquoll.io/api/v1/gauges?state=nsw&lga=17750" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

### GET /gauges/{id}

One gauge with a 6-hour recent window

Returns a single gauge station plus its trailing 6 hours of raw readings (enough to see the current trend). Deeper history is the tier-gated /gauges/{id}/readings endpoint.

Parameters:

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `id` | path | yes | `string` | Gauge id from /gauges (e.g. hydstra-nsw-410001) |

Responses:

| Status | Description |
| --- | --- |
| `200` | The gauge and its recent readings |
| `404` | No active gauge with that id |

Example request:

```bash
curl "https://dataquoll.io/api/v1/gauges/{id}" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

### GET /gauges/{id}/readings

Gauge reading history (paid tier)

Historical water level readings for one gauge. Free tier is blocked (the free surface is current readings on /gauges and the 6-hour window on /gauges/{id}). Starter tier limited to 1 year lookback, Developer and Business to 5 years, Pro and Enterprise unlimited. Retention ladder: raw 30 days, hourly rollups 90 days, daily forever — plus full-resolution raw inside flood-event windows kept forever. interval=auto picks the finest granularity available for the requested window.

Parameters:

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `id` | path | yes | `string` |  |
| `after` | query | no | `string` | Start of range (ISO 8601, inclusive). Tier-limited. |
| `before` | query | no | `string` | End of range (ISO 8601, exclusive). Defaults to now. |
| `interval` | query | no | `string` | raw, hourly, daily, or auto (default) |
| `above` | query | no | `string` | Only readings at/above this published flood classification for the gauge |
| `limit` | query | no | `integer` |  |
| `cursor` | query | no | `string` | Pagination cursor from meta.nextCursor (ISO timestamp keyset) |

Responses:

| Status | Description |
| --- | --- |
| `200` | Readings for the gauge, newest first |
| `403` | Free tier blocked or depth limit exceeded |

Example request:

```bash
curl "https://dataquoll.io/api/v1/gauges/{id}/readings" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

### GET /gauges/summary

Flood status counts by state or LGA

Counts of gauges at or above minor/moderate/major flood classification, grouped by state or LGA, plus the full list of at-or-above-minor stations (capped at 500). STALE GUARD: only readings within the staleness horizon enter class counts — a days-old reading above minor is counted as stale, never as a current flood signal.

Parameters:

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `variable` | query | no | `string` | Measured variable. Defaults to water_level (rain gauges carry no flood class, so they are excluded from the counts by default). |
| `groupBy` | query | no | `string` | state (default) or lga (requires the state parameter) |
| `state` | query | no | `string` |  |

Responses:

| Status | Description |
| --- | --- |
| `200` | Flood status summary |

Example request:

```bash
curl "https://dataquoll.io/api/v1/gauges/summary?state=sa" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

### GET /facilities

Emergency service facility locations

Where responders come from: the locations of police, ambulance, metropolitan fire, rural and country fire, and SES facilities across Australia, from Geoscience Australia under CC BY 4.0. A static reference layer, not a live feed.

Two lanes, and at least one is required. Either a radius search (lat, lng and radius together) or a filter (state and/or class). A bare call is rejected rather than returning all 8,888 facilities.

Address columns derived from G-NAF are deliberately not collected, because they carry a separate licence to the rest of the dataset.


Parameters:

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `lat` | query | no | `number` | Latitude of the search centre. Required with lng and radius. |
| `lng` | query | no | `number` | Longitude of the search centre. Required with lat and radius. |
| `radius` | query | no | `number` | Search radius in kilometres. Required with lat and lng. |
| `state` | query | no | `string` | Lowercase state code. Note that three Australian Federal Police facilities in the Indian Ocean Territories carry no state and are returned only by radius search. |
| `class` | query | no | `string` | Facility class, as a short alias or the full source string. |
| `limit` | query | no | `integer` |  |

Responses:

| Status | Description |
| --- | --- |
| `200` | Matching facilities |
| `400` | Neither lane supplied, or a parameter out of range |
| `401` | Missing or invalid API key |
| `429` | Rate limit exceeded |

Example request:

```bash
curl "https://dataquoll.io/api/v1/facilities" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

### GET /calendars

Industry calendar editions

Every industry-calendar edition on the platform, one per jurisdiction and year (NSW, VIC, QLD, WA, SA, TAS, ACT and NT for 2026), with its publisher, cover range and per-category counts. RDOs, public holidays, school holidays and industry shutdowns, read from each branch calendar and verified against the Fair Work Ombudsman list and the education departments' term dates.

Responses:

| Status | Description |
| --- | --- |
| `200` | The editions |

Example request:

```bash
curl "https://dataquoll.io/api/v1/calendars" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

### GET /calendars/{jurisdiction}

Calendar days for a jurisdiction

The day rows for one jurisdiction across a date range, each date answered by exactly one edition. Defaults to the current calendar year in the jurisdiction's own time zone; a lone from or to extends to the edge of its own year. Recorded disagreements between the calendar and the official list are returned under discrepancies. Rows can be CSV with format=csv.

Parameters:

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `jurisdiction` | path | yes | `string` | Jurisdiction code |
| `from` | query | no | `string` | First date, YYYY-MM-DD |
| `to` | query | no | `string` | Last date, YYYY-MM-DD |
| `category` | query | no | `string` | Comma-separated categories to include (default all). Values are the CalendarDay category enum. |
| `format` | query | no | `string` | json (default) or csv |

Responses:

| Status | Description |
| --- | --- |
| `200` | The days in range |
| `400` | Unknown jurisdiction, malformed date, unknown category, or from after to |

Example request:

```bash
curl "https://dataquoll.io/api/v1/calendars/{jurisdiction}" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

### GET /calendars/{jurisdiction}/{date}

Is this a working day

The answer for one date in one jurisdiction. A jurisdiction-wide public holiday wins, then the weekend, then the calendar's own entries in order (industry shutdown, RDO, part-day holiday, annual leave, industry event); otherwise working. Restricted holidays (a show day for one region, a public-service-only day) never decide it and are returned under restricted for the caller to apply to the employer's area.

Parameters:

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `jurisdiction` | path | yes | `string` | Jurisdiction code |
| `date` | path | yes | `string` | The date, YYYY-MM-DD |

Responses:

| Status | Description |
| --- | --- |
| `200` | The verdict |
| `400` | Unknown jurisdiction or malformed date |
| `404` | No edition covers the date; the detail names the editions that exist |

Example request:

```bash
curl "https://dataquoll.io/api/v1/calendars/{jurisdiction}/{date}" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

### GET /publications

Official documents from the publisher registry

Official documents, newest first: media releases, news, alerts and notices from the publishers in the registry (listPublishers). Today that is South Australia Police media releases, collected continuously since 26 September 2026 and kept after the publisher deletes them. Filter by state, publisher type or source, document kind, a publisher's own section, and a UTC date range; page with the cursor in links.next.

Free keys see the last 7 days, from 00:00 UTC seven days back. A since or until outside that window is refused with 403 and counts against quota. Paid plans see the whole archive.

A media release follows the event, often by hours or days, and an appeal for information is not a finding of fact. Place and time extracted from the text appear under extract once the extraction pass has run, and are null until then, never guessed. Images are counted in imageCount; whether they are served is set per publisher.


Parameters:

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `state` | query | no | `string` | Jurisdiction code, or a comma list. A jurisdiction with no publisher yet returns an empty list, not an error. |
| `type` | query | no | `string` | Publisher type, or a comma list: police, fire, ses, ambulance, health, transport, council, union, other. |
| `source` | query | no | `string` | Publisher id from listPublishers, or a comma list. |
| `kind` | query | no | `string` | Document kind, or a comma list: media_release, news, alert, notice. |
| `section` | query | no | `string` | One of the publisher's own sections. For South Australia Police, a district, region or topic such as northern-police-district, traffic or missing-persons. |
| `since` | query | no | `string` | First UTC date, YYYY-MM-DD, inclusive. |
| `until` | query | no | `string` | Last UTC date, YYYY-MM-DD, inclusive. |
| `includeRemoved` | query | no | `boolean` | true to include documents the publisher has since taken down. They stay in the archive with removedAt set. Default false. |
| `limit` | query | no | `integer` |  |
| `cursor` | query | no | `string` | The opaque cursor from links.next. |

Responses:

| Status | Description |
| --- | --- |
| `200` | The page of publications |
| `400` | Unknown state, type, source or kind, a malformed date, section, limit or cursor |
| `401` | Missing or invalid API key |
| `403` | A free key asked for dates outside its 7-day window |
| `429` | Rate limit exceeded |

Example request:

```bash
curl "https://dataquoll.io/api/v1/publications?state=sa&type=police" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

Example response:

```json
{
  "publications": [
    {
      "id": "83c37297-3803-404c-babd-02225d57372e",
      "source": "sa-police",
      "publisher": {
        "name": "South Australia Police",
        "agency": "SAPOL",
        "type": "police",
        "jurisdiction": "sa"
      },
      "kind": "media_release",
      "slug": "dashcam-sought-after-eudunda-road-rage",
      "title": "Dashcam sought after Eudunda road rage",
      "summary": "Police are seeking witnesses and dashcam footage following a road rage incident at Eudunda.",
      "publishedAt": "2026-09-26T00:26:36+00:00",
      "modifiedAt": "2026-09-26T00:26:54+00:00",
      "sections": [
        "barossa-region",
        "more-news",
        "rss-news",
        "yorke-mid-north-region"
      ],
      "url": "https://www.police.sa.gov.au/sa-police-news-assets/front-page-news/dashcam-sought-after-eudunda-road-rage",
      "versionCount": 1,
      "removedAt": null,
      "attributes": {
        "crimeStoppersRef": "251098",
        "metaTopstory": "no"
      },
      "extract": null,
      "imageCount": 0
    }
  ],
  "meta": {
    "generatedAt": "2026-09-27T03:00:00.000Z",
    "count": 1,
    "depthDays": null
  },
  "links": {
    "next": null
  },
  "attribution": "https://dataquoll.io/api/v1/attribution"
}
```

### GET /publications/{id}

One publication in full

One publication in full: the text body, every path it was published under, and its version list. Publishers edit releases in place and every edit is kept as a new version; the current version is returned unless version is given. images is null while the publisher's images are withheld (South Australia Police images are withheld pending legal advice on identifiable people) and for a document the publisher has taken down (removedAt set); otherwise a list of one-hour signed URLs. Free keys can read publications from the last 7 days.


Parameters:

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `id` | path | yes | `string` | Publication id (a UUID) from listPublications. |
| `version` | query | no | `integer` | A version number from the version list. Default the current version. |

Responses:

| Status | Description |
| --- | --- |
| `200` | The publication |
| `400` | The id is not a UUID, or version is not a positive integer |
| `401` | Missing or invalid API key |
| `403` | A free key asked for a publication older than its 7-day window |
| `404` | No publication with that id, or no such version |
| `429` | Rate limit exceeded |

Example request:

```bash
curl "https://dataquoll.io/api/v1/publications/83c37297-3803-404c-babd-02225d57372e?version=1" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

Example response:

```json
{
  "publication": {
    "id": "83c37297-3803-404c-babd-02225d57372e",
    "source": "sa-police",
    "publisher": {
      "name": "South Australia Police",
      "agency": "SAPOL",
      "type": "police",
      "jurisdiction": "sa"
    },
    "kind": "media_release",
    "slug": "dashcam-sought-after-eudunda-road-rage",
    "title": "Dashcam sought after Eudunda road rage",
    "summary": "Police are seeking witnesses and dashcam footage following a road rage incident at Eudunda.",
    "publishedAt": "2026-09-26T00:26:36+00:00",
    "modifiedAt": "2026-09-26T00:26:54+00:00",
    "sections": [
      "barossa-region",
      "more-news",
      "rss-news",
      "yorke-mid-north-region"
    ],
    "url": "https://www.police.sa.gov.au/sa-police-news-assets/front-page-news/dashcam-sought-after-eudunda-road-rage",
    "versionCount": 1,
    "removedAt": null,
    "attributes": {
      "crimeStoppersRef": "251098",
      "metaTopstory": "no"
    },
    "extract": null,
    "imageCount": 0,
    "version": 1,
    "body": "Police are seeking witnesses and dashcam footage following a road rage incident at Eudunda...",
    "paths": [
      "/sa-police-news-assets/barossa-region/dashcam-sought-after-eudunda-road-rage",
      "/sa-police-news-assets/front-page-news/dashcam-sought-after-eudunda-road-rage",
      "/sa-police-news-assets/yorke-mid-north-region/dashcam-sought-after-eudunda-road-rage"
    ],
    "versions": [
      {
        "versionNo": 1,
        "modifiedAt": "2026-09-26T00:26:54+00:00",
        "title": "Dashcam sought after Eudunda road rage"
      }
    ],
    "images": null
  },
  "meta": {
    "generatedAt": "2026-09-27T03:00:00.000Z"
  },
  "attribution": "https://dataquoll.io/api/v1/attribution"
}
```

### GET /publishers

Publishers of official documents

Every publisher of official documents on the platform: its jurisdiction and type, licence and required attribution, the document kinds it publishes, whether its images are served, the publisher-specific fields its documents carry in attributes and what each means, and live counts. A new publisher appears here the day it is added.


Parameters:

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `state` | query | no | `string` | Jurisdiction code, or a comma list. |
| `type` | query | no | `string` | Publisher type, or a comma list. |
| `source` | query | no | `string` | Publisher id, or a comma list. |

Responses:

| Status | Description |
| --- | --- |
| `200` | The publishers |
| `400` | Unknown state, type or source |
| `401` | Missing or invalid API key |
| `429` | Rate limit exceeded |

Example request:

```bash
curl "https://dataquoll.io/api/v1/publishers?state=sa&type=police" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

Example response:

```json
{
  "publishers": [
    {
      "id": "sa-police",
      "name": "South Australia Police",
      "agency": "SAPOL",
      "type": "police",
      "jurisdiction": "sa",
      "homeUrl": "https://www.police.sa.gov.au",
      "licence": "CC BY 4.0",
      "licenceUrl": "https://creativecommons.org/licenses/by/4.0/",
      "attribution": "Contains SA Police media releases, (c) South Australia Police, used under CC BY 4.0.",
      "commercialUse": true,
      "kinds": [
        "media_release"
      ],
      "serveImages": false,
      "attributes": {
        "crimeStoppersRef": "The Crime Stoppers reference an appeal asks readers to quote, when the release carries one."
      },
      "collection": {
        "kind": "scrape",
        "cadence": "Front-page lists every 5 minutes, district, region and topic sections every 20."
      },
      "status": "active",
      "publications": {
        "total": 498,
        "live": 498,
        "latestPublishedAt": "2026-09-27T02:01:36+00:00"
      },
      "lastCollectedAt": "2026-09-27T03:10:00+00:00"
    }
  ],
  "meta": {
    "generatedAt": "2026-09-27T03:00:00.000Z",
    "count": 1
  },
  "attribution": "https://dataquoll.io/api/v1/attribution"
}
```

## Schemas

The per-incident `details` object is agency-specific and varies by feed. Full per-feed breakdown: https://dataquoll.io/guides/incident-details-fields

### Publication

| Field | Type | Description |
| --- | --- | --- |
| `id` | `string` |  |
| `source` | `string` | Publisher id; see listPublishers. |
| `publisher` | `object` |  |
| `publisher.name` | `string` |  |
| `publisher.agency` | `string` |  |
| `publisher.type` | `string` |  |
| `publisher.jurisdiction` | `string` |  |
| `kind` | `string` | One of: media_release, news, alert, notice. |
| `slug` | `string` |  |
| `title` | `string \| null` |  |
| `summary` | `string \| null` |  |
| `publishedAt` | `string` |  |
| `modifiedAt` | `string` | The publisher's last edit of the current version. |
| `sections` | `string[]` | Every section of the publisher's site the document was listed under. |
| `url` | `string \| null` | Where the publisher published it (the earliest path seen). Publishers delete documents |
| `versionCount` | `integer` |  |
| `removedAt` | `string \| null` | When the publisher stopped publishing it; null while still published. |
| `attributes` | `object` | Publisher-specific fields. Their meanings are listed per publisher by listPublishers. |
| `extract` | `object \| null` | Place, time and category extracted from the text. Null until the extraction pass has run; never guessed. |
| `extract.eventAt` | `string \| null` |  |
| `extract.place` | `object` |  |
| `extract.place.suburb` | `string \| null` |  |
| `extract.place.street` | `string \| null` |  |
| `extract.place.lat` | `number \| null` |  |
| `extract.place.lng` | `number \| null` |  |
| `extract.place.precision` | `string \| null` | One of: exact, locality, postcode, lga, state, null. |
| `extract.category` | `string \| null` |  |
| `extract.attributes` | `object` |  |
| `extract.method` | `string` |  |
| `extract.extractedAt` | `string` |  |
| `imageCount` | `integer` | How many images the current version carries |

### PublicationFull

### Publisher

| Field | Type | Description |
| --- | --- | --- |
| `id` | `string` |  |
| `name` | `string` |  |
| `agency` | `string` |  |
| `type` | `string` | One of: police, fire, ses, ambulance, health, transport, council, union, other. |
| `jurisdiction` | `string` | One of: nsw, vic, qld, sa, wa, tas, act, nt, national. |
| `homeUrl` | `string` |  |
| `licence` | `string` |  |
| `licenceUrl` | `string` |  |
| `attribution` | `string` | The attribution the licence requires wherever the documents are reused. |
| `commercialUse` | `boolean` |  |
| `kinds` | `string[]` |  |
| `serveImages` | `boolean` |  |
| `attributes` | `object` | Publisher-specific field name to meaning. |
| `collection` | `object` |  |
| `collection.kind` | `string` | One of: scrape, feed. |
| `collection.cadence` | `string` |  |
| `status` | `string` | One of: active, paused, retired. |
| `publications` | `object` |  |
| `publications.total` | `integer` |  |
| `publications.live` | `integer` |  |
| `publications.latestPublishedAt` | `string \| null` |  |
| `lastCollectedAt` | `string \| null` |  |

### IncidentFeature

| Field | Type | Description |
| --- | --- | --- |
| `type` | `"Feature"` |  |
| `id` | `string` |  |
| `geometry` | `object` |  |
| `geometry.type` | `string` | One of: Point, Polygon, MultiPolygon. |
| `geometry.coordinates` | `oneOf` |  |
| `properties` | `object` |  |
| `properties.source` | `object` |  |
| `properties.source.state` | `string` |  |
| `properties.source.agency` | `string` |  |
| `properties.source.feedId` | `string` |  |
| `properties.title` | `string` |  |
| `properties.eventType` | `string` | One of: bushfire, burn_off, fire_ban, structure_fire, vehicle_fire, grass_fire, other_fire, hazmat, rescue, flood, storm, tree_down, cyclone, earthquake, extreme_heat, vehicle_accident, medical, alarm, other. |
| `properties.eventCategory` | `string` | Groups related event types. See /api/v1/schema for the full mapping. One of: fire, weather, rescue, hazmat, medical, alarm, planned, earth, hazard, other. |
| `properties.featureType` | `string` | Point incident or boundary polygon. Defaults to 'incident'; list endpoints return only incidents unless ?featureType= is supplied. One of: incident, incident_area, warning_area, fire_ban_area, road_disruption. |
| `properties.status` | `string` | One of: active, contained, controlled, safe, completed. |
| `properties.warningLevel` | `string` | One of: advice, watch_and_act, emergency_warning, none. |
| `properties.severity` | `string` | One of: Extreme, Severe, Moderate, Minor, Unknown. |
| `properties.urgency` | `string` | One of: Immediate, Expected, Future, Past, Unknown. |
| `properties.certainty` | `string` | One of: Observed, Likely, Possible, Unlikely, Unknown. |
| `properties.location` | `object` |  |
| `properties.location.address` | `string` |  |
| `properties.location.suburb` | `string` |  |
| `properties.location.state` | `string` |  |
| `properties.location.lga` | `string` |  |
| `properties.location.latitude` | `number` | Centroid latitude (extracted from geometry) |
| `properties.location.longitude` | `number` | Centroid longitude (extracted from geometry) |
| `properties.location.precision` | `string` | How far the point can be trusted. 'exact' = a specific place: the agency's own coordinates, or a point derived from a street address or a map-book grid reference. 'locality' = the centre of the suburb or town the record names. 'postcode' or 'lga' = approximate centroid backfilled for historical archive rows that logged no point. 'state' = the record could not be placed and the point only stands for somewhere in the state; radius and bounding-box searches leave these records out. 'unstated' = a historical archive record whose source never said how it was located (the label /hazard-history/point gives the same record). Absent when no coordinates are available (geometry is null). One of: exact, locality, postcode, lga, state, unstated. |
| `properties.location.confidence` | `string` | How the point was placed, on records where the source did not supply it directly: grid_ref = a map-book grid cell, geocoded = an address or agency point resolved to coordinates, suburb = the town or suburb centre, centroid = on a point, not placed (precision 'state'); on a historical archive area, the importer derived the record's location from the shape's centre, which says nothing about the shape. Set by the SA pager and WA DFES feeds, on any record that fell back to a state point, and on some archive fire and flood areas. Absent when the agency's own coordinates were used. One of: grid_ref, geocoded, suburb, centroid. |
| `properties.boundary` | `object \| null` | The area the agency published for this incident (a fire perimeter, a warning area, a burn area), or null when it published none. geometry keeps the agency's point. Present on /incidents/{id}, and on list endpoints only with include_boundary=true. Coordinates are rounded to 6 decimal places, like area geometry (points are rounded to 4). |
| `properties.boundary.type` | `string` | One of: Polygon, MultiPolygon. |
| `properties.boundary.coordinates` | `object[]` | Ring arrays for Polygon; an array of those for MultiPolygon. |
| `properties.details` | `object` | Agency-specific incident metadata, passed through from the source feed. OPTIONAL and varies by feed AND by incident (it is not standardised across agencies, and some feeds carry none). Render whatever keys are present rather than expecting a fixed set. The properties below are the common ones; the full per-feed breakdown (every field, its type and meaning) is documented at https://dataquoll.io/guides/incident-details-fields |
| `properties.details.description` | `string` | Source detail text; structure varies by feed (NSW RFS alert block, a place name, raw pager text, etc.). |
| `properties.details.resources` | `integer` | Count of resources (crews/appliances/units) assigned or responding. |
| `properties.details.aircraft` | `integer` | Count of aircraft assigned (SA CFS). |
| `properties.details.region` | `string` | Agency operational region, e.g. the SA CFS region number 1-6. Not a place name. |
| `properties.details.fire_ban_district` | `string` | Fire ban district, e.g. MOUNT LOFTY RANGES (SA CFS/MFS). Agency spelling, not normalised. |
| `properties.details.decoded_units` | `string[]` | Decoded responding unit names (SA pager feeds). |
| `properties.details.alarm_level_description` | `string` | Alarm/warning level label (SA pager feeds). |
| `properties.details.priority_description` | `string` | Case priority label (SA Ambulance pager). |
| `properties.details.size` | `string` | Incident size label, e.g. Small/Medium/Large (VIC OSOM). |
| `properties.details.cad_id` | `string` | CAD dispatch identifier (e.g. WA DFES 6-digit number) |
| `properties.details.source_id` | `string` | Upstream agency record ID |
| `properties.details.source_url` | `string` | Deep link to the incident on the source agency website |
| `properties.timestamps` | `object` |  |
| `properties.timestamps.reported` | `string` |  |
| `properties.timestamps.updated` | `string` |  |
| `properties.timestamps.fetched` | `string` |  |
| `properties.archive` | `object` | EM-DAT / historical enrichment. Present only on deep-archive snapshot results (meta.source = archive). Each field appears only when populated. |
| `properties.archive.eventStartDate` | `string` |  |
| `properties.archive.eventEndDate` | `string` |  |
| `properties.archive.magnitude` | `number` |  |
| `properties.archive.magnitudeScale` | `string` |  |
| `properties.archive.impactDeaths` | `integer` |  |
| `properties.archive.impactAffected` | `integer` |  |
| `properties.archive.impactEconomic` | `number` |  |
| `properties.archive.glideNumber` | `string` | GLIDE disaster identifier |

### IncidentCollection

| Field | Type | Description |
| --- | --- | --- |
| `type` | `"FeatureCollection"` |  |
| `features` | `IncidentFeature[]` |  |
| `meta` | `object` |  |
| `meta.total_count` | `integer` |  |
| `meta.has_more` | `boolean` |  |
| `meta.next_cursor` | `string` |  |
| `meta.size_limited` | `boolean` | /incidents/history and /incidents/snapshot. True when the answer ended at the ~4 MB size cap rather than at `limit`, so fewer records than asked for came back. On history `has_more` is then true (follow the cursor); on a snapshot `truncated` is true (narrow by state or event_type). |
| `meta.generatedAt` | `string` |  |
| `links` | `object` |  |
| `links.self` | `string` |  |
| `links.next` | `string` |  |
| `data_freshness` | `object[]` | How current each state's data is, one entry per state. Present on the GeoJSON and JSON responses; the csv, cap-au and cap-atom formats return before it is built. |
| `attribution` | `string` |  |

### EventFeature

| Field | Type | Description |
| --- | --- | --- |
| `type` | `"Feature"` |  |
| `id` | `string` |  |
| `geometry` | `object` | Boundary polygon (convex hull of cluster) or centroid point |
| `geometry.type` | `string` | One of: Polygon, Point. |
| `geometry.coordinates` | `oneOf` |  |
| `properties` | `object` |  |
| `properties.title` | `string` |  |
| `properties.incidentCount` | `integer` |  |
| `properties.affectedSuburbs` | `string[]` |  |
| `properties.affectedStates` | `string[]` |  |
| `properties.agencies` | `string[]` |  |
| `properties.eventTypes` | `string[]` |  |
| `properties.maxSeverity` | `string` | One of: Extreme, Severe, Moderate, Minor, Unknown. |
| `properties.maxWarningLevel` | `string` | One of: advice, watch_and_act, emergency_warning, none. |
| `properties.estimatedHectares` | `number` |  |
| `properties.summary` | `string` |  |
| `properties.firstDetectedAt` | `string` |  |
| `properties.lastUpdatedAt` | `string` |  |
| `properties.isActive` | `boolean` |  |

### EventCollection

| Field | Type | Description |
| --- | --- | --- |
| `type` | `"FeatureCollection"` |  |
| `features` | `EventFeature[]` |  |
| `meta` | `object` |  |
| `meta.totalEvents` | `integer` |  |
| `meta.generatedAt` | `string` |  |
| `attribution` | `string` |  |

### CalendarDay

One row of an industry calendar. Null-valued fields are omitted from this description but always present in the JSON.

| Field | Type | Description |
| --- | --- | --- |
| `date` | `string` |  |
| `weekday` | `string` | One of: Mon, Tue, Wed, Thu, Fri, Sat, Sun. |
| `category` | `string` | public_holiday is official and jurisdiction-wide. restricted_public_holiday is official but only for the area or sector in scope. poster_holiday is a day the source calendar colours as a holiday that is not one, kept for audit. One of: public_holiday, part_day_public_holiday, restricted_public_holiday, poster_holiday, rdo, industry_shutdown, annual_leave, industry_event, union_event, school_holiday, school_term. |
| `subtype` | `string` | The calendar's own split where it has one (scheduled |
| `scope` | `string` | For restricted_public_holiday |
| `name` | `string` |  |
| `poster_marking` | `string` | What the source calendar shows for the day; null where it has no cell |
| `official_match` | `boolean` | For official holidays |
| `part_day_from` | `string` | Local start time of a part-day holiday; null otherwise |
| `range_end` | `string` | Last day of the range this row belongs to (a shutdown |
| `note` | `string` |  |

### CalendarEdition

| Field | Type | Description |
| --- | --- | --- |
| `jurisdiction` | `string` |  |
| `year` | `integer` |  |
| `title` | `string` |  |
| `publisher` | `string` |  |
| `source_url` | `string` |  |
| `applies_to` | `string` |  |
| `covers` | `object` |  |
| `covers.from` | `string` |  |
| `covers.to` | `string` |  |
| `timezone` | `string` |  |

### CalendarDiscrepancy

| Field | Type | Description |
| --- | --- | --- |
| `date` | `string` |  |
| `issue` | `string` |  |

### CalendarVerdict

| Field | Type | Description |
| --- | --- | --- |
| `jurisdiction` | `string` |  |
| `date` | `string` |  |
| `weekday` | `string` | One of: Mon, Tue, Wed, Thu, Fri, Sat, Sun. |
| `timezone` | `string` |  |
| `status` | `string` | One of: public_holiday, weekend, industry_shutdown, rdo, part_day_public_holiday, annual_leave, industry_event, working. |
| `working_day` | `boolean` |  |
| `applies_to` | `string` |  |
| `entries` | `CalendarDay[]` | Every row on the date |
| `restricted` | `CalendarDay[]` | Official holidays that apply only to the area or sector in their scope |
| `edition` | `CalendarEdition` |  |

### ProblemDetails

RFC 9457 Problem Details

| Field | Type | Description |
| --- | --- | --- |
| `type` | `string` |  |
| `title` | `string` |  |
| `status` | `integer` |  |
| `detail` | `string` |  |
| `instance` | `string` |  |

### DeclarationRecord

| Field | Type | Description |
| --- | --- | --- |
| `agrn` | `string` |  |
| `title` | `string` |  |
| `instrumentType` | `string` | One of: state_natural_disaster_declaration, drfa_activation_agrn, state_of_disaster_emergency_powers. |
| `jurisdiction` | `string` |  |
| `disasterTypes` | `string[]` |  |
| `startDate` | `string` |  |
| `endDate` | `string` |  |
| `status` | `string` | One of: active, expired, unknown. |
| `source` | `string` | Display name of the highest-precedence reporting source |
| `sources` | `string[]` | Every government source reporting this AGRN+instrument for this LGA. Multiple entries = multiple sources corroborate it. |
| `sourceUrl` | `string` |  |
| `sourcePublishedAt` | `string` |  |
| `scope` | `string` | Present only when the source published this record for a whole ABS catch-all area (for example Unincorporated SA) without saying which part it covers. It still counts toward the status, except that a declaration published this way reads uncertain, never declared. One of: part_not_stated. |

### PostcodeDeclarationRecord

### MatchedLga

| Field | Type | Description |
| --- | --- | --- |
| `lgaCode` | `string` |  |
| `lgaName` | `string` |  |
| `area` | `object` | Present only when the location is inside an ABS catch-all code whose parts sources name (NSW and VIC): the part it is in. lgaCode stays the ABS code, and records the sources place in a different part are left out. |
| `area.code` | `string` |  |
| `area.name` | `string` |  |
| `populationShare` | `number` | Share of the postcode's population in this LGA (ABS correspondence). Always the postcode-level share, even when the response is narrowed by suburb (never renormalised). null for point lookups, where population share is not a meaningful concept. |
| `declarationStatus` | `string` | One of: declared, uncertain, activation_only, not_declared. |
| `declarations` | `PostcodeDeclarationRecord[]` |  |

### SuburbNarrowing

Present on postcode responses only when the suburb parameter was supplied.

| Field | Type | Description |
| --- | --- | --- |
| `requested` | `string` | The trimmed caller input (up to 100 characters) |
| `applied` | `boolean` |  |
| `method` | `string` | How suburb-to-LGA membership was derived. spatial_derivation = area-weighted intersection of ABS SAL 2021 and LGA 2022 boundary polygons (the current source; ABS publishes no SAL 2021 to LGA 2022 correspondence); abs_sal_lga_correspondence = a published ABS population-weighted correspondence, if one is adopted later. One of: spatial_derivation, abs_sal_lga_correspondence. |
| `matchedSuburbs` | `object[]` | The ABS SAL suburb(s) the input matched within this postcode. More than one entry means the bare name denotes multiple suburbs (their LGA sets are unioned). |
| `reason` | `string` | Present only when applied is false One of: suburb_not_found_in_postcode, suburb_lgas_outside_postcode, unknown_postcode. |
| `knownSuburbs` | `string[]` | Present only when applied is false and the postcode is known — the postcode's suburb names |

### PostcodeDeclarationResult

| Field | Type | Description |
| --- | --- | --- |
| `postcode` | `string` |  |
| `matchStatus` | `string` | One of: declared, partial, not_declared, uncertain, activation_only, unknown_postcode. |
| `matchStatusReason` | `string` | Present when matchStatus is uncertain or activation_only |
| `matchedLgas` | `MatchedLga[]` |  |
| `narrowing` | `SuburbNarrowing` |  |
| `asAt` | `string` | Date the status was evaluated against; the requested as_at value or today (AEST) when omitted |
| `dataLastUpdated` | `string` |  |
| `stale` | `boolean` |  |
| `disclaimer` | `string` |  |
| `attribution` | `string` |  |

### HazardHistoryRequest

| Field | Type | Description |
| --- | --- | --- |
| `lat` | `number` | Latitude in decimal degrees, -90 to 90. Never logged or echoed. |
| `lng` | `number` | Longitude in decimal degrees, -180 to 180. Never logged or echoed. |
| `radiusKm` | `number` | Search radius for the observed lane, greater than 0 and no more than 5. Defaults to 1. |
| `records` | `integer` | Maximum observed records returned in the list. Aggregates always cover everything in radius. 1 to 100, defaults to 25. |

### HazardHistoryResult

| Field | Type | Description |
| --- | --- | --- |
| `location` | `object` | The ABS local government area containing the point. All fields are null when the point lies outside every Australian LGA. |
| `location.lgaCode` | `string` |  |
| `location.lgaName` | `string` |  |
| `location.stateCode` | `string` |  |
| `location.area` | `object` | Present only inside an ABS catch-all code whose parts sources name (NSW and VIC): the part the point is in. Declarations placed in another part are left out. |
| `location.area.code` | `string` |  |
| `location.area.name` | `string` |  |
| `radiusKm` | `number` |  |
| `declared` | `object` | Disaster declarations covering the local government area, counted once per AGRN. |
| `declared.distinctCount` | `integer` | Number of distinct AGRNs, not a row count. One event recorded by three authorities counts once. |
| `declared.earliest` | `string` |  |
| `declared.latest` | `string` |  |
| `declared.records` | `object[]` |  |
| `declared.sourceUrls` | `object` | Official source URL per AGRN, where known. Omitted when none are. |
| `observed` | `object` | What official sources recorded within the radius, from both lanes. byType, byPrecision, earliest, latest and records cover the historical archive and the live-era incident history together; archiveTotal and liveTotal split the count by lane. |
| `observed.archiveTotal` | `integer` | Records from the historical archive. |
| `observed.liveTotal` | `integer` | Records from the live-era incident history (2026-04-08 onward). |
| `observed.earliest` | `string` |  |
| `observed.latest` | `string` |  |
| `observed.undatedCount` | `integer` | Records whose source never supplied a date. Present in the counts, flagged dated=false, never given an invented date. |
| `observed.byType` | `object[]` |  |
| `observed.byPrecision` | `object[]` | How the matched records were located. Postcode-precision records sit at a postcode centroid, not at the event. |
| `observed.records` | `object[]` |  |
| `gauge` | `object` | Nearest active river gauge, for context. Not a flood assessment. |
| `gauge.name` | `string` |  |
| `gauge.jurisdiction` | `string` |  |
| `gauge.distanceM` | `integer` |  |
| `coverage` | `string[]` | The measured limits of this answer. Rides on every response. |
| `disclaimer` | `string` |  |

### PointLookupRequest

| Field | Type | Description |
| --- | --- | --- |
| `lat` | `number` |  |
| `lng` | `number` |  |
| `as_at` | `string` | Point-in-time check (YYYY-MM-DD). Defaults to today. |
| `include_expired` | `boolean` | Include expired records in the per-LGA lists. Never changes matchStatus. |
| `instrument_type` | `string` | Trim the returned record lists to one instrument type. Never changes matchStatus. One of: state_natural_disaster_declaration, drfa_activation_agrn, state_of_disaster_emergency_powers. |

### PointDeclarationResult

| Field | Type | Description |
| --- | --- | --- |
| `matchStatus` | `string` | One of: declared, partial, not_declared, uncertain, activation_only, unknown_location. |
| `matchStatusReason` | `string` | Present when matchStatus is uncertain or activation_only |
| `matchedLgas` | `MatchedLga[]` | Normally one area. Two areas only when the point lies exactly on a shared boundary (onBoundary=true); partial is then possible and means the covering areas have different statuses. |
| `onBoundary` | `boolean` | Present (true) only when the point lies on a shared LGA boundary and more than one area is returned. |
| `boundaryEdition` | `string` | ABS boundary edition the point was resolved against. Informative, not an enum — it changes with ASGS edition refreshes. LGA matching is at ABS code level; point-in-polygon cannot be more precise than the code. |
| `asAt` | `string` | Date the status was evaluated against; the requested as_at value or today (AEST) when omitted |
| `dataLastUpdated` | `string` |  |
| `stale` | `boolean` |  |
| `disclaimer` | `string` |  |
| `attribution` | `string` |  |

### DeclarationListItem

### DeclarationList

| Field | Type | Description |
| --- | --- | --- |
| `declarations` | `DeclarationListItem[]` |  |
| `dataLastUpdated` | `string` |  |
| `stale` | `boolean` |  |
| `disclaimer` | `string` |  |
| `links` | `object` |  |
| `links.next` | `string` |  |
| `attribution` | `string` |  |

### DeclarationDetail

| Field | Type | Description |
| --- | --- | --- |
| `agrn` | `string` |  |
| `title` | `string` |  |
| `instrumentType` | `string` |  |
| `jurisdiction` | `string` |  |
| `disasterTypes` | `string[]` |  |
| `startDate` | `string` |  |
| `endDate` | `string` |  |
| `status` | `string` | One of: active, expired, unknown. |
| `source` | `string` |  |
| `sourcePublishedAt` | `string` |  |
| `sourceUrl` | `string` |  |
| `contributingSources` | `object[]` |  |
| `affectedLgas` | `object[]` |  |
| `dataLastUpdated` | `string` |  |
| `stale` | `boolean` |  |
| `disclaimer` | `string` |  |
| `attribution` | `string` |  |

### Gauge

A gauge station with its latest reading. Water-level readings are metres relative to the gauge's local datum, not sea level; rainfall readings are incremental millimetres. floodClass, thresholds and datum are present only on water-level gauges.

| Field | Type | Description |
| --- | --- | --- |
| `id` | `string` |  |
| `name` | `string` |  |
| `river` | `string` |  |
| `state` | `string` |  |
| `agency` | `string` |  |
| `source` | `string` |  |
| `variable` | `string` | The measured variable. Rainfall gauges carry no floodClass, thresholds or datum. One of: water_level, rainfall. |
| `awrcStationNo` | `string` |  |
| `coordinates` | `object` |  |
| `coordinates.lat` | `number` |  |
| `coordinates.lng` | `number` |  |
| `lga` | `object` |  |
| `lga.code` | `string` |  |
| `lga.name` | `string` |  |
| `latest` | `object` |  |
| `latest.value` | `number` |  |
| `latest.observedAt` | `string` |  |
| `latest.quality` | `string` |  |
| `readingStatus` | `string` | One of: live, stale. |
| `unit` | `string` | Present on rainfall gauges (always 'mm'). Water-level gauges carry their unit inside thresholds.unit. |
| `floodClass` | `string` | Water-level gauges only. Derived at read time from the latest reading vs the published BoM thresholds; never stored as judgement. One of: below_minor, minor, moderate, major, unclassified. |
| `thresholds` | `object` | Water-level gauges only. |
| `thresholds.minor` | `number` |  |
| `thresholds.moderate` | `number` |  |
| `thresholds.major` | `number` |  |
| `thresholds.unit` | `string` |  |
| `thresholds.source` | `string` |  |
| `thresholds.version` | `string` |  |
| `thresholds.fetchedAt` | `string` |  |
| `datum` | `object` | Water-level gauges only. |
| `datum.gaugeZeroM` | `number` |  |
| `datum.datum` | `string` |  |

### GaugeReading

A raw reading (observedAt/value/quality) or an aggregated bucket (bucket/min/max/mean/nObs), depending on the interval.

| Field | Type | Description |
| --- | --- | --- |
| `observedAt` | `string` |  |
| `value` | `number` |  |
| `quality` | `string` |  |
| `bucket` | `string` |  |
| `min` | `number` |  |
| `max` | `number` |  |
| `mean` | `number` |  |
| `nObs` | `integer` |  |

### GaugeCollection

| Field | Type | Description |
| --- | --- | --- |
| `gauges` | `Gauge[]` |  |
| `meta` | `object` |  |
| `meta.count` | `integer` |  |
| `meta.hasMore` | `boolean` |  |
| `meta.nextCursor` | `string` |  |
| `meta.generatedAt` | `string` |  |
| `disclaimer` | `string` |  |
| `attribution` | `string` |  |

