# Metrocuadrado Locations API Documentation

Scrappa's `GET /api/metrocuadrado/locations` endpoint resolves Colombian place names, in two modes. Each request performs one lookup; the modes are alternatives, not a chain.

**`mode=autocomplete` (default)** takes free text such as `bogota` and returns the source's six suggestion levels — cities, neighbourhoods, points, regions, sectors and zones — each with a display label and the token to use in a search. This is what a type-ahead field should call.

**`mode=fanout`** takes a place token and returns the source's own vocabulary for that place — useful for resolving `city` and `zone` tokens, and for autocomplete. Pass `level=zones` (default), `level=cities` or `level=neighborhoods`. The resolved vocabulary is cached for 30 minutes, so repeated lookups of the same city cost one lookup, not one per request.

**It does not return a complete neighbourhood partition and must not be used as one.** The source caps the neighbourhood list at 100 rows and does not scope it to the queried city: for `q=bogota` it returns an alphabetical slice of a global vocabulary and omits most barrios, including Chapinero. `level=zones` is city-scoped, but its union covers only 56.1 % of the Bogotá venta/apartment cell (16,218 of 28,888, with Norte alone at 9,598 — 93 % of the 10,000 page ceiling). A sweep built on either list silently misses rows, so the response sets `is_complete_enumeration: false` on every call.

`neighborhood` remains a valid **filter** value — a bare slug; `chapinero` matches 769 listings. To subdivide a large cell without silent loss, use the radius grid (`latitude`, `longitude`, `distance`) on the search endpoint: inside a radius every returned listing is geo-referenced. The radius grid is **best effort over the geo-referenced subset** — 98.8 % for that cell and 89.9 % nationally — so it is not lossless, and **no partition available here is provably exhaustive**. Start the grid at 3 km or tighter; at 5 km the cell is past the row ceiling again.

A token is not a URL fragment. Passing `bogota/chapinero` where `chapinero` is expected is rejected with a 422 rather than answered with an empty page.

A term the source does not know returns a non-billable error rather than an empty success.

- **Documentation:** [https://scrappa.co/docs/metrocuadrado-api/metrocuadrado_locations](https://scrappa.co/docs/metrocuadrado-api/metrocuadrado_locations)
- **API group:** Metrocuadrado API
- **Endpoint:** `GET https://scrappa.co/api/metrocuadrado/locations`

## Authentication

Send your Scrappa API key in the `X-API-KEY` request header. Paid endpoints also support accountless x402 payments when called without an API key.

## Parameters

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `q` | string | Yes | Free text in autocomplete mode, or a place token in fanout mode. |
| `mode` | string | No | autocomplete (default) or fanout. |
| `level` | string | No | fanout mode only: zones (default, city-scoped), cities, or neighborhoods. The neighborhood list cannot enumerate a city. |

## Example request

```bash
#!/bin/bash

curl -X GET \
    -H "x-api-key: YOUR_API_KEY_HERE" \
    "https://scrappa.co/api/metrocuadrado/locations?q=bogota&mode=fanout"
```

## Example response

```json
{
    "success": true,
    "mode": "fanout",
    "query": "bogota",
    "level": "zones",
    "count": 1,
    "values": [
        {
            "token": "norte",
            "label": "Norte",
            "city": "bogota",
            "zone": "norte",
            "neighborhood": null,
            "latitude": null,
            "longitude": null
        }
    ],
    "is_complete_enumeration": false,
    "available_levels": [
        "cities",
        "zones",
        "neighborhoods"
    ],
    "did_you_mean": null,
    "meta": {
        "endpoint_family": "locations",
        "fanout_axes": [
            "business_type",
            "property_type",
            "city",
            "neighborhood"
        ],
        "fanout_axis_sources": {
            "business_type": "client-side value; list them at /api/metrocuadrado/types?type=deal",
            "property_type": "client-side value; list them at /api/metrocuadrado/types?type=property",
            "city": "token from this endpoint (level=cities)",
            "neighborhood": "a working filter on /search by bare slug, but its partition is NOT available from this endpoint - enumerate with the radius grid instead"
        },
        "note": "Use the token in `location` for the city and neighborhood parameters of /search. URL fragments are a different vocabulary and are not accepted there.",
        "partition_method": "To split a large city, subdivide by radius instead: pass latitude, longitude and distance to /search. Inside a radius every returned listing is geo-referenced, so the grid cannot silently drop rows it can see. Start the grid at 3 km or tighter: at 5 km a large cell already exceeds the row ceiling again. It is still not an exhaustive sweep: listings carrying no coordinates are unreachable by radius (roughly 2 percent of sale and 6 percent of rent inventory carries none), so no partition here is provably complete. Do not build one from this vocabulary."
    }
}
```

## Errors

| Status | Error | Description |
| --- | --- | --- |
| 422 | Error | The term is missing, is a URL fragment in fanout mode, or an unknown parameter was sent. Nothing is charged. |
| 404 | Error | The source knows no location for this term. Not charged. |
| 503 | Error | The source was unreachable. Not charged, safe to retry. |

## More Scrappa resources

- [API documentation](https://scrappa.co/docs)
- [Full LLM-readable API reference](https://scrappa.co/llms-full.txt)
- [OpenAPI specification](https://scrappa.co/docs/api.json)
- [Pricing](https://scrappa.co/pricing)
