# Docs

## Quickstarts

- [Leaflet](https://pinsharing.com/docs/leaflet) — raster tiles and address search in Leaflet
- [MapLibre GL JS](https://pinsharing.com/docs/maplibre) — vector tiles and styles
- [OpenLayers](https://pinsharing.com/docs/openlayers) — raster and vector tiles in OpenLayers
- [AI assistants (MCP)](https://pinsharing.com/docs/mcp) — connect Claude, Cursor, VS Code and other MCP clients

Machine-readable: [OpenAPI 3.1 spec](https://pinsharing.com/openapi.json) · [llms.txt](https://pinsharing.com/llms.txt) · [this page as Markdown](https://pinsharing.com/docs.md)

## Getting started

Get a key from the [dashboard](https://pinsharing.com/dashboard). Every request takes it as `?key=ps_…` or as an `Authorization: Bearer ps_…` header. The base URL is `https://api.pinsharing.com`.

```bash
curl "https://api.pinsharing.com/v1/geocode?q=Oswego%20IL&limit=1&key=YOUR_KEY"
```

JavaScript:

```
const r = await fetch("https://api.pinsharing.com/v1/geocode?q=" + encodeURIComponent("Oswego IL") + "&limit=1", {
  headers: { Authorization: "Bearer YOUR_KEY" }
});
const { features } = await r.json();
const [lng, lat] = features[0].geometry.coordinates;
```

Python:

```
import requests
r = requests.get("https://api.pinsharing.com/v1/geocode", params={"q": "Oswego IL", "limit": 1},
                 headers={"Authorization": "Bearer YOUR_KEY"}, timeout=10)
lng, lat = r.json()["features"][0]["geometry"]["coordinates"]
```

PHP (for example in WordPress):

```
$url = "https://api.pinsharing.com/v1/geocode?" . http_build_query(["q" => "Oswego IL", "limit" => 1, "key" => "YOUR_KEY"]);
$data = json_decode(file_get_contents($url), true);
[$lng, $lat] = $data["features"][0]["geometry"]["coordinates"];
```

## Static images

`GET /v1/static` returns an image. Give a `center` and `zoom`, or let us fit the view to your markers, path or area.

| Parameter | Meaning | Default |
| --- | --- | --- |
| `center` | `lat,lng` | fitted |
| `zoom` | 0 to 20, decimals allowed | fitted |
| `size` | `WIDTHxHEIGHT`, each 16 to 1280 | `600x400` |
| `scale` | `2` for high-density screens | `1` |
| `style` | `light`, `dark`, `white`, `grayscale` | `light` |
| `format` | `png`, `jpg`, `webp` | `png` |
| `markers` | Up to 25 points: `lat,lng\|lat,lng` |  |
| `marker_color` | Hex colour | `e11d48` |
| `path` | A line through 2 to 200 points: `lat,lng\|lat,lng\|…` |  |
| `path_color`, `path_width` | Hex colour; 1 to 12 px | `2563eb`, 4 |
| `padding` | Pixels kept clear around fitted content | 40 |

```html
<img src="https://api.pinsharing.com/v1/static?markers=41.8781,-87.6298|41.6828,-88.3515&size=600x300&scale=2&key=YOUR_KEY"
     width="600" height="300" alt="Map from Chicago to Oswego">
```

Images are deterministic: the same URL gives the same picture, so cache them for as long as your plan allows. On the Free plan, images carry a small "Map by pinsharing.com" mark in the bottom-left corner; paid plans have none.

## Privacy area mode

For listings, deliveries or anything where the exact address should stay private. Send the real point as `area`; we snap it to a grid, draw a shaded circle, and add no pin.

| Parameter | Meaning | Default |
| --- | --- | --- |
| `area` | The real `lat,lng` |  |
| `radius` | Circle radius in metres, 100 to 25000. Raised if needed so the circle always contains the real point. | 1000 |
| `snap` | Grid size in degrees, 0 to 0.1. 0.01 is about 1 km. | 0.01 |
| `color` | Hex colour of the circle | `0f766e` |

```
https://api.pinsharing.com/v1/static?area=41.6843,-88.3512&size=640x300&key=YOUR_KEY
```

Try it without a key

Every address in the same grid cell gets the identical image, so viewers can't narrow the location down by comparing maps. Build the URL on your server if the real point must never reach the browser; the image itself contains only the snapped circle. See [privacy-safe listing maps](https://pinsharing.com/privacy-maps) for a full walkthrough.

## Address search

`GET /v1/geocode?q=…` returns GeoJSON features, best match first. `/v1/autocomplete` takes the same parameters and suits type-ahead boxes; each call counts as one lookup, so wait for a short pause in typing (about 250 ms) before calling it.

| Parameter | Meaning |
| --- | --- |
| `q` | Text to search for (required) |
| `limit` | 1 to 20, default 5 |
| `lat`, `lon` | Prefer results near this point |
| `bbox` | `minLon,minLat,maxLon,maxLat` to restrict results |
| `lang` | `en`, `de`, `fr` or `default` (local names) |
| `layer` | Filter: `house`, `street`, `city`, `county`, `state`, `country` and more |

```bash
curl "https://api.pinsharing.com/v1/geocode?q=4%20Yorkville%20Rd%20Oswego&limit=1&key=YOUR_KEY"
```

Try it without a key

```

```

Paid plans may store and reuse results indefinitely; Free results may be stored for up to 30 days. Each response carries a `license` field that says which applies. US house-number coverage follows OpenStreetMap and varies by area; street and town results are reliable everywhere.

## Reverse lookup

`GET /v1/reverse?lat=…&lon=…` returns the nearest address or place. Optional `radius` (km), `limit`, `lang`.

## Raster tiles

256-pixel PNG tiles, with `@2x` for sharp screens. Use them with Leaflet, OpenLayers or anything that takes an XYZ URL. A typical map view loads about 16 tiles.

```
L.tileLayer("https://api.pinsharing.com/v1/tiles/light/{z}/{x}/{y}@2x.png?key=YOUR_KEY", {
  tileSize: 256, maxZoom: 19,
  attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap contributors</a>'
}).addTo(map);
```

## Vector tiles & styles

For MapLibre GL, point the map at a style. Fonts, icons and tile URLs inside it already carry your key.

```
new maplibregl.Map({
  container: "map",
  style: "https://api.pinsharing.com/v1/styles/light.json?key=YOUR_KEY",
  center: [-88.35, 41.68], zoom: 12
});
```

Styles: `light`, `dark`, `white`, `grayscale`. Raw tiles are at `/v1/tiles/vector/{z}/{x}/{y}.pbf` (Protomaps schema, zoom 0 to 15), described by `/v1/tiles/vector.json`.

## Keys & websites

Keys used in web pages are visible to visitors. In the dashboard, limit such a key to your websites (for example `example.com, *.example.com`); requests from other sites are refused. Keep an unrestricted key on your server only. Revoking a key takes effect within a minute. Free accounts have 1 key; paid plans up to 20.

## Plans, caps & errors

Each plan has a monthly cap per product (see [Pricing](https://pinsharing.com/pricing)). Caps reset on the 1st of each month (UTC). We email the account at 80% and at 100% of a cap. The Free plan also allows 5 requests a second per account, with bursts up to 60; paid plans have no per-second limit.

Errors are JSON with an `error` code and a readable `message`.

| Status | `error` | Meaning |
| --- | --- | --- |
| 400 | `bad_request` | A parameter is missing or out of range |
| 401 | `missing_key`, `invalid_key` | No key, or a revoked one |
| 403 | `referer_denied` | The key is limited to other websites |
| 404 | `not_found` | No such tile, style or path |
| 429 | `monthly_cap_reached` | This product's cap is used up; includes `product`, `cap`, `resets` and `upgrade_url` |
| 429 | `slow_down` | Free plan rate limit; retry after the `Retry-After` header (1 second) |
| 502 | `engine_error` | Temporary; retry shortly |

## Attribution

Map data comes from OpenStreetMap under the Open Database License. Show © OpenStreetMap contributors near any map or results you display, linked to [openstreetmap.org/copyright](https://www.openstreetmap.org/copyright). Static images already include it in the corner. PinSharing is not affiliated with or endorsed by the OpenStreetMap Foundation.

---
Source: https://pinsharing.com/docs · Map data © OpenStreetMap contributors · Index: https://pinsharing.com/llms.txt
