openapi: "3.0.3"

info:
  title: LaTeXLite API
  version: "1.0.0"
  description: |
    REST API for rendering LaTeX templates to PDF and LaTeX math expressions to PNG.

    **Authentication:** All endpoints require `Authorization: Bearer <API_KEY>`.
    Get a free demo key at https://latexlite.com/get-demo-key.

    **Response format:** By default endpoints return binary output (PDF or PNG).
    Set `Accept: application/json` to receive a JSON wrapper containing base64-encoded output instead.

servers:
  - url: https://latexlite.com

security:
  - bearerAuth: []

paths:
  /v1/renders-sync:
    post:
      summary: Render LaTeX template to PDF
      description: |
        Compiles a LaTeX template and returns the resulting PDF.

        Supports three input formats via `Content-Type`:
        - `application/json` — inline template string with optional data injection via `[[.Field]]` placeholders
        - `text/plain` / `text/x-tex` / `application/x-tex` — raw self-contained `.tex` file (no data injection)
        - `multipart/form-data` — `.tex` file upload with optional JSON data injection

        Response format is controlled by the `Accept` header:
        - Default (`application/pdf`) — binary PDF bytes
        - `Accept: application/json` — JSON wrapper with base64-encoded PDF
      operationId: renderSync
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/RenderRequest"
          text/plain:
            schema:
              type: string
              format: binary
              description: Raw self-contained `.tex` file. No `[[.Field]]` placeholders supported.
          text/x-tex:
            schema:
              type: string
              format: binary
              description: Raw self-contained `.tex` file. No `[[.Field]]` placeholders supported.
          application/x-tex:
            schema:
              type: string
              format: binary
              description: Raw self-contained `.tex` file. No `[[.Field]]` placeholders supported.
          multipart/form-data:
            schema:
              $ref: "#/components/schemas/RenderMultipartRequest"
      responses:
        "200":
          description: Successful render
          headers:
            X-RateLimit-Limit:
              $ref: "#/components/headers/X-RateLimit-Limit"
            X-RateLimit-Remaining:
              $ref: "#/components/headers/X-RateLimit-Remaining"
            X-RateLimit-Reset:
              $ref: "#/components/headers/X-RateLimit-Reset"
          content:
            application/pdf:
              schema:
                type: string
                format: binary
                description: PDF binary bytes (default)
            application/json:
              schema:
                $ref: "#/components/schemas/RenderJSONResponse"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "408":
          $ref: "#/components/responses/Timeout"
        "422":
          $ref: "#/components/responses/UnprocessableEntity"
        "429":
          $ref: "#/components/responses/RateLimited"
        "502":
          $ref: "#/components/responses/BadGateway"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"

  /v1/math-sync:
    post:
      summary: Render LaTeX math expression to PNG
      description: |
        Compiles a LaTeX math expression and returns the result as a cropped PNG image.

        The `math` string must start and end with `$` (inline) or `$$` (display).

        Response format is controlled by the `Accept` header:
        - Default (`image/png`) — binary PNG bytes
        - `Accept: application/json` — JSON wrapper with base64-encoded PNG
      operationId: mathSync
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/MathRequest"
      responses:
        "200":
          description: Successful render
          headers:
            X-RateLimit-Limit:
              $ref: "#/components/headers/X-RateLimit-Limit"
            X-RateLimit-Remaining:
              $ref: "#/components/headers/X-RateLimit-Remaining"
            X-RateLimit-Reset:
              $ref: "#/components/headers/X-RateLimit-Reset"
          content:
            image/png:
              schema:
                type: string
                format: binary
                description: PNG binary bytes (default)
            application/json:
              schema:
                $ref: "#/components/schemas/MathJSONResponse"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "408":
          $ref: "#/components/responses/Timeout"
        "422":
          $ref: "#/components/responses/UnprocessableEntity"
        "429":
          $ref: "#/components/responses/RateLimited"
        "502":
          $ref: "#/components/responses/BadGateway"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"

