{
  "openapi": "3.1.0",
  "info": {
    "title": "WordCloud Generator API",
    "description": "Generate word clouds programmatically. Returns URLs to view, edit, and embed word clouds on word-cloud.net.\n\n**Data Use:** By using this API, you are sending data to word-cloud.net servers. We do not log, store, or record any request data. All data is used transiently and solely for the purpose of generating the requested image, after which it is immediately discarded.",
    "version": "1.1.0",
    "contact": {
      "name": "Seth Osher",
      "url": "https://word-cloud.net"
    }
  },
  "servers": [
    {
      "url": "https://word-cloud.net",
      "description": "Production"
    }
  ],
  "paths": {
    "/api/generate/svg": {
      "post": {
        "operationId": "generate_wordcloud_svg",
        "summary": "Generate a word cloud as SVG image",
        "description": "Renders a word cloud server-side and returns an SVG image. Rate limited to 1 request per second.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GenerateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "SVG image",
            "content": {
              "image/svg+xml": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/generate/image": {
      "post": {
        "operationId": "generate_wordcloud_image",
        "summary": "Generate a word cloud as a raster image",
        "description": "Renders a word cloud server-side and returns a WebP image. Also available at /api/generate/png for backwards compatibility. Rate limited to 1 request per second.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GenerateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "WebP image",
            "content": {
              "image/webp": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/generate": {
      "post": {
        "operationId": "generate_wordcloud",
        "summary": "Generate a word cloud",
        "description": "Accepts a list of weighted words and optional styling parameters. Returns URLs to view, edit, and embed the resulting word cloud. Rate limited to 1 request per second.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GenerateRequest"
              },
              "example": {
                "words": [
                  { "text": "Hello", "weight": 10 },
                  { "text": "World", "weight": 5 },
                  { "text": "Cloud", "weight": 8 },
                  { "text": "Generate", "weight": 3 }
                ],
                "shape": "landscape",
                "colorPalette": "ocean",
                "mask": "circle"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Word cloud generated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GenerateResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "WordEntry": {
        "type": "object",
        "required": ["text", "weight"],
        "properties": {
          "text": {
            "type": "string",
            "description": "The word or phrase to display"
          },
          "weight": {
            "type": "number",
            "description": "Relative size weight (higher = larger)"
          }
        }
      },
      "GenerateRequest": {
        "type": "object",
        "required": ["words"],
        "properties": {
          "words": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WordEntry"
            },
            "description": "Array of words with their weights",
            "minItems": 1
          },
          "shape": {
            "type": "string",
            "enum": ["landscape", "portrait", "square"],
            "default": "landscape",
            "description": "Canvas shape"
          },
          "rotation": {
            "type": "string",
            "enum": ["horizontal", "horizontal-vertical", "all"],
            "default": "horizontal-vertical",
            "description": "Word rotation style"
          },
          "font": {
            "type": "string",
            "default": "Impact",
            "description": "Font family name. Built-in fonts: Arial, Audiowide, Bangers, Black Ops One, Bungee, Caveat, Chewy, Comic Sans MS, Courier New, Creepster, Dancing Script, Fredoka One, Georgia, Great Vibes, Impact, Lobster, Luckiest Guy, MedievalSharp, Montserrat, Nosifer, Open Sans, Orbitron, Oswald, Pacifico, Passion One, Permanent Marker, Righteous, Roboto, Russo One, Satisfy, UnifrakturMaguntia. Any Google Font can also be used with googleFontsUrl."
          },
          "bold": {
            "type": "boolean",
            "default": false,
            "description": "Use bold font weight"
          },
          "colorPalette": {
            "type": "string",
            "enum": ["rainbow", "ocean", "warm", "forest", "sunset"],
            "default": "rainbow",
            "description": "Preset color palette"
          },
          "colorMode": {
            "type": "string",
            "enum": ["bw", "white", "palette"],
            "default": "palette",
            "description": "Color mode"
          },
          "customColors": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "default": [],
            "description": "Custom hex color values (e.g. [\"#ff0000\", \"#00ff00\"])"
          },
          "googleFontsUrl": {
            "type": "string",
            "nullable": true,
            "default": null,
            "description": "Google Fonts CSS URL for custom fonts (e.g. https://fonts.googleapis.com/css2?family=Lobster&display=swap)"
          },
          "backgroundPreset": {
            "type": "string",
            "enum": ["None", "Black", "White", "Aurora", "Chalkboard", "Circuit Board", "Night Sky", "Ocean Gradient", "Parchment", "Speech Bubble", "Sunset Gradient"],
            "default": "None",
            "description": "Built-in background image preset. Mutually exclusive with backgroundColor and gradient."
          },
          "backgroundColor": {
            "type": "string",
            "nullable": true,
            "default": null,
            "description": "Solid background hex color (null for transparent). Mutually exclusive with gradient and backgroundPreset."
          },
          "gradient": {
            "$ref": "#/components/schemas/Gradient"
          },
          "backgroundUrl": {
            "type": "string",
            "nullable": true,
            "default": null,
            "description": "URL to a background image (PNG, JPEG, WebP, GIF)"
          },
          "mask": {
            "type": "string",
            "enum": ["none", "box", "circle", "heart", "star", "diamond", "speech-bubble", "triangle", "cloud", "shield", "pentagon", "hexagon"],
            "default": "none",
            "description": "Shape mask preset to constrain word placement"
          },
          "maskUrl": {
            "type": "string",
            "nullable": true,
            "default": null,
            "description": "URL to a custom mask image. Black areas define where words are placed."
          }
        }
      },
      "GenerateResponse": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "description": "URL to view and edit the word cloud in the interactive editor"
          },
          "embedUrl": {
            "type": "string",
            "description": "URL for embedding the word cloud (read-only view)"
          },
          "embedHtml": {
            "type": "string",
            "description": "Ready-to-use HTML iframe snippet for embedding"
          }
        }
      },
      "Gradient": {
        "type": "object",
        "description": "Background gradient. Mutually exclusive with backgroundColor.",
        "properties": {
          "type": {
            "type": "string",
            "enum": ["linear", "radial"],
            "default": "linear",
            "description": "Gradient type"
          },
          "direction": {
            "type": "string",
            "enum": ["to-bottom", "to-right", "to-bottom-right", "to-top-right"],
            "default": "to-bottom",
            "description": "Gradient direction (linear gradients only)"
          },
          "stops": {
            "type": "array",
            "minItems": 2,
            "description": "Color stops with hex color and offset (0-100)",
            "items": {
              "type": "object",
              "required": ["color", "offset"],
              "properties": {
                "color": {
                  "type": "string",
                  "description": "Hex color (e.g. #3498db)"
                },
                "offset": {
                  "type": "integer",
                  "description": "Position from 0 to 100"
                }
              }
            }
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string",
            "description": "Error message"
          }
        }
      }
    }
  }
}
