API and docs
One envelope.
REST and MCP.
Six read operations, each one request, each taking the text as typed, an id or a point. The MCP tools return the same JSON as the REST endpoints.
curl -sS "https://api.landfeed.pl/v1/check?q=Lesnowola%2025%2F18" \
-H "X-Api-Key: $LANDFEED_API_KEY"
Conventions
- Every read takes exactly one of
q(free text as typed: "pogorzelec dziłaka 284/5", "Lesnowola 25/18", "Marcinowice 221"),id(EGiB id in slash or dash form:146501_1.0101.12/3or146501_1.0101.12-3) orpoint(lat,lng, orlatandlng). You never need to resolve first. - Ambiguous input returns HTTP 200,
status: "ambiguous"andcandidateswith confidence.needs_obreb: truemeans ask which obręb. - Plans carry
statusdraft | adopted | in_force | noneandeffective_from. Drafts are shown and labelled. - Ids we return are canonical (slash form). Field names are snake_case.
- Auth: an
X-Api-Keyheader; OAuth for the hosted MCP is planned at release.
The six tools
One MCP tool per endpoint. Six tools keep tools/list small.
| Tool | Endpoint | Answers |
|---|---|---|
check | GET /v1/check | Can you build on this parcel? Verdict, named checks with sources and basis, record embedded. |
parcel | GET /v1/parcel, POST /v1/parcel/batch | The full sourced record; layers narrows it, geometry=full adds the polygon. Batch up to 1,000 items. |
layer | GET /v1/layer/{layer} | One layer for one parcel; planning answers plan ogólny, MPZP, WZ and gmina status at once. |
resolve | GET /v1/resolve | Candidates with confidence and corpus_coverage; fuzzy locality matching. |
search | GET or POST /v1/search | Parcels at an address, within up to 2,000 m, or in a bbox up to 4 km²; cursor pagination. |
events | GET /v1/events | Changes since a date, newest first, each with before, after, source and as_of. |
Also: GET /v1/gminy/{teryt}/planning and GET /v1/gminy/planning for a gmina's planning status, and GET /v1/sources for sources, licences and freshness.
Costs
Cost is in requests per call, declared as x-request-cost on every operation in the OpenAPI.
GET /v1/check1verdict, named checks and the full record in one call
GET /v1/parcel1POST /v1/parcel/batch1per item, up to 1,000GET /v1/layer/{layer}1GET /v1/resolve1GET or POST /v1/search1GET /v1/events1GET /v1/gminy/…/planning1GET /v1/sources0GET /v1/openapi.json0Coverage states
Every layer answer has coverage, note, source (with attribution) and as_of.
| State | Meaning | value |
|---|---|---|
| covered | The source holds a record here. | the record |
| covered_no_data | The source covers this place and records nothing. A real negative, and it is charged. | the empty answer: false, 0, [], "none" |
| not_covered | The state does not publish it, or we hold no data here. Say so; do not infer. | null |
| not_computed | We hold the source but have not computed it here yet. | null |
Billing and refunds
Every response carries billing {cost, charged, refunded, rule} and the headers X-Request-Cost, X-Credits-Charged and X-Credits-Refunded.
Charged
Answers, informative negatives (covered_no_data) and candidate lists (ambiguous).
Free
Invalid input (HTTP 400, free_invalid_input), a missing or wrong key (401), a matching If-None-Match (304), and operations that cost 0.
Refunded
Not found (404), other 4xx, every 5xx, status: not_covered, and a single-layer answer that is not_covered or not_computed.
Batch counts per item (rule: batch_mixed when items differ).
Errors
Every error body has code, message, hint and docs; example_id when the input was a parcel; signup_url on 401.
Caching
GET by id returns an ETag; send it as If-None-Match to get 304, free. Authenticated responses are Cache-Control: private. Caching, embedding and keeping answers in session memory are allowed with attribution.
More examples
The planning layer by id
curl -sS "https://api.landfeed.pl/v1/layer/planning?id=141803_2.0006.25/18" \
-H "X-Api-Key: $LANDFEED_API_KEY"
Sources and freshness, free
curl -sS "https://api.landfeed.pl/v1/sources" \
-H "X-Api-Key: $LANDFEED_API_KEY"
Invalid input is free
{
"status": "error",
"result": null,
"error": { "code": "invalid_input", "hint": "Pass exactly one of q, id or point",
"example_id": "146501_1.0101.12/3", "docs": "…", … },
"billing": { "cost": 1, "charged": 0, "refunded": 0, "rule": "free_invalid_input" }
}
The generated reference (operations, layer schemas, tool pages, the envelope) lives in the docs site, built from these contracts. Docs for agents: llms.txt.