{
  "openapi": "3.1.1",
  "info": {
    "title": "Cartograph Map Poster (SVG + PDF from OpenStreetMap) API",
    "version": "1.0.0",
    "summary": "Turn an OpenStreetMap extract into a print-ready city map poster as SVG and vector PDF.",
    "description": "Every endpoint performs the same calculation as the human page and returns inputs, result, units, assumptions, sources, warnings and computedAt. MCP endpoint: /mcp."
  },
  "servers": [
    {
      "url": "https://cartographmapposter.usefulweb.app"
    }
  ],
  "paths": {
    "/api/v1/calculate": {
      "post": {
        "operationId": "calculate",
        "summary": "Turn an OpenStreetMap extract into a print-ready city map poster as SVG and vector PDF.",
        "description": "Draws a city map poster from your own OpenStreetMap extract (.osm XML, .osm.pbf or GeoJSON with OSM tags): roads by class, paths, railways, water, parks and woods, optional buildings, in one of six original colour styles, on A4–A2, 30 × 40, 50 × 70 or square paper, with a rectangular or round frame, title, subtitle, coordinates and the OpenStreetMap attribution. Returns a true-size SVG and a vector PDF. It is the poster engine of the Cartograph app.\n\nMethodology:\n- The extract is read locally: OSM XML (API 0.6), OSM PBF (zlib blocks, dense nodes, ways, multipolygon relations) or GeoJSON with OSM tags as properties. Nothing is downloaded from a map server.\n- Tags become layers: highway=* by class (motorway/trunk, primary, secondary/tertiary, streets, service/track, paths), railway=rail/light_rail/tram, waterway=river/canal/stream, natural=water and reservoirs (also multipolygons), parks/meadows/cemeteries and woods, building=*. Tunnels are left out.\n- Projection: Web Mercator around the centre, scaled so that the chosen half-width on the ground spans half of the frame. Every feature is clipped to the frame (Cyrus–Beck for lines, Sutherland–Hodgman for areas) and thinned to 0.04 mm, so the files carry only what is visible.\n- Line widths depend on the road class, the paper size, the area (wider areas get thinner lines) and the factor. Text uses Helvetica in the PDF; labels in other scripts are embedded as Noto subsets (Arabic shaping and Devanagari included).\n- Every poster carries “© OpenStreetMap contributors, ODbL”. Posters are Produced Works under the ODbL; the share-alike terms apply to databases, not to the printed map.",
        "tags": [
          "apps"
        ],
        "x-mcp-tool": "cartograph_map_poster",
        "x-owner-app": "cartograph",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CartographMapPosterInput"
              },
              "examples": {
                "example1": {
                  "summary": "Vaduz on A3 paper (built-in OpenStreetMap sample)",
                  "value": {
                    "center": "47.1393, 9.5215",
                    "radiusM": 1200,
                    "paper": "a3",
                    "style": "paper",
                    "title": "Vaduz",
                    "subtitle": "Liechtenstein"
                  }
                },
                "example2": {
                  "summary": "Round midnight poster with buildings, 30 × 30 cm",
                  "value": {
                    "center": "47.1393, 9.5215",
                    "radiusM": 1000,
                    "paper": "square",
                    "frame": "circle",
                    "style": "midnight",
                    "buildings": true,
                    "title": "Vaduz",
                    "subtitle": "Liechtenstein"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CartographMapPosterResult"
                }
              }
            }
          },
          "400": {
            "description": "Malformed JSON body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Invalid input (see errors[]).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (see Retry-After).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tool": {
      "get": {
        "operationId": "getToolDefinition",
        "summary": "Inputs, output schema and examples for this tool",
        "responses": {
          "200": {
            "description": "Tool definition.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Problem": {
        "type": "object",
        "description": "RFC 9457 problem details. 422 responses include per-field `errors`.",
        "required": [
          "type",
          "title",
          "status",
          "detail"
        ],
        "properties": {
          "type": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "integer"
          },
          "detail": {
            "type": "string"
          },
          "code": {
            "type": "string"
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "field",
                "message"
              ],
              "properties": {
                "field": {
                  "type": "string"
                },
                "message": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "CartographMapPosterInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "file": {
            "title": "OpenStreetMap extract (.osm, .osm.pbf or GeoJSON)",
            "description": "Up to 25 MB. Leave empty to use the built-in Vaduz sample. Download extracts from your own OpenStreetMap export, Geofabrik or BBBike; Cartograph never fetches map data itself. Upload as {filename, contentType?, contentBase64}. Max 24414 KiB. Accepts .osm,.pbf,.geojson,.json,application/xml,text/xml,application/geo+json,application/json,application/octet-stream.",
            "type": "object",
            "additionalProperties": false,
            "required": [
              "filename",
              "contentBase64"
            ],
            "properties": {
              "filename": {
                "type": "string"
              },
              "contentType": {
                "type": "string"
              },
              "contentBase64": {
                "type": "string"
              }
            }
          },
          "center": {
            "title": "Poster centre",
            "description": "Any coordinate format (decimal degrees, DMS, UTM, MGRS, plus code). Empty: the middle of the extract.",
            "type": "string",
            "default": ""
          },
          "radiusM": {
            "title": "Area half-width",
            "description": "Ground distance from the centre to the left and right edges of the map frame.",
            "type": "number",
            "minimum": 100,
            "maximum": 25000,
            "default": 1200,
            "x-unit": "m"
          },
          "paper": {
            "title": "Paper",
            "type": "string",
            "enum": [
              "a4",
              "a3",
              "a2",
              "30x40",
              "50x70",
              "letter",
              "square"
            ],
            "default": "a3"
          },
          "orientation": {
            "title": "Orientation",
            "type": "string",
            "enum": [
              "portrait",
              "landscape"
            ],
            "default": "portrait"
          },
          "frame": {
            "title": "Map frame",
            "type": "string",
            "enum": [
              "rect",
              "circle"
            ],
            "default": "rect"
          },
          "style": {
            "title": "Colour style",
            "type": "string",
            "enum": [
              "paper",
              "midnight",
              "blueprint",
              "terracotta",
              "mono",
              "forest"
            ],
            "default": "paper"
          },
          "paths": {
            "title": "Draw footpaths and cycleways",
            "type": "boolean",
            "default": true
          },
          "buildings": {
            "title": "Draw buildings",
            "type": "boolean",
            "default": false
          },
          "lineScale": {
            "title": "Line width factor",
            "type": "number",
            "minimum": 0.4,
            "maximum": 3,
            "default": 1
          },
          "title": {
            "title": "Title",
            "description": "Empty: the town name found in the extract.",
            "type": "string",
            "maxLength": 80,
            "default": ""
          },
          "subtitle": {
            "title": "Subtitle",
            "type": "string",
            "maxLength": 120,
            "default": ""
          },
          "showCoords": {
            "title": "Print the centre coordinates",
            "type": "boolean",
            "default": true
          }
        },
        "required": []
      },
      "CartographMapPosterResult": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "tool",
          "computedAt",
          "inputs",
          "summary",
          "result",
          "units",
          "assumptions",
          "sources",
          "warnings",
          "presentation",
          "links"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "const": "1.0"
          },
          "tool": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "name",
              "version"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "version": {
                "type": "string"
              }
            }
          },
          "computedAt": {
            "type": "string",
            "format": "date-time"
          },
          "inputs": {
            "type": "object",
            "description": "Normalised inputs actually used, including applied defaults."
          },
          "summary": {
            "type": "string"
          },
          "result": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "title",
              "paper",
              "orientation",
              "widthMm",
              "heightMm",
              "center",
              "radiusM",
              "scale",
              "groundWidthM",
              "groundHeightM",
              "features",
              "sample",
              "attribution",
              "svg",
              "pdf"
            ],
            "properties": {
              "title": {
                "type": "string"
              },
              "paper": {
                "type": "string"
              },
              "orientation": {
                "type": "string"
              },
              "widthMm": {
                "type": "number"
              },
              "heightMm": {
                "type": "number"
              },
              "center": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "lat",
                  "lon"
                ],
                "properties": {
                  "lat": {
                    "type": "number"
                  },
                  "lon": {
                    "type": "number"
                  }
                }
              },
              "radiusM": {
                "type": "number"
              },
              "scale": {
                "type": "integer",
                "description": "Paper scale 1 : n at the centre."
              },
              "groundWidthM": {
                "type": "number"
              },
              "groundHeightM": {
                "type": "number"
              },
              "features": {
                "type": "object",
                "additionalProperties": {
                  "type": "integer"
                },
                "description": "Features drawn per layer."
              },
              "sample": {
                "type": "boolean"
              },
              "attribution": {
                "type": "string"
              },
              "svg": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "artifactId",
                  "filename",
                  "mime",
                  "bytes",
                  "sha256",
                  "path"
                ],
                "properties": {
                  "artifactId": {
                    "type": "string"
                  },
                  "filename": {
                    "type": "string"
                  },
                  "mime": {
                    "type": "string"
                  },
                  "bytes": {
                    "type": "integer"
                  },
                  "sha256": {
                    "type": "string"
                  },
                  "path": {
                    "type": "string",
                    "description": "Download path on the same site (valid for about 2 hours)."
                  }
                }
              },
              "pdf": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "artifactId",
                  "filename",
                  "mime",
                  "bytes",
                  "sha256",
                  "path"
                ],
                "properties": {
                  "artifactId": {
                    "type": "string"
                  },
                  "filename": {
                    "type": "string"
                  },
                  "mime": {
                    "type": "string"
                  },
                  "bytes": {
                    "type": "integer"
                  },
                  "sha256": {
                    "type": "string"
                  },
                  "path": {
                    "type": "string",
                    "description": "Download path on the same site (valid for about 2 hours)."
                  }
                }
              }
            }
          },
          "units": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "assumptions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "title"
              ],
              "properties": {
                "title": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                },
                "publisher": {
                  "type": "string"
                },
                "retrievedAt": {
                  "type": "string"
                },
                "note": {
                  "type": "string"
                }
              }
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "presentation": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Display blocks used by the human page (same data)."
          },
          "links": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "human",
              "api",
              "openapi",
              "methodology"
            ],
            "properties": {
              "human": {
                "type": "string",
                "format": "uri"
              },
              "api": {
                "type": "string",
                "format": "uri"
              },
              "openapi": {
                "type": "string",
                "format": "uri"
              },
              "methodology": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      }
    }
  }
}