---
title: "Resolve or create a city from an IP address"
method: GET
path: "/cities/ip"
tags: ["Cities"]
---

# Resolve or create a city from an IP address

`GET /cities/ip`

## Request

- Base URL: `https://api.purplegrain.com/api/v1`
- URL: `https://api.purplegrain.com/api/v1/cities/ip`
- Auth: none declared

Resolve an IPv4 or IPv6 address through the local GeoIP catalogue. Pass the end user's `ip`. If `ip` is omitted, the API uses the request's remote IP, which over MCP is the server's address rather than the person's. Reuses an existing city with the same name, subdivision and country, or persists a shared city and location record when missing. Returns the saved city ID and fields; request `include=location` for coordinates. This lookup can create records even though the API uses GET, so its MCP tool requires `confirm: true` when confirmation is enabled. Returns 404 when the GeoIP data has no city-level location.

## Query parameters

- `ip` string
- `include` string

## Response `200`

Successful. When the `include` query parameter is used, the response may contain an `included` array (JSON:API) or inlined related resources (application/json).

- CitiesShowResponseAttributes
  - `data` CityModelAttributes: City in attributes-adapter shape (Accept application/json); fields at top level.
    - `id` string
    - `type` string
    - `place_id` string, nullable
    - `name` string
    - `subdivision` string
    - `country` string
    - `location` object: Inlined when include=location

## Other responses

- `400`: Bad Request
- `404`: Valid IP but no city-level GeoIP record (e.g. datacenter/VPN egress) — treat as "no location default", not an error.

---

[API](https://skmtc.dev/purplegrain/apis/purple-grain-api.md) · [All operations](https://skmtc.dev/purplegrain/apis/purple-grain-api/llms.txt) · [OpenAPI document](https://skmtc.dev/purplegrain/apis/purple-grain-api/revisions/4bedbc1c784c?raw)
