API reference
Incidents
Live and historical emergency incidents from every state and territory, in one GeoJSON schema. Base URL https://dataquoll.io/api/v1.
/incidentsList 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, forecast (a forecast the source publishes for a day, such as CFA's fire danger forecast: no incident, and it states no warning level, severity, urgency or certainty). See /api/v1/schema. |
severity | query | No | string | CAP-AU severity levels (Extreme, Severe, Moderate, Minor, Unknown). Matches the published value: a record whose agency does not state severity, or whose stored value could be DataQuoll's, matches Unknown only. |
urgency | query | No | string | CAP-AU urgency levels (Immediate, Expected, Future, Past, Unknown). Matches the published value: a record whose agency does not state urgency, or whose stored value could be DataQuoll's, matches Unknown only. |
certainty | query | No | string | CAP-AU certainty levels (Observed, Likely, Possible, Unlikely, Unknown). Matches the published value: a record whose agency does not state certainty, or whose stored value could be DataQuoll's, matches Unknown only. |
warningLevel | query | No | string | Australian Warning System levels (advice, watch_and_act, emergency_warning, none). Matches the published level: none matches a record whose agency states no level; a level DataQuoll cannot confirm (absent on the record) matches nothing. |
status | query | No | string | Incident status filter |
agency | query | No | string | Comma-separated source agency codes, as each record's source.agency gives them (for example RFS, CFS). Matching is exact and case-sensitive, so rfs matches nothing; an unknown code matches nothing. At most 100 values, each at most 64 characters and 2,000 characters for the whole list, counted URL-encoded: a letter, digit, space, hyphen, full stop, underscore or asterisk counts one, any other character three or more. A longer list returns 400; to get every agency, omit agency. |
official | query | No | boolean | Filter by source provenance. `true` excludes sources the feed registry marks unofficial (today the South Australian community-decoded pager feeds, and NT PFES, an agency feed whose licence is not published); `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 `/api/v1/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, feature_type, event_category. In CSV, a text cell begins with a single quote (') when its first visible character is =, +, - or @ (also after spaces or line breaks, and in fullwidth form) or it starts with a tab, carriage return or single quote, so a spreadsheet opens it as text, never as a formula; numbers, such as a negative latitude, are never changed. To get the original text, remove one single quote from the start of a cell that begins with one. 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. A forecast is not an alert, so cap-au and cap-atom with featureType=forecast return 400. 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. /api/v1/incidents/{id} always includes it. |
Responses
| Status | Description |
|---|---|
200 | A GeoJSON FeatureCollection of incidents |
400 | A malformed parameter (a filter, limit or cursor), or a CAP format asked for forecasts. A request whose database query would be longer than 24,926 characters also returns 400, naming the filters that made it large (for example, severity, urgency, certainty and warningLevel each set to every value). |
402 | Pay per request: no key was sent, so the answer is a price. The WWW-Authenticate header carries an MPP Payment challenge; pay it and send the request again with Authorization: Payment. Also sent, with a fresh price, when a payment fails its checks or its price has expired. Only while pay per request is on; otherwise a request without a key gets 401. |
403 | A paid format (csv, cap-au, cap-atom) below the Developer plan, or a key restricted to other origins or endpoints |
429 | Rate limit exceeded |
curl "https://dataquoll.io/api/v1/incidents?state=nsw%2Cvic&eventType=bushfire%2Cflood" \ -H "Authorization: Bearer YOUR_API_KEY"
{
"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": "Unknown",
"urgency": "Unknown",
"certainty": "Unknown",
"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": "/api/v1/incidents?limit=100",
"next": "/api/v1/incidents?limit=100&after=cursor_xyz789"
},
"attribution": "https://dataquoll.io/api/v1/attribution"
}/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. A forecast record (featureType forecast) is not an alert and returns 400 for cap-au. 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 |
400 | format=cap-au for a record that is not an alert (a forecast) |
402 | Pay per request: no key was sent, so the answer is a price. The WWW-Authenticate header carries an MPP Payment challenge; pay it and send the request again with Authorization: Payment. Also sent, with a fresh price, when a payment fails its checks or its price has expired. Only while pay per request is on; otherwise a request without a key gets 401. |
404 | Incident not found |
curl "https://dataquoll.io/api/v1/incidents/{id}" \
-H "Authorization: Bearer YOUR_API_KEY"/incidents/nearbyFind 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 | |
category | query | No | string | Comma-separated event categories, as on /api/v1/incidents (fire, weather and so on; see /api/v1/schema). Named eventCategory here until v1.96.1, a name this endpoint never read: a filter sent under it was ignored. |
urgency | query | No | string | |
certainty | query | No | string | |
warningLevel | query | No | string | |
agency | query | No | string | Comma-separated source agency codes, as each record's source.agency gives them (for example RFS, CFS). Matching is exact and case-sensitive, so rfs matches nothing; an unknown code matches nothing. At most 100 values, each at most 64 characters and 2,000 characters for the whole list, counted URL-encoded: a letter, digit, space, hyphen, full stop, underscore or asterisk counts one, any other character three or more. A longer list returns 400; to get every agency, omit agency. |
official | query | No | boolean | Filter by source provenance. `true` excludes sources the feed registry marks unofficial (today the South Australian community-decoded pager feeds, and NT PFES, an agency feed whose licence is not published); `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 `/api/v1/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 /api/v1/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. /api/v1/incidents/{id} always includes it. |
Responses
| Status | Description |
|---|---|
200 | Nearby incidents as GeoJSON FeatureCollection |
400 | Missing or invalid parameters. A request whose database query would be longer than 24,926 characters also returns 400, naming the filters that made it large (for example, severity, urgency, certainty and warningLevel each set to every value). |
402 | Pay per request: no key was sent, so the answer is a price. The WWW-Authenticate header carries an MPP Payment challenge; pay it and send the request again with Authorization: Payment. Also sent, with a fresh price, when a payment fails its checks or its price has expired. Only while pay per request is on; otherwise a request without a key gets 401. |
curl "https://dataquoll.io/api/v1/incidents/nearby?lat=-33.87&lng=151.21" \ -H "Authorization: Bearer YOUR_API_KEY"
/incidents/snapshotAudit trail snapshot
Returns the incidents that were active at a specific point in time, each once. Recent datetimes are reconstructed from live and lifecycle data: an incident counts from when we first saw it until its source withdrew it, so one withdrawn by then is left out. Each carries the latest state we recorded for it, which, for an incident its source updated in place, can be later than the datetime asked (timestamps.updated says when). Datetimes before 2026-04-08 are reconstructed from the historical archive (4.5M records) and are gated by the same tier lookback as /api/v1/incidents/history (free has no archive access; Starter 1 year, Developer and Business 5 years, Pro, Organisation 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". meta.truncated is true when more incidents were active than came back: the answer stopped at limit, or at about 4 MB (archive flood extents come back whole; meta.size_limited is then true too). Narrow by state or event_type. An archive record its source dated only to a period (properties.archive.datePrecision, datePeriodEnd) counts as active from the period's first day until the end its source states, or, without one, until the period's last day, because the source does not say on which of those days it burned or flooded. One with a stated day and no stated end counts on that day only.
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 |
feature_type | query | No | string | Comma-separated feature types: only these kinds are returned. Without it every kind is returned except forecast, because a forecast (such as a day of CFA's fire danger forecast) is no incident; ask for forecasts with feature_type=forecast. Archive records are incidents. An unknown value is a 400. |
limit | query | No | integer | Max results (default 500). An integer from 1 to 500; anything else is a 400. |
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. /api/v1/incidents/{id} always includes it. |
Responses
| Status | Description |
|---|---|
200 | Incidents active at the requested datetime |
400 | Missing or invalid datetime, a limit that is not an integer from 1 to 500, an archive (pre-2026-04-08) snapshot requested without the required state filter, or a query that timed out (narrow it, or try again in a moment) |
402 | Pay per request: no key was sent, so the answer is a price. The WWW-Authenticate header carries an MPP Payment challenge; pay it and send the request again with Authorization: Payment. Also sent, with a fresh price, when a payment fails its checks or its price has expired. Only while pay per request is on; otherwise a request without a key gets 401. |
403 | Archive access requires a paid plan, or the datetime predates your tier's lookback window |
429 | Rate limit exceeded |
curl "https://dataquoll.io/api/v1/incidents/snapshot?datetime=2026-04-20T14%3A30%3A00%2B09%3A30&state=sa" \ -H "Authorization: Bearer YOUR_API_KEY"
/incidents/historyHistorical 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.5M 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, or forecast records) 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; a record with no `reported_at` is not returned here (hazard history counts it as undated). An archive record whose source stated only a period carries `date_precision` (`month`, `season`, `financial_year`, `year` or `period`) and `date_period_end`: its `event_start_date` is then the period's first day, not a stated day, and the same keys sit in its `details`, with `details.date_as_published` holding the source's own value wherever we replaced a placeholder start, and `details.end_as_published` a replaced end. A period-dated archive record's `reported_at` is its period's first day at the start of the day, UTC, so `after` and `before` select it by that day, not by overlap. 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 holds more than 600,000 records), 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 South Australian community-decoded pager feeds, and NT PFES, an agency feed whose licence is not published); `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 `/api/v1/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 |
400 | Invalid before or after, filters, limit or cursor, or a window too large to answer within the database budget (narrow it). A request whose database query would be longer than 24,926 characters also returns 400, naming the filters that made it large (for example, severity, urgency, certainty and warningLevel each set to every value). |
402 | Pay per request: no key was sent, so the answer is a price. The WWW-Authenticate header carries an MPP Payment challenge; pay it and send the request again with Authorization: Payment. Also sent, with a fresh price, when a payment fails its checks or its price has expired. Only while pay per request is on; otherwise a request without a key gets 401. |
403 | Free tier blocked or depth limit exceeded |
429 | Rate limit exceeded |
curl "https://dataquoll.io/api/v1/incidents/history?state=wa%2Csa&eventType=bushfire%2Cflood" \ -H "Authorization: Bearer YOUR_API_KEY"