GET /v1/resolve
Rozpoznaj kandydatów na działkę na podstawie tekstu użytkownika, identyfikatora albo punktu.
Operation ID: resolve.
Description
Zawsze zwracane są candidates (także z jednym kandydatem) i corpus_coverage. Status ok oznacza dokładnie jednego pewnego kandydata: pewność co najmniej 0,85 i przewaga co najmniej 0,15 nad kolejnym. W przeciwnym razie zwracany jest status ambiguous, a needs_obreb=true wskazuje numer występujący w kilku obrębach gminy. Nazwy miejscowości i gmin są dopasowywane w przybliżeniu, z uwzględnieniem diakrytyków i jednej lub dwóch literówek, np. „Lesnowola” znajduje Lesznowolę. Pewność jest wtedy obniżana, a założenie opisują query.resolved.note i match_reason. Identyfikatory są przyjmowane z ukośnikiem lub łącznikiem. Kandydat ze zbioru, którego jeszcze nie załadowano, ma held=false; informuje o tym także corpus_coverage.
Cost
x-request-cost: 1 request per call.
Inputs
Declared path/query inputs: q | id | point | lat | lng | limit | listing_url.
Dokładnie jeden z parametrów q, id, point (lat i lng razem liczą się jako point). Wszystkie punkty odczytu API i wszystkie narzędzia obsługują te trzy warianty.
Parameters
| Name | In | Required | Schema | Description |
|---|---|---|---|---|
q | query | false | {"maxLength": 300, "minLength": 1, "type": "string"} | Tekst wpisany przez użytkownika (działka, adres, gmina). Dokładnie jeden parametr: q, id albo point. |
id | query | false | {"description": "Identyfikator EGiB id_dzialki w postaci przyjmowanej od wywołującego. Wzorzec apps/web/src/lib/schemas/validation.ts sprawdzono na zbiorze danych: przyjmuje 38 339 611 z 38 339 612 rekordów parcel_inventory; pominięty rekord ma pusty numer. Zapis \\\\p{L}\\\\p{N} zastąpiono literami łacińskimi z diakrytykami i cyframi, aby wzorzec działał w ECMA-262, Python re i PostgreSQL. Postać: sześciocyfrowy prefiks TERYT, następnie „_” lub „.” (np. „020207.5.0004.345” w przychodzących odnośnikach), cyfra jednostki, obręb złożony z 1-4 cyfr i numer zawierający do 64 liter, cyfr, znaków „_”, „.”, „/”, „-” i spacji. Arkusze AR_, np. „247701_1.0003.AR_4.734/113” i „240702_2.0001.AR_10BORONÓW LAS.310/121”, są poprawnymi identyfikatorami. Dopuszczalne są spacje na początku i końcu wklejonego identyfikatora. landfeed.normalize_parcel_id() zamienia każdą przyjmowaną postać na ParcelId: usuwa skrajne spacje, zamienia „.” po prefiksie na „_” oraz „-” w ostatnim członie na „/” („146501_1.0101.12-3” na „146501_1.0101.12/3”). API zwraca wyłącznie identyfikatory w ujednoliconej postaci. Przykłady: fixtures/real_ids.txt, fixtures/id_forms.jsonl.", "maxLength": 100, "pattern": "^\\s*[0-9]{6}[._][0-9]\\.[0-9]{1,4}\\.[0-9A-Za-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u024F_./ -]{0,63}[0-9A-Za-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u024F_./-]\\s*$", "type": "string"} | EGiB id_dzialki z ukośnikiem, łącznikiem lub kropką jako separatorem, np. 146501_1.0101.12/3, 146501_1.0101.12-3, 247701_1.0003.AR_4.734/113. landfeed.normalize_parcel_id normalizuje zapis; odpowiedzi zawierają ujednoliconą postać z ukośnikiem. Dokładnie jeden parametr: q, id albo point. |
point | query | false | {"type": "string"} | WGS84 lat,lng, np. 52.2297,21.0122. Dokładnie jeden parametr q, id albo point lub para lat i lng. |
lat | query | false | {"maximum": 55.0, "minimum": 49.0, "type": "number"} | Szerokość geograficzna WGS84; wraz z lng odpowiada point. |
lng | query | false | {"maximum": 24.5, "minimum": 14.0, "type": "number"} | Długość geograficzna WGS84; wraz z lat odpowiada point. |
limit | query | false | {"default": 5, "maximum": 20, "minimum": 1, "type": "integer"} | not specified in the source contract |
listing_url | query | false | {"format": "uri", "maxLength": 2048, "pattern": "^https://", "type": "string"} | Zastępuje q|id|point. Wymaga LANDFEED_LISTING_LOOKUP_ENABLED (domyślnie false). Odpowiedź zawiera status ambiguous i wyłącznie candidates[], także przy jednym kandydacie. Bez treści, zdjęć i cen z ogłoszenia. Pusta lista oznacza not_found i zwrot opłaty. |
Authentication
[
{
"ApiKey": []
},
{
"OAuthConnector": []
}
]
{
"ApiKey": {
"description": "Klucz API konta korzystający z tych samych kredytów co wywołania przez połączenie OAuth.",
"in": "header",
"name": "X-Api-Key",
"type": "apiKey"
},
"OAuthConnector": {
"bearerFormat": "OAuth 2.1 access token",
"description": "Autoryzacja połączenia OAuth ze wspólnymi kredytami konta. Wykrywanie konfiguracji i zgodę obsługuje usługa uwierzytelniania.",
"scheme": "bearer",
"type": "http"
}
}
Responses
| Status | Description | Billing rule |
|---|---|---|
| 200 | Odpowiedź Envelope; result to najlepszy kandydat albo null; candidates jest zawsze obecne. | See billing.rule and the verbatim Billing policy below (answers, coverage, ambiguity, and batch). |
| 400 | Bezpłatne HTTP 400. Odpowiedź Envelope ze statusem error, error.code=invalid_input, error.hint, error.example_id i billing {charged 0, rule free_invalid_input}. | free_invalid_input |
| 401 | Odpowiedź Envelope ze statusem not_found lub error, result=null i wypełnionym error (hint, docs, example_id przy danych wejściowych dotyczących działki; signup_url przy HTTP 401). Zwrot opłaty albo bezpłatne przy HTTP 401. | free_unauthorized |
| 404 | Odpowiedź Envelope ze statusem not_found lub error, result=null i wypełnionym error (hint, docs, example_id przy danych wejściowych dotyczących działki; signup_url przy HTTP 401). Zwrot opłaty albo bezpłatne przy HTTP 401. | refunded_client_error |
HTTP 200: headers and body schemas
{
"content": {
"application/json": {
"schema": {
"allOf": [
{
"$ref": "./envelope.json"
},
{
"properties": {
"result": {
"oneOf": [
{
"type": "null"
},
{
"$ref": "./envelope.json#/$defs/Candidate"
}
]
}
}
}
]
}
}
},
"description": "Odpowiedź Envelope; result to najlepszy kandydat albo null; candidates jest zawsze obecne.",
"headers": {
"Cache-Control": {
"$ref": "#/components/headers/CacheControl"
},
"ETag": {
"$ref": "#/components/headers/ETag"
},
"X-Credits-Charged": {
"$ref": "#/components/headers/XCreditsCharged"
},
"X-Credits-Refunded": {
"$ref": "#/components/headers/XCreditsRefunded"
},
"X-Request-Cost": {
"$ref": "#/components/headers/XRequestCost"
}
}
}
HTTP 400: headers and body schemas
{
"content": {
"application/json": {
"schema": {
"$ref": "./envelope.json"
}
}
},
"description": "Bezpłatne HTTP 400. Odpowiedź Envelope ze statusem error, error.code=invalid_input, error.hint, error.example_id i billing {charged 0, rule free_invalid_input}.",
"headers": {
"Cache-Control": {
"$ref": "#/components/headers/CacheControl"
},
"X-Credits-Charged": {
"$ref": "#/components/headers/XCreditsCharged"
},
"X-Request-Cost": {
"$ref": "#/components/headers/XRequestCost"
}
}
}
HTTP 401: headers and body schemas
{
"content": {
"application/json": {
"schema": {
"$ref": "./envelope.json"
}
}
},
"description": "Odpowiedź Envelope ze statusem not_found lub error, result=null i wypełnionym error (hint, docs, example_id przy danych wejściowych dotyczących działki; signup_url przy HTTP 401). Zwrot opłaty albo bezpłatne przy HTTP 401.",
"headers": {
"Cache-Control": {
"$ref": "#/components/headers/CacheControl"
},
"ETag": {
"$ref": "#/components/headers/ETag"
},
"X-Credits-Charged": {
"$ref": "#/components/headers/XCreditsCharged"
},
"X-Credits-Refunded": {
"$ref": "#/components/headers/XCreditsRefunded"
},
"X-Request-Cost": {
"$ref": "#/components/headers/XRequestCost"
}
}
}
HTTP 404: headers and body schemas
{
"content": {
"application/json": {
"schema": {
"$ref": "./envelope.json"
}
}
},
"description": "Odpowiedź Envelope ze statusem not_found lub error, result=null i wypełnionym error (hint, docs, example_id przy danych wejściowych dotyczących działki; signup_url przy HTTP 401). Zwrot opłaty albo bezpłatne przy HTTP 401.",
"headers": {
"Cache-Control": {
"$ref": "#/components/headers/CacheControl"
},
"ETag": {
"$ref": "#/components/headers/ETag"
},
"X-Credits-Charged": {
"$ref": "#/components/headers/XCreditsCharged"
},
"X-Credits-Refunded": {
"$ref": "#/components/headers/XCreditsRefunded"
},
"X-Request-Cost": {
"$ref": "#/components/headers/XRequestCost"
}
}
}
Layer answers and value schemas
When a response includes layer answers, their common frame is:
{
"additionalProperties": false,
"allOf": [
{
"else": {
"properties": {
"value": {
"type": "object"
}
}
},
"if": {
"properties": {
"coverage": {
"enum": [
"not_covered",
"not_computed"
]
}
}
},
"then": {
"properties": {
"value": {
"type": "null"
}
}
}
},
{
"if": {
"properties": {
"coverage": {
"enum": [
"covered",
"covered_no_data"
]
},
"layer": {
"const": "mpzp"
}
}
},
"then": {
"properties": {
"value": {
"$ref": "#/$defs/MpzpValue"
}
}
}
}
],
"description": "Wspólny format każdej odpowiedzi tematycznej. Pola właściwe dla danej kategorii znajdują się w value (schematy *Value w openapi.yaml).",
"properties": {
"as_of": {
"format": "date",
"type": [
"string",
"null"
]
},
"basis": {
"description": "Przepis lub reguła będąca podstawą wyliczonej odpowiedzi, np. „u.p.z.p. art. 59 ust. 3”.",
"type": [
"string",
"null"
]
},
"confidence": {
"maximum": 1,
"minimum": 0,
"type": "number"
},
"coverage": {
"$ref": "#/$defs/Coverage"
},
"hash": {
"description": "Skrót sha256 w zapisie szesnastkowym z coverage + ':' + canonical(value) (nagłówek parcel_record.sql). Wartość null dla danych ustalanych podczas żądania.",
"type": [
"string",
"null"
]
},
"layer": {
"$ref": "#/$defs/LayerKey"
},
"layer_version": {
"description": "Identyfikator obliczenia dla wcześniej obliczonych danych; live dla danych ustalanych podczas żądania.",
"type": "string"
},
"licence": {
"$ref": "#/$defs/Licence"
},
"method": {
"$ref": "#/$defs/Method"
},
"note": {
"description": "Jedno zdanie prostym językiem do przytoczenia przez agenta w każdym stanie: co oznacza wartość lub dlaczego jej brakuje. Bez określenia „bezpieczna” i bez „brak planu”, jeżeli nie wskazano rodzaju planu i źródła.",
"minLength": 1,
"type": "string"
},
"scope": {
"$ref": "#/$defs/Scope"
},
"source": {
"$ref": "#/$defs/SourceRef"
},
"threshold": {
"maximum": 1,
"minimum": 0,
"type": "number"
},
"value": {
"description": "Wartość null wtedy i tylko wtedy, gdy coverage wynosi not_covered lub not_computed.",
"type": [
"object",
"null"
]
}
},
"required": [
"layer",
"coverage",
"value",
"note",
"source",
"as_of",
"layer_version"
],
"type": "object"
}
Schema names correspond to the layer keys below. A schema dispatch constraint in LayerAnswer is not specified in v1.
| Layer key | LayerAnswer.value schema |
|---|---|
address | AddressValue |
admin | not specified in the source contract |
buildings | BuildingsValue |
flood | FloodValue |
landslide | LandslideValue |
mpzp | MpzpValue |
parcel | not specified in the source contract |
permits | PermitsValue |
planning | PlanningValue |
pog | PogValue |
prices | PricesValue |
protected | ProtectedValue |
road_access | RoadAccessValue |
soil | SoilValue |
wz | WzValue |
Referenced response definitions from openapi.yaml:
See Schemas for all operation-specific definitions.
Envelope references are defined in Envelope.
Coverage states
Cztery stany zakresu danych dla jednej kategorii w danym miejscu. covered: źródło obejmuje to miejsce i zawiera rekord; value zawiera ten rekord. covered_no_data: źródło obejmuje to miejsce, lecz nie zawiera rekordu; value ma określoną dla danej kategorii pustą wartość (false, 0, [], none), nigdy null; jest to potwierdzony brak rekordu, za który naliczana jest opłata. not_covered: źródło nie obejmuje miejsca albo państwo nie publikuje tych danych w postaci do odczytu maszynowego; value=null, agent nie może wyciągać wniosków, a opłata jest zwracana, gdy zapytanie dotyczy tych danych. not_computed: posiadamy źródło, lecz nie obliczyliśmy jeszcze wyniku dla tego miejsca, np. trwa ładowanie zbioru; value=null, opłata jest zwracana. Każdy stan zawiera uwagę napisaną prostym językiem.
States: covered | covered_no_data | not_covered | not_computed.
LayerAnswer required fields: layer, coverage, value, note, source, as_of, layer_version.
Billing rule
Koszt żądania. charged: liczba naliczonych wywołań po zwrotach. refunded: liczba wywołań naliczonych, a następnie zwróconych. rule: zastosowana reguła. Płatne są odpowiedzi, potwierdzone braki rekordów (covered_no_data) i niejednoznaczne listy kandydatów. Bezpłatne są błędne dane wejściowe (400), brak uwierzytelnienia (401), odpowiedzi bez zmiany danych (304) i operacje bezpłatne. Zwrot obejmuje pozostałe 4xx, każde 5xx, status not_covered oraz odpowiedź dotyczącą jednej kategorii ze stanem not_covered lub not_computed. W operacjach zbiorczych liczby dotyczą poszczególnych elementów.
Rule values: charged | free_operation | free_invalid_input | free_unauthorized | free_not_modified | refunded_client_error | refunded_server_error | refunded_not_covered | refunded_not_computed | batch_mixed.
Recorded example
No valid key supplied. Request UUID and response clock normalized. No database, socket, paid call or live coverage claim.
Recorded HTTP status: 401. The curl example reproduces this admission response with an unset API key. For supported authenticated operations, supply an account key and required permissions; data and billing then depend on that account. The Stripe receiver additionally requires a provider signature.
curl --silent --show-error --request GET "https://mcp.agentdzialek.pl/v1/resolve" --get \
-H "X-Api-Key: ${LANDFEED_API_KEY}" \
--data-urlencode 'id=141803_2.0001.12/3'
{
"billing": {
"charged": 0,
"cost": 1,
"refunded": 0,
"rule": "free_unauthorized"
},
"candidates": [],
"error": {
"code": "unauthorized",
"docs": "https://landfeed.pl/docs",
"example_id": "141803_2.0001.12/3",
"hint": "Podaj wydany klucz w nagłówku Authorization: Bearer lub X-Api-Key albo połącz się z MCP przez OAuth.",
"message": "Wymagany jest ważny klucz API lub token dostępu. Podaj go i ponów żądanie.",
"signup_url": "https://landfeed.pl/signup"
},
"meta": {
"api_version": "v1",
"calls": 1,
"generated_at": "2026-10-21T00:00:00Z",
"request_id": "00000000-0000-4000-8000-000000000000"
},
"needs_obreb": false,
"query": {
"input": {
"id": "141803_2.0001.12/3"
},
"resolved": null
},
"result": null,
"sources": [],
"status": "error"
}