# Polygrid Maps

> Ephemeral, shareable web maps for AI agents. POST GeoJSON or place names, get back a link (plus a PNG preview and a markdown snippet) to give the user. No API key. Maps are deleted after 24 h without views.

Base URL: https://maps.polygrid.dev

## Create a map

`POST https://maps.polygrid.dev/v1/maps` with a JSON body. At least one of `data` or `places` is required.

Named places (geocoded for you; prefer this over inventing coordinates):

```bash
curl -X POST https://maps.polygrid.dev/v1/maps -H 'Content-Type: application/json' -d '{
  "title": "Weekend in Prague",
  "places": ["Prague Castle", "Charles Bridge, Prague", "Old Town Square, Prague"],
  "connect": true
}'
```

`connect: true` draws a straight line through the places in order and numbers the pins 1..n. `"route": "car"` (or `bike`, `foot`) follows roads instead and adds distance and travel time, e.g. `{"places": ["Prague", "Bratislava"], "route": "car"}` → "2 places and a 335 km drive (about 3 h 36 min)". If a place is unroutable (>5 km from a road), it falls back to straight lines with a warning. A place can also be an object with its own style: `{"q": "Charles Bridge, Prague", "title": "Bridge", "marker-color": "#e11d48"}`. Max 50 places. Add city/country to names to avoid ambiguity.

GeoJSON (FeatureCollection, Feature, GeometryCollection or a bare geometry, including Multi*). Coordinates are `[longitude, latitude]`:

```bash
curl -X POST https://maps.polygrid.dev/v1/maps -H 'Content-Type: application/json' -d '{
  "data": {"type": "LineString", "coordinates": [[14.4005, 50.0908], [14.4114, 50.0865], [14.4208, 50.0875]]},
  "basemap": "dark"
}'
```

Styled features (simplestyle-spec properties on each feature):

```bash
curl -X POST https://maps.polygrid.dev/v1/maps -H 'Content-Type: application/json' -d '{
  "title": "Coffee and parks",
  "data": {"type": "FeatureCollection", "features": [
    {"type": "Feature", "properties": {"title": "Café Louvre", "description": "Since 1902", "marker-color": "#b45309", "marker-symbol": "☕"},
     "geometry": {"type": "Point", "coordinates": [14.4193, 50.0820]}},
    {"type": "Feature", "properties": {"title": "Letná Park", "fill": "#16a34a", "fill-opacity": 0.3, "stroke": "#15803d"},
     "geometry": {"type": "Polygon", "coordinates": [[[14.410, 50.096], [14.432, 50.096], [14.432, 50.100], [14.410, 50.100], [14.410, 50.096]]]}}
  ]}
}'
```

### Request fields

- `data`: GeoJSON object.
- `places`: list of names/addresses, or `{q, title, description, marker-color, marker-symbol, …}` objects.
- `connect`: `true` for an itinerary line through `places`, with numbered pins.
- `route`: `car`, `bike` or `foot` (`true` = car): follow roads through `places` in order instead of straight lines. Routing by FOSSGIS OSRM.
- `title`, `description`: plain text. Generated from the data when omitted (e.g. "Prague Castle → Charles Bridge → Old Town Square").
- `basemap`: `positron` (default, light), `liberty` (streets), `bright`, `dark`, `fiord`. Aliases: `light`, `streets`.
- `marker`: `pin` | `dot` | `none`. Default: pin up to 300 points, dot above.
- `color`: default feature color, hex (`#2563eb`).
- `cluster`: cluster points (default: on above 1000 points). `labels`: draw feature titles as labels.
- `center` `[lng, lat]` and `zoom` (0–22): initial view. Omit to fit all features.

## Response (201)

```json
{
  "id": "k3f9q2xa7b",
  "url": "https://maps.polygrid.dev/m/k3f9q2xa7b",
  "image_url": "https://maps.polygrid.dev/m/k3f9q2xa7b.png",
  "data_url": "https://maps.polygrid.dev/m/k3f9q2xa7b.geojson",
  "title": "Prague Castle → Charles Bridge → Old Town Square",
  "description": "3 places and a 1.6 km route in Prague, Czechia.",
  "alt_text": "Map of Prague, Czechia showing 3 places and a 1.6 km route.",
  "markdown": "[![Map of Prague, Czechia showing 3 places and a 1.6 km route.](https://maps.polygrid.dev/m/k3f9q2xa7b.png)](https://maps.polygrid.dev/m/k3f9q2xa7b)",
  "embed_html": "<iframe src=\"https://maps.polygrid.dev/m/k3f9q2xa7b?embed=1\" …></iframe>",
  "expires": "Deleted after 24h without views",
  "feature_count": 4,
  "bbox": [14.4005, 50.0865, 14.4208, 50.0908],
  "warnings": []
}
```

Give the user `url`. In chat or markdown replies, `markdown` shows the preview image linked to the map. `warnings` lists inputs that were fixed or skipped (swapped lat/lng, unknown basemap, a place that could not be geocoded); mention the relevant ones.

## Simplestyle cheat sheet (feature `properties`)

| Property | Applies to | Example |
|---|---|---|
| `title` | all | `"Old Town Square"` (popup title, label) |
| `description` | all | plain text popup body |
| `marker-color` | points | `"#e11d48"` |
| `marker-size` | points | `"small"` \| `"medium"` \| `"large"` |
| `marker-symbol` | points | emoji (`"☕"`), 1–2 characters, or a number |
| `stroke`, `stroke-width`, `stroke-opacity` | lines, polygon outlines | `"#1d4ed8"`, `3`, `0.8` |
| `fill`, `fill-opacity` | polygons | `"#16a34a"`, `0.3` |
| `category` or `group` | all | features without a color get one per category (up to 10) and the map shows a legend |

Other properties appear in the popup as a table; http(s) values become links.

## Viewer URL parameters

Append to `url` to change the display without creating a new map: `?basemap=dark&marker=dot&color=e11d48&cluster=1&labels=1`. `embed=1` hides the title panel (for iframes). Other files per map: `/m/{id}.geojson` (normalized data), `/m/{id}.png` (1200×630 preview, rendered on first request), `/oembed?url=…` (oEmbed).

## Limits

- Maps are deleted after 24 h without views. Each view extends the lifetime.
- Request body up to 2 MB. Up to 50 places per request.
- 60 creates per minute per IP.
- Maps cannot be edited or deleted. Create a new one instead.

## Errors

Errors are JSON `{"error": "…", "hint": "…", "example": {…}}`. `hint` says how to fix the call and `example` is a minimal valid request. Codes: 400 invalid input, 404 unknown or expired map, 413 body too large, 429 rate limited (see `Retry-After`), 503 preview image temporarily unavailable.

## MCP

Remote MCP server (streamable HTTP, no auth): `https://maps.polygrid.dev/mcp`. One tool, `create_map`, with the same input as `POST /v1/maps`.

Claude Code: `claude mcp add --transport http polygrid-maps https://maps.polygrid.dev/mcp`

## More

- [OpenAPI spec](https://maps.polygrid.dev/openapi.json)
- [Human docs](https://maps.polygrid.dev/docs)
