Limits, keys and identification
Without an API key the limit is 60 requests per minute per IP — one shared bucket for every anonymous caller behind the address. Over the limit, the endpoints answer HTTP 429 with a Retry-After header (seconds until the penalty lifts) and X-RateLimit-*.
An API key (the X-API-Key header, t24_… format) identifies your integration and moves it to a bucket of its own with its own limit. Apply through the request form — after approval you get an email with a single-use claim link, and the key is shown only once.
Besides the key, set a meaningful User-Agent (your application's name instead of a stock axios/1) — GET /v1/whoami shows what the server records about your requests, and a key can check its own usage via GET /v1/usage.
Successful GETs carry an ETag and Cache-Control: public, max-age=86400 — a repeated request with If-None-Match gets a 304 without a body, saving transfer on both sides.
GET /v1/whoami
An echo of the request's attribution — not cached, because the answer is per-caller.
Try it live: /v1/whoami
Example
Keyless, from curl
curl "https://teryt24.pl/v1/whoami"Response:
{
"apiClient": null,
"identified": false,
"clientClass": "server",
"userAgent": "curl/8",
"refererHost": null,
"originHost": null,
"country": "PL",
"policyUrl": "/usage-policy",
"rateLimit": { "max": 60, "windowMs": 60000, "scope": "per IP (keyless — see the docs on identifying yourself)" }
}| Status | Description |
|---|---|
200 | What the service records about this request. |
401 | The presented X-API-Key is invalid or revoked. |
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. |
GET /v1/usage
The key's request totals and a zero-filled per-day series (UTC days). Keyless: identified:false with null totals/perDay. unavailable:true means the aggregation failed (the HTTP status is 200 regardless).
Try it live: /v1/usage?days=30
| Name | Required | Description |
|---|---|---|
days | — | Window length in days (1–90, default 30). A blank value falls back to the default. |
Example
Keyless (the response shape)
curl "https://teryt24.pl/v1/usage?days=30"Response:
{
"apiClient": null,
"identified": false,
"windowDays": 30,
"rateLimit": { "max": 60, "windowMs": 60000, "scope": "per IP (keyless — see the docs on identifying yourself)" },
"generatedAt": "2026-10-18T14:37:57.265Z",
"totals": null,
"perDay": null,
"unavailable": false
}| Status | Description |
|---|---|
200 | Successful response. |
401 | The presented X-API-Key is invalid or revoked. |
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. |
GET /v1/datasets
Where the data comes from and how fresh it is: per dataset — the source and licence, the SOURCE's own date stamp (parsed from the GUS/GeoNames file name), when this instance last published it, the row count as measured by that ingest, and the staleness verdict (status: ok | stale | unknown). lastAttempt reports the most recent refresh attempt — a validation-rejected or failed update is visible here while the previously published data stays served. Not cached.
Try it live: /v1/datasets
Example
Example response (abridged)
curl "https://teryt24.pl/v1/datasets"Response:
{
"datasets": [
{
"id": "simc",
"title": "Localities (SIMC)",
"source": "GUS TERYT (eteryt.stat.gov.pl)",
"licence": "public register (GUS)",
"sourceDated": true,
"sourceFile": "SIMC_Adresowy_2026-06-12.csv",
"sourceDate": "2026-06-12",
"sourceAgeDays": 129,
"processingStartedAt": "2026-10-18T04:10:02.113Z",
"publishedAt": "2026-10-18T04:12:33.847Z",
"ingestAgeDays": 1,
"recordCount": 54123,
"recordCountAsOf": "2026-10-18T04:12:33.847Z",
"coverage": null,
"budgetDays": 183,
"stale": false,
"status": "ok",
"publishedWith": { "warnings": 0, "forced": false }
},
{
"id": "prg",
"title": "Address points (PRG)",
"source": "GUGiK EMUiA (opendata.geoportal.gov.pl)",
"sourceDated": false,
"sourceDate": null,
"coverage": "16/16 voivodeships · 8634512 address points",
"status": "ok"
}
],
"lastAttempt": { "startedAt": "2026-10-18T04:10:01.902Z", "finishedAt": "2026-10-18T04:12:33.847Z", "status": "success", "outcome": "published" },
"policyUrl": "/usage-policy",
"generatedAt": "2026-10-18T09:30:00.000Z"
}| Status | Description |
|---|---|
200 | Per-dataset status, values only. |
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. |
Browse the data
The API key request form:
All /v1 endpoints return JSON, speak CORS and are covered by the openapi.json document. Interactive version of this reference: /en/docs.
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.