{
  "openapi": "3.1.1",
  "info": {
    "title": "SVG Optimizer API",
    "version": "1.0.0",
    "summary": "Shrink and sanitise SVG files: strip editor junk and scripts, round numbers, minify paths.",
    "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://svgoptimizer.usefulweb.site"
    }
  ],
  "paths": {
    "/api/v1/calculate": {
      "post": {
        "operationId": "calculate",
        "summary": "Shrink and sanitise SVG files: strip editor junk and scripts, round numbers, minify paths.",
        "description": "Optimises an SVG file in your choice of steps and shows how many bytes each one saved: removes comments, metadata and Inkscape/Illustrator editor data, hidden and empty elements, rounds numbers, rewrites path data in its shortest form and collapses whitespace. It also removes scripts, event handlers and external references, so the result is safe to embed.\n\nMethodology:\n- The SVG is parsed by a strict built-in XML parser (no external entities; internal DOCTYPE entities are expanded once with a size cap, which blocks \"billion laughs\" files). The document is re-serialised after every step, and the byte count before/after each step is reported.\n- Security (always on): removes <script>, <foreignObject>, <iframe>/<embed>/<object>, all on* event handlers, javascript: links, xml:base, CSS @import and url() references to other files, external href on <use>/<image>/<feImage> (raster data: URIs are kept), and animations that change href or event attributes. Links in <a> may point to http(s) or mailto only.\n- Clean-up: comments, XML declaration, DOCTYPE and processing instructions; <metadata>, RDF and editor namespaces (Inkscape, Sodipodi, Illustrator, Sketch, Serif, Figma); elements with display:none that nothing references; unreferenced children of <defs>; empty groups, and groups without attributes are unwrapped; unused namespace declarations, version and baseProfile.\n- Numbers in geometry attributes are rounded to the chosen decimal places (transforms to two more) with leading zeros dropped. Path data is re-written per segment in whichever of absolute or relative form is shorter, lines become H/V where possible, repeated command letters are omitted, and relative values are computed from the rounded current point so errors do not accumulate.\n- Whitespace between elements is removed except inside text elements and xml:space=\"preserve\". Removing width/height keeps (or creates) the viewBox so the graphic still scales.\n- The optimised SVG is offered as a download (served as an attachment, never rendered on this site).\n\nCheck the optimised file visually: very low precision can shift shapes, and removing width/height changes how some programs size the image.",
        "tags": [
          "media"
        ],
        "x-mcp-tool": "svg_optimizer",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SvgOptimizerInput"
              },
              "examples": {
                "example1": {
                  "summary": "Inkscape export with a script",
                  "value": {
                    "svgText": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<!-- Created with Inkscape (http://www.inkscape.org/) -->\n<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" xmlns:sodipodi=\"http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd\" width=\"120.000000\" height=\"80.000000\" viewBox=\"0 0 120 80\" version=\"1.1\" onload=\"alert('hi')\">\n  <sodipodi:namedview id=\"namedview1\" pagecolor=\"#ffffff\" inkscape:zoom=\"2.0\"/>\n  <metadata id=\"metadata1\"><rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"/></metadata>\n  <script>alert('x')</script>\n  <g inkscape:label=\"Layer 1\" inkscape:groupmode=\"layer\" id=\"layer1\">\n    <rect x=\"10.0000001\" y=\"10.123456\" width=\"40.000000\" height=\"30.000000\" fill=\"#1652f0\" />\n    <path d=\"M 60.000000 10.000000 L 110.000000 10.000000 L 110.000000 40.000000 L 60.000000 40.000000 Z\" fill=\"#f0a500\" />\n    <circle cx=\"35.555555\" cy=\"60.444444\" r=\"12.0000\" fill=\"#0f8a5f\" style=\"display:none\" />\n    <g></g>\n  </g>\n</svg>\n",
                    "precision": 2
                  }
                },
                "example2": {
                  "summary": "Responsive icon (width/height removed)",
                  "value": {
                    "svgText": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\"><path d=\"M 2.0000 12.0000 L 12.0000 2.0000 L 22.0000 12.0000 L 12.0000 22.0000 Z\" fill=\"currentColor\"/></svg>",
                    "precision": 1,
                    "removeDimensions": true
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SvgOptimizerResult"
                }
              }
            }
          },
          "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"
                }
              }
            }
          }
        }
      },
      "SvgOptimizerInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "svgFile": {
            "title": "SVG file",
            "description": "An .svg or .svgz file, max 5 MB. Alternatively paste the SVG code below. Upload as {filename, contentType?, contentBase64}. Max 5120 KiB. Accepts .svg,.svgz,image/svg+xml.",
            "type": "object",
            "additionalProperties": false,
            "required": [
              "filename",
              "contentBase64"
            ],
            "properties": {
              "filename": {
                "type": "string"
              },
              "contentType": {
                "type": "string"
              },
              "contentBase64": {
                "type": "string"
              }
            }
          },
          "svgText": {
            "title": "Or paste SVG code",
            "type": "string",
            "maxLength": 2000000
          },
          "precision": {
            "title": "Decimal places",
            "description": "Coordinates and lengths are rounded to this many decimals. 1–3 is usually invisible; transforms keep two more.",
            "type": "integer",
            "minimum": 0,
            "maximum": 8,
            "default": 3
          },
          "minifyPaths": {
            "title": "Minify path data (shortest relative/absolute commands)",
            "type": "boolean",
            "default": true
          },
          "removeHidden": {
            "title": "Remove hidden elements and unused definitions",
            "type": "boolean",
            "default": true
          },
          "removeDimensions": {
            "title": "Remove width/height (keep viewBox so the SVG scales responsively)",
            "type": "boolean",
            "default": false
          }
        },
        "required": []
      },
      "SvgOptimizerResult": {
        "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": [
              "bytesBefore",
              "bytesAfter",
              "savingsPercent",
              "gzipBefore",
              "gzipAfter",
              "elementsBefore",
              "elementsAfter",
              "precision",
              "steps",
              "securityFindings",
              "hasViewBox",
              "artifact"
            ],
            "properties": {
              "bytesBefore": {
                "type": "integer"
              },
              "bytesAfter": {
                "type": "integer"
              },
              "savingsPercent": {
                "type": "number"
              },
              "gzipBefore": {
                "type": "integer",
                "description": "Size after gzip -9, as most web servers deliver SVG."
              },
              "gzipAfter": {
                "type": "integer"
              },
              "elementsBefore": {
                "type": "integer"
              },
              "elementsAfter": {
                "type": "integer"
              },
              "precision": {
                "type": "integer"
              },
              "hasViewBox": {
                "type": "boolean"
              },
              "steps": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "id",
                    "label",
                    "bytesBefore",
                    "bytesAfter",
                    "changes"
                  ],
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "label": {
                      "type": "string"
                    },
                    "bytesBefore": {
                      "type": "integer"
                    },
                    "bytesAfter": {
                      "type": "integer"
                    },
                    "changes": {
                      "type": "integer"
                    }
                  }
                }
              },
              "securityFindings": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "kind",
                    "detail"
                  ],
                  "properties": {
                    "kind": {
                      "type": "string"
                    },
                    "detail": {
                      "type": "string"
                    }
                  }
                }
              },
              "artifact": {
                "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"
              }
            }
          }
        }
      }
    }
  }
}