components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: API Key

  headers:
    X-RateLimit-Limit:
      description: Maximum requests allowed per minute
      schema:
        type: integer
    X-RateLimit-Remaining:
      description: Requests remaining in the current window
      schema:
        type: integer
    X-RateLimit-Reset:
      description: Unix timestamp when the rate limit window resets
      schema:
        type: integer

  schemas:
    RenderRequest:
      type: object
      required:
        - template
      properties:
        template:
          type: string
          description: |
            LaTeX source. Use `[[.FieldName]]` placeholders for dynamic values.
            Uses Go `text/template` syntax with `[[ ]]` delimiters.
          example: "\\documentclass{article}\n\\begin{document}\nHello [[.Name]]!\n\\end{document}"
        data:
          type: object
          additionalProperties: true
          description: Key/value pairs injected into the template placeholders. Optional if no placeholders are used.
          example:
            Name: World

    RenderMultipartRequest:
      type: object
      required:
        - template
      properties:
        template:
          type: string
          format: binary
          description: The `.tex` file. May contain `[[.Field]]` placeholders if `data` is also provided.
        data:
          type: string
          description: JSON string of key/value pairs to inject into the template. Required if the template contains `[[.Field]]` placeholders.
          example: '{"Name":"World","Items":[{"Description":"Web Design","Qty":"1","Total":"£2,500"}]}'

    MathRequest:
      type: object
      required:
        - math
      properties:
        math:
          type: string
          description: |
            LaTeX math expression. Must start and end with `$` (inline) or `$$` (display).
          example: "$\\int_0^1 x^2 \\, dx = \\frac{1}{3}$"

    RenderJSONResponse:
      type: object
      properties:
        success:
          type: boolean
          example: true
        data:
          type: object
          properties:
            content_type:
              type: string
              example: application/pdf
            pdf_base64:
              type: string
              description: Base64-encoded PDF bytes
              example: "JVBERi0xLjQKJeLjz9MK..."

    MathJSONResponse:
      type: object
      properties:
        success:
          type: boolean
          example: true
        data:
          type: object
          properties:
            content_type:
              type: string
              example: image/png
            png_base64:
              type: string
              description: Base64-encoded PNG bytes
              example: "iVBORw0KGgoAAAANSUhEUgAA..."

    ErrorResponse:
      type: object
      properties:
        success:
          type: boolean
          example: false
        error:
          type: object
          properties:
            message:
              type: string
              description: Human-readable error description
              example: "LaTeX compilation failed: ! Undefined control sequence."
            line:
              type: integer
              description: Line number associated with the error, if available
              example: 0

  responses:
    BadRequest:
      description: Bad Request — invalid template, missing required field, or malformed input
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorResponse"
          examples:
            missingTemplate:
              value:
                success: false
                error:
                  message: "missing required field: template"
                  line: 0
            templateTooLarge:
              value:
                success: false
                error:
                  message: "template too large (max 200KB)"
                  line: 0
            mathFormat:
              value:
                success: false
                error:
                  message: "math must start and end with $ (or $$)"
                  line: 0

    Unauthorized:
      description: Unauthorized — missing or invalid API key
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorResponse"
          examples:
            missingHeader:
              value:
                success: false
                error:
                  message: "Missing or invalid Authorization header"
                  line: 0
            invalidKey:
              value:
                success: false
                error:
                  message: "Invalid API key"
                  line: 0

    Timeout:
      description: Request Timeout — render timed out (default limit ~8 seconds)
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorResponse"
          example:
            success: false
            error:
              message: "render timed out. Try optimizing your template."
              line: 0

    UnprocessableEntity:
      description: Unprocessable Entity — LaTeX compilation failed
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorResponse"
          example:
            success: false
            error:
              message: "LaTeX compilation failed: ! Undefined control sequence."
              line: 0

    RateLimited:
      description: Too Many Requests — rate limit exceeded
      headers:
        X-RateLimit-Limit:
          $ref: "#/components/headers/X-RateLimit-Limit"
        X-RateLimit-Remaining:
          $ref: "#/components/headers/X-RateLimit-Remaining"
        X-RateLimit-Reset:
          $ref: "#/components/headers/X-RateLimit-Reset"
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorResponse"
          examples:
            apiKeyLimit:
              value:
                success: false
                error:
                  message: "API key rate limit exceeded. Try again in 1 minute."
                  line: 0
            ipLimit:
              value:
                success: false
                error:
                  message: "IP rate limit exceeded. Maximum 50 requests per minute per IP."
                  line: 0

    BadGateway:
      description: Bad Gateway — renderer service error
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorResponse"

    ServiceUnavailable:
      description: Service Unavailable — renderer not configured
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorResponse"
          example:
            success: false
            error:
              message: "renderer not configured"
              line: 0