{
  "openapi": "3.1.0",
  "info": {
    "title": "PinSharing API",
    "version": "1.0.0",
    "description": "Map API built on OpenStreetMap data: static map images (including a privacy area mode), geocoding and reverse geocoding, and raster and vector tiles.\n\nEvery request takes an API key as `?key=ps_\u2026` or `Authorization: Bearer ps_\u2026`. Plans have hard monthly caps per product; when a cap is reached the product returns 429 until the first of the next month or until you upgrade. Show \"\u00a9 OpenStreetMap contributors\" wherever maps or results appear.",
    "termsOfService": "https://pinsharing.com/terms",
    "contact": {
      "name": "PinSharing support",
      "email": "support@pinsharing.com",
      "url": "https://pinsharing.com"
    }
  },
  "externalDocs": {
    "url": "https://pinsharing.com/docs"
  },
  "servers": [
    {
      "url": "https://api.pinsharing.com"
    }
  ],
  "security": [
    {
      "apiKeyQuery": []
    },
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Static maps"
    },
    {
      "name": "Geocoding"
    },
    {
      "name": "Tiles"
    },
    {
      "name": "MCP"
    },
    {
      "name": "Service"
    }
  ],
  "x-attribution": "\u00a9 OpenStreetMap contributors",
  "components": {
    "securitySchemes": {
      "apiKeyQuery": {
        "type": "apiKey",
        "in": "query",
        "name": "key"
      },
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "ps_\u2026"
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "error",
          "message"
        ],
        "properties": {
          "error": {
            "type": "string",
            "enum": [
              "missing_key",
              "invalid_key",
              "referer_denied",
              "monthly_cap_reached",
              "bad_request",
              "not_found",
              "slow_down",
              "engine_error",
              "internal",
              "unavailable"
            ]
          },
          "message": {
            "type": "string"
          },
          "product": {
            "type": "string"
          },
          "cap": {
            "type": "integer"
          },
          "resets": {
            "type": "string",
            "format": "date"
          },
          "upgrade_url": {
            "type": "string",
            "format": "uri"
          }
        }
      },
      "GeocodeResponse": {
        "type": "object",
        "required": [
          "type",
          "features",
          "attribution",
          "license"
        ],
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "FeatureCollection"
            ]
          },
          "features": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/GeocodeFeature"
            }
          },
          "attribution": {
            "type": "string"
          },
          "license": {
            "type": "string"
          }
        }
      },
      "GeocodeFeature": {
        "type": "object",
        "required": [
          "type",
          "geometry",
          "properties"
        ],
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "Feature"
            ]
          },
          "geometry": {
            "type": "object",
            "required": [
              "type",
              "coordinates"
            ],
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "Point"
                ]
              },
              "coordinates": {
                "type": "array",
                "minItems": 2,
                "maxItems": 2,
                "items": {
                  "type": "number"
                },
                "description": "[longitude, latitude]"
              }
            }
          },
          "properties": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string"
              },
              "housenumber": {
                "type": "string"
              },
              "street": {
                "type": "string"
              },
              "postcode": {
                "type": "string"
              },
              "city": {
                "type": "string"
              },
              "district": {
                "type": "string"
              },
              "county": {
                "type": "string"
              },
              "state": {
                "type": "string"
              },
              "country": {
                "type": "string"
              },
              "countrycode": {
                "type": "string"
              },
              "osm_type": {
                "type": "string"
              },
              "osm_id": {
                "type": "string"
              },
              "osm_key": {
                "type": "string"
              },
              "osm_value": {
                "type": "string"
              },
              "type": {
                "type": "string"
              },
              "extent": {
                "type": "array",
                "items": {
                  "type": "number"
                }
              }
            },
            "additionalProperties": true
          }
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Bad request: missing or invalid parameters.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Missing or invalid API key.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Forbidden": {
        "description": "Key is not allowed from this website.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "NotFound": {
        "description": "No such tile, style or path.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "TooMany": {
        "description": "monthly_cap_reached or slow_down; see Retry-After.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "EngineError": {
        "description": "Temporary engine error; retry shortly.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    }
  },
  "paths": {
    "/v1/static": {
      "get": {
        "operationId": "staticMap",
        "summary": "Render a static map image",
        "description": "Give center+zoom, or any of area/markers/path to fit automatically. Privacy area mode snaps the point to a grid, always keeps the real point inside the circle, draws no pin, and returns the identical image for every address in the same grid cell. Counts as 1 static image. Free plan adds a small mark.",
        "tags": [
          "Static maps"
        ],
        "parameters": [
          {
            "name": "center",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "lat,lng"
          },
          {
            "name": "zoom",
            "in": "query",
            "schema": {
              "type": "number",
              "minimum": 0,
              "maximum": 20
            },
            "description": "0 to 20."
          },
          {
            "name": "size",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "600x400"
            },
            "description": "WIDTHxHEIGHT; each side 16 to 1280."
          },
          {
            "name": "scale",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 1,
              "enum": [
                1,
                2
              ]
            }
          },
          {
            "name": "style",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "light",
              "enum": [
                "light",
                "dark",
                "white",
                "grayscale"
              ]
            }
          },
          {
            "name": "format",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "png",
              "enum": [
                "png",
                "jpg",
                "webp"
              ]
            }
          },
          {
            "name": "padding",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 40
            },
            "description": "Pixels kept clear around fitted content."
          },
          {
            "name": "markers",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "lat,lng|lat,lng; up to 25 points."
          },
          {
            "name": "marker_color",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Hex colour."
          },
          {
            "name": "path",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "lat,lng|\u2026; 2 to 200 points."
          },
          {
            "name": "path_color",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Hex colour."
          },
          {
            "name": "path_width",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 4,
              "minimum": 1,
              "maximum": 12
            }
          },
          {
            "name": "area",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Privacy area centre as lat,lng."
          },
          {
            "name": "radius",
            "in": "query",
            "schema": {
              "type": "number",
              "default": 1000,
              "minimum": 100,
              "maximum": 25000
            },
            "description": "Circle radius in metres."
          },
          {
            "name": "snap",
            "in": "query",
            "schema": {
              "type": "number",
              "default": 0.01,
              "minimum": 0,
              "maximum": 0.1
            },
            "description": "Grid size in degrees; 0.01 is about 1 km."
          },
          {
            "name": "color",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Hex colour for the area circle."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "image/png": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "image/jpeg": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "image/webp": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "Bad request: missing or invalid parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Key is not allowed from this website.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "monthly_cap_reached or slow_down; see Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "Temporary engine error; retry shortly.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/geocode": {
      "get": {
        "operationId": "geocode",
        "summary": "Forward geocoding",
        "description": "Turns an address or place name into GeoJSON features. Counts as 1 geocode.",
        "tags": [
          "Geocoding"
        ],
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "schema": {
              "type": "string",
              "maxLength": 300
            },
            "required": true,
            "description": "Text to search for."
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 5,
              "minimum": 1,
              "maximum": 20
            }
          },
          {
            "name": "lang",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Language code, or default for local names."
          },
          {
            "name": "lat",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Prefer results near this latitude."
          },
          {
            "name": "lon",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Prefer results near this longitude."
          },
          {
            "name": "bbox",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "minLon,minLat,maxLon,maxLat to restrict results."
          },
          {
            "name": "layer",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Feature layer filter, e.g. house, street, city."
          },
          {
            "name": "osm_tag",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "OpenStreetMap tag filter."
          },
          {
            "name": "zoom",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Location bias zoom."
          },
          {
            "name": "location_bias_scale",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Location bias scale."
          }
        ],
        "responses": {
          "200": {
            "description": "GeoJSON results.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GeocodeResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad request: missing or invalid parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Key is not allowed from this website.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "monthly_cap_reached or slow_down; see Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "Temporary engine error; retry shortly.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/autocomplete": {
      "get": {
        "operationId": "autocomplete",
        "summary": "Address autocomplete",
        "description": "Same parameters as geocode; suited to type-ahead boxes. Counts as 1 geocode.",
        "tags": [
          "Geocoding"
        ],
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "schema": {
              "type": "string",
              "maxLength": 300
            },
            "required": true,
            "description": "Text to search for."
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 5,
              "minimum": 1,
              "maximum": 20
            }
          },
          {
            "name": "lang",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Language code, or default for local names."
          },
          {
            "name": "lat",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Prefer results near this latitude."
          },
          {
            "name": "lon",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Prefer results near this longitude."
          },
          {
            "name": "bbox",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "minLon,minLat,maxLon,maxLat to restrict results."
          },
          {
            "name": "layer",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Feature layer filter, e.g. house, street, city."
          },
          {
            "name": "osm_tag",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "OpenStreetMap tag filter."
          },
          {
            "name": "zoom",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Location bias zoom."
          },
          {
            "name": "location_bias_scale",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Location bias scale."
          }
        ],
        "responses": {
          "200": {
            "description": "GeoJSON results.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GeocodeResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad request: missing or invalid parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Key is not allowed from this website.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "monthly_cap_reached or slow_down; see Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "Temporary engine error; retry shortly.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/reverse": {
      "get": {
        "operationId": "reverseGeocode",
        "summary": "Reverse geocoding",
        "description": "Coordinates to the nearest address or place. Counts as 1 geocode.",
        "tags": [
          "Geocoding"
        ],
        "parameters": [
          {
            "name": "lat",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "required": true
          },
          {
            "name": "lon",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "required": true
          },
          {
            "name": "radius",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Radius in km."
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 5,
              "minimum": 1,
              "maximum": 20
            }
          },
          {
            "name": "lang",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "layer",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "osm_tag",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "GeoJSON results.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GeocodeResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad request: missing or invalid parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Key is not allowed from this website.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "monthly_cap_reached or slow_down; see Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "Temporary engine error; retry shortly.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/tiles/{style}/{z}/{x}/{file}": {
      "get": {
        "operationId": "rasterTile",
        "summary": "Raster map tile",
        "description": "256-pixel raster tile. Counts as 1 tile.",
        "tags": [
          "Tiles"
        ],
        "parameters": [
          {
            "name": "style",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "light",
                "dark",
                "white",
                "grayscale"
              ]
            }
          },
          {
            "name": "z",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 20
            }
          },
          {
            "name": "x",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "file",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "image/png": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "image/jpeg": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "image/webp": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "Bad request or unknown style.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Key is not allowed from this website.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such tile.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "monthly_cap_reached or slow_down; see Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/tiles/vector/{z}/{x}/{file}": {
      "get": {
        "operationId": "vectorTile",
        "summary": "Vector map tile",
        "description": "Protomaps basemap schema vector tile. Counts as 1 tile.",
        "tags": [
          "Tiles"
        ],
        "parameters": [
          {
            "name": "z",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 15
            }
          },
          {
            "name": "x",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "file",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "{y}.pbf"
          }
        ],
        "responses": {
          "200": {
            "description": "Vector tile.",
            "content": {
              "application/x-protobuf": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Key is not allowed from this website.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such tile.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "monthly_cap_reached or slow_down; see Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/tiles/vector.json": {
      "get": {
        "operationId": "tileJSON",
        "summary": "Vector TileJSON",
        "description": "TileJSON for the Protomaps vector basemap. Free of charge.",
        "tags": [
          "Tiles"
        ],
        "responses": {
          "200": {
            "description": "TileJSON.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "monthly_cap_reached or slow_down; see Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/styles/{file}": {
      "get": {
        "operationId": "style",
        "summary": "MapLibre style JSON",
        "description": "MapLibre style whose tile, glyph and sprite URLs already carry the caller's key. Free of charge.",
        "tags": [
          "Tiles"
        ],
        "parameters": [
          {
            "name": "file",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "{style}.json"
          }
        ],
        "responses": {
          "200": {
            "description": "MapLibre style JSON.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such style.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "monthly_cap_reached or slow_down; see Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/mcp": {
      "post": {
        "operationId": "mcp",
        "summary": "PinSharing MCP server",
        "description": "Streamable HTTP JSON-RPC 2.0 endpoint. Stateless; no SSE. initialize and tools/list need no key. tools/call uses the API key and counts like REST.",
        "tags": [
          "MCP"
        ],
        "externalDocs": {
          "url": "https://pinsharing.com/docs/mcp"
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "jsonrpc",
                  "method"
                ],
                "properties": {
                  "jsonrpc": {
                    "type": "string",
                    "enum": [
                      "2.0"
                    ]
                  },
                  "id": {
                    "type": [
                      "string",
                      "integer"
                    ]
                  },
                  "method": {
                    "type": "string"
                  },
                  "params": {
                    "type": "object"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "JSON-RPC response.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Bad request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "monthly_cap_reached or slow_down; see Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "Temporary engine error; retry shortly.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/health": {
      "get": {
        "operationId": "health",
        "summary": "Service health",
        "description": "Reports whether the service and database are OK. No API key required.",
        "tags": [
          "Service"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Health JSON.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "502": {
            "description": "Service unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/meta": {
      "get": {
        "operationId": "meta",
        "summary": "Public metadata",
        "description": "Plans, styles and attribution. No API key required.",
        "tags": [
          "Service"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Metadata JSON.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "502": {
            "description": "Service unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/demo": {
      "get": {
        "operationId": "demoLookup",
        "summary": "Keyless demo lookup",
        "description": "IP-limited keyless demo for the public website.",
        "tags": [
          "Service"
        ],
        "security": [],
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "responses": {
          "200": {
            "description": "Demo result.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Bad request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "slow_down; see Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/demo/image": {
      "get": {
        "operationId": "demoImage",
        "summary": "Keyless demo image",
        "description": "Keyless privacy-area demo image.",
        "tags": [
          "Service"
        ],
        "security": [],
        "parameters": [
          {
            "name": "area",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "required": true,
            "description": "lat,lng"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "image/png": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "image/jpeg": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "image/webp": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "Bad request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "slow_down; see Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  }
}