# resolve_location

> Turn a place name or a lat/lon point into canonical area_ids (max 5 candidates).

Turn a place name or a lat/lon point into canonical area_ids (max 5 candidates). If status is 'ambiguous', do NOT pick one: ask the user or call again with area_type.

**Counts against your plan:** yes, one call. **Read-only:** yes, nothing you send is stored or changes any data.

## Inputs

| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| `query` | `string` | no | none | Place name, e.g. 'Matzikama', 'Kenilworth', 'West Coast'. |
| `lat` | `number` | no | none | WGS84 latitude (with lon) |
| `lon` | `number` | no | none | WGS84 longitude (with lat) |
| `area_type` | `"province" / "district" / "local_municipality" / "ward" / "police_station"` | no | none | Restrict to one geography type |

## Caps

| Cap | Value |
|---|---|
| Candidates returned | 5 |

Your plan can set lower caps. See [Plans and limits](/docs/limits). A request over a cap is refused with `LIMIT_EXCEEDED`; nothing is truncated silently.

## Response

Every response also carries `citations`, `caveats` and `dataset_version` ([Citations](/docs/citations)).

| Field | Type | Description |
|---|---|---|
| `citations` | `object[]` |  |
| `caveats` | `string[]` |  |
| `dataset_version` | `string` |  |
| `status` | `"resolved" / "ambiguous" / "not_found"` |  |
| `resolved_area_id` | `string` |  |
| `candidates` | `object[]` |  |
| `message` | `string` |  |

**`candidates[]`** (each item)

| Field | Type | Description |
|---|---|---|
| `area_id` | `string` |  |
| `name` | `string` |  |
| `area_type` | `string` |  |
| `province_code` | `string` |  |
| `parent_id` | `string` |  |
| `parent_name` | `string` |  |
| `match` | `"exact" / "prefix" / "contains" / "point_in_polygon"` |  |

## Examples

> **Fixture data**
>
> These responses were produced by the real tool against the synthetic test dataset (`fixture-2026.11.05`), so the numbers are illustrative, not real statistics. Production responses cite the real sources.

### A unique match

Request:

```json
{
  "query": "Matzikama"
}
```

Response:

```json
{
  "citations": [
    {
      "source_id": "mdb_wards_2026",
      "name": "[FIXTURE] MDB Wards 2026",
      "publisher": "Municipal Demarcation Board (MDB)",
      "url": "https://www.demarcation.org.za/",
      "licence": "MDB custom terms",
      "commercial_use": "unclear",
      "attribution": "Source: Municipal Demarcation Board (MDB)",
      "retrieved_at": "2026-11-05",
      "dataset_version": "fixture-2026.11.05"
    }
  ],
  "caveats": [
    "FIXTURE DATA: these numbers are synthetic test values, not real statistics. Do not use them for decisions.",
    "Licence note (mdb_wards_2026): MDB custom terms; commercial use 'unclear'. Served only as derived aggregates with attribution: Source: Municipal Demarcation Board (MDB)"
  ],
  "dataset_version": "fixture-2026.11.05",
  "status": "resolved",
  "resolved_area_id": "lm:WC011",
  "candidates": [
    {
      "area_id": "lm:WC011",
      "name": "Matzikama",
      "area_type": "local_municipality",
      "province_code": "WC",
      "parent_id": "dm:DC1",
      "parent_name": "West Coast",
      "match": "exact"
    }
  ],
  "message": "Resolved to Matzikama (local_municipality)."
}
```

Provenance in this example: source `mdb_wards_2026`, licence “MDB custom terms”, retrieved 2026-11-05, dataset_version `fixture-2026.11.05`.

### An ambiguous name (two police stations are called Kenilworth)

Request:

```json
{
  "query": "Kenilworth",
  "area_type": "police_station"
}
```

Response:

```json
{
  "citations": [
    {
      "source_id": "saps_crime_stats",
      "name": "[FIXTURE] SAPS Crime Statistics",
      "publisher": "South African Police Service (SAPS)",
      "url": "https://www.saps.gov.za/services/crimestats.php",
      "licence": "SAPS website copyright (no open licence)",
      "commercial_use": "unclear",
      "attribution": "Source: South African Police Service, Crime Statistics",
      "retrieved_at": "2026-11-05",
      "dataset_version": "fixture-2026.11.05"
    }
  ],
  "caveats": [
    "FIXTURE DATA: these numbers are synthetic test values, not real statistics. Do not use them for decisions.",
    "Licence note (saps_crime_stats): SAPS website copyright (no open licence); commercial use 'unclear'. Served only as derived aggregates with attribution: Source: South African Police Service, Crime Statistics"
  ],
  "dataset_version": "fixture-2026.11.05",
  "status": "ambiguous",
  "resolved_area_id": null,
  "candidates": [
    {
      "area_id": "saps:kenilworth-gt",
      "name": "Kenilworth",
      "area_type": "police_station",
      "province_code": "GT",
      "parent_id": "prov:GT",
      "parent_name": "Gauteng",
      "match": "exact"
    },
    {
      "area_id": "saps:kenilworth-wc",
      "name": "Kenilworth",
      "area_type": "police_station",
      "province_code": "WC",
      "parent_id": "prov:WC",
      "parent_name": "Western Cape",
      "match": "exact"
    }
  ],
  "message": "'Kenilworth' matches several places; no guess was made. Ask the user which one they mean, or call again with area_type or a more specific name."
}
```

Provenance in this example: source `saps_crime_stats`, licence “SAPS website copyright (no open licence)”, retrieved 2026-11-05, dataset_version `fixture-2026.11.05`.

## Errors

Errors read `<CODE>: <what went wrong>. Fix: <how to fix it>`. Shared codes are on the [Tool reference](/docs/tools) page.

| Request | Error |
|---|---|
| `{}` | `INVALID_ARGUMENT: Give a place name (query) or a point (lat and lon). Fix: e.g. resolve_location(query='Matzikama') or resolve_location(lat=-31.6, lon=18.5).` |
| `{"lat": -31.0}` | `INVALID_ARGUMENT: lat and lon must be given together. Fix: Pass both lat and lon.` |
