The TERYT registry change feed
GUS publishes "pliki aktualizacyjne": the DIFFS between catalogue states. GET /v1/changes serves them as a feed — with the catalogue state the change belongs to, and with GUS's own field names in the `before` and `after` blocks (the feed invents no schema of its own).
Three meanings, stated plainly. A DELETION means the object left the catalogue — it does NOT mean the address became invalid. A REORDERING (the type "reordered", ULIC's "Z") is a FORMATTING change: the part of the street's name that decides its alphabetical position changed — it has its own type, so it can be filtered out. The dates are the CATALOGUE STATES (GUS's StanPrzed/StanPo), not the moment the file was published.
The feed starts with the first ingested update file: the registry's earlier history is NOT reconstructed, because the diff files only describe the states they were generated for. `meta.coverage.complete` says so plainly. Until the first file is fetched the endpoint answers 503.
GET /v1/changes
The change feed: filters by catalogue state, registry and change type. Newest first.
Try it live: /v1/changes?dataset=simc&since=2026-10-01&limit=2
| Name | Required | Description |
|---|---|---|
since | — | The catalogue state to start from (YYYY-MM-DD). Changes whose "after" state is on or after this date are returned. |
until | — | The catalogue state to stop at (YYYY-MM-DD), inclusive. |
dataset | — | The registry: terc (administrative units) | simc (localities) | ulic (streets). All three when omitted. |
type | — | The change type(s), comma-separated: added, modified, moved, renamed, reordered, deleted. All of them when omitted. |
limit | — | Maximum changes per page (1–200). |
offset | — | 0-based, skips the first N changes (max 10000). |
Example
Locality changes
curl "https://teryt24.pl/v1/changes?dataset=simc&since=2026-10-01&limit=2"Response (truncated — first rows shown):
{
"changes": [
{
"dataset": "simc",
"type": "renamed",
"correctionType": "Z",
"stanBefore": "2026-10-12",
"stanAfter": "2026-11-09",
"identityBefore": "0983988",
"identityAfter": "0983988",
"nameBefore": "Dzierżoniów",
"nameAfter": "Dzierżoniów Śląski",
"before": { "Stan": "2026-10-12", "Woj": "14", "Pow": "65", "Gmi": "03", "Rodz": "01", "Nazwa": "Dzierżoniów" },
"after": { "Stan": "2026-11-09", "Woj": "14", "Pow": "65", "Gmi": "03", "Rodz": "01", "Nazwa": "Dzierżoniów Śląski" }
}
],
"meta": {
"total": 1,
"offset": 0,
"limit": 2,
"coverage": { "from": "2026-10-12", "to": "2026-11-09", "ingestedAt": "2026-11-10T03:12:44.000Z", "complete": false }
}
}| Status | Description |
|---|---|
200 | The changes, newest first, plus `meta.coverage` — the states the feed covers, when it was last ingested, and the fact that the earlier history is not reconstructed. |
400 | Invalid query parameters. |
429 | Rate limit exceeded (60 requests/min/IP) or a plan's monthly quota exhausted. Includes `Retry-After` and `X-RateLimit-*` headers; the body's `code` distinguishes the two kinds. |
500 | Unexpected server failure (e.g. the database is unreachable). The body is deliberately generic — error detail lives in the server logs, never in the response. |
Browse the data
The changes concern the same objects that have browsable pages:
All /v1 endpoints return JSON, speak CORS and are covered by the openapi.json document. Interactive version of this reference: /en/docs.
Limits: 60 requests/min per IP without a key; an API key (the X-API-Key header) gets its own bucket. Over the limit the endpoints answer HTTP 429 with a Retry-After header. Details: limits & keys · usage policy.
Data: GUS TERYT, PRG address points (GUGiK), GeoNames postal codes — via teryt24.pl with a link to the usage policy. Server-side-only use is exempt.