{
  "openapi" : "3.1.0",
  "components" : {
    "schemas" : {
      "GenerateImageRequest" : {
        "description" : "Request to generate an image from a template with variable substitution",
        "type" : "object",
        "required" : [ "variables" ],
        "properties" : {
          "variables" : {
            "type" : "object",
            "additionalProperties" : {
              "type" : "string"
            },
            "description" : "Map of variable names to values",
            "examples" : [ {
              "customer_name" : "John Doe",
              "discount_code" : "SAVE20"
            } ]
          },
          "format" : {
            "type" : "string",
            "description" : "Output image format",
            "examples" : [ "png" ],
            "enum" : [ "png", "jpeg", "webp", "pdf" ],
            "pattern" : "^(png|jpeg|webp|pdf)$"
          },
          "options" : {
            "$ref" : "#/components/schemas/RenderOptions"
          },
          "formatOrDefault" : {
            "type" : "string"
          }
        }
      },
      "OffsetDateTime" : {
        "type" : "string",
        "format" : "date-time",
        "examples" : [ "2022-03-10T12:15:50-04:00" ]
      },
      "OutputDpi" : {
        "type" : "integer",
        "format" : "int32",
        "enum" : [ 96, 150, 300 ]
      },
      "ProjectListItem" : {
        "type" : "object",
        "properties" : {
          "id" : {
            "$ref" : "#/components/schemas/UUID"
          },
          "name" : {
            "type" : "string"
          },
          "description" : {
            "type" : "string"
          },
          "templateCount" : {
            "type" : "integer",
            "format" : "int32"
          },
          "visibility" : {
            "type" : "string"
          },
          "updatedAt" : {
            "$ref" : "#/components/schemas/OffsetDateTime"
          }
        }
      },
      "RenderOptions" : {
        "description" : "Options controlling output quality, resolution, and appearance. Specify EITHER outputDpi (print DPI tiers) OR scale (screen pixel multiplication), not both; when both are provided, outputDpi takes priority. When neither is provided, renders default to the design's stored export DPI for print-intent designs, to 300 DPI for PDF output, and to 1x for screen designs otherwise.",
        "type" : "object",
        "properties" : {
          "outputDpi" : {
            "description" : "DPI tier for output image (SCREEN=96, DRAFT=150, PRINT=300). Takes priority over scale when both are set.",
            "type" : "string",
            "$ref" : "#/components/schemas/OutputDpi"
          },
          "scale" : {
            "type" : "integer",
            "format" : "int32",
            "maximum" : 4,
            "minimum" : 1,
            "description" : "Integer scale multiplier for output image"
          },
          "quality" : {
            "type" : "integer",
            "format" : "int32",
            "maximum" : 100,
            "minimum" : 1,
            "description" : "Quality for JPEG/WebP output"
          },
          "backgroundColor" : {
            "type" : "string",
            "description" : "Background color override in hex format"
          }
        }
      },
      "TemplateDetailResponse" : {
        "description" : "Template detail with metadata and variable definitions",
        "type" : "object",
        "properties" : {
          "id" : {
            "description" : "Unique template identifier",
            "type" : "string",
            "examples" : [ "019463b8-1234-7890-abcd-ef1234567890" ],
            "$ref" : "#/components/schemas/UUID"
          },
          "name" : {
            "type" : "string",
            "description" : "Template name",
            "examples" : [ "Summer Sale Coupon" ]
          },
          "description" : {
            "type" : "string",
            "description" : "Optional template description",
            "examples" : [ "20% off coupon for summer sale campaign" ]
          },
          "projectId" : {
            "description" : "Project ID this template belongs to",
            "type" : "string",
            "examples" : [ "019463b8-abcd-7890-1234-ef1234567890" ],
            "$ref" : "#/components/schemas/UUID"
          },
          "viewport" : {
            "$ref" : "#/components/schemas/ViewportInfo"
          },
          "viewportUnit" : {
            "type" : "string",
            "description" : "Viewport dimension unit",
            "examples" : [ "px" ]
          },
          "viewportExportDpi" : {
            "type" : "integer",
            "format" : "int32",
            "description" : "Export DPI for raster output",
            "examples" : [ 96 ]
          },
          "viewportOutputIntent" : {
            "type" : "string",
            "description" : "Output intent for PDF/print workflows",
            "examples" : [ "screen" ]
          },
          "visibility" : {
            "type" : "string",
            "description" : "Template visibility",
            "examples" : [ "SHARED" ],
            "enum" : [ "PRIVATE", "SHARED" ]
          },
          "createdAt" : {
            "$ref" : "#/components/schemas/OffsetDateTime"
          },
          "updatedAt" : {
            "$ref" : "#/components/schemas/OffsetDateTime"
          },
          "variables" : {
            "type" : "array",
            "items" : {
              "$ref" : "#/components/schemas/VariableInfo"
            }
          }
        }
      },
      "TemplateListItem" : {
        "type" : "object",
        "properties" : {
          "id" : {
            "$ref" : "#/components/schemas/UUID"
          },
          "name" : {
            "type" : "string"
          },
          "description" : {
            "type" : "string"
          },
          "projectId" : {
            "$ref" : "#/components/schemas/UUID"
          },
          "updatedAt" : {
            "$ref" : "#/components/schemas/OffsetDateTime"
          },
          "visibility" : {
            "type" : "string"
          }
        }
      },
      "UUID" : {
        "type" : "string",
        "format" : "uuid",
        "pattern" : "[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}"
      },
      "VariableInfo" : {
        "type" : "object",
        "description" : "Variable definition for template substitution",
        "properties" : {
          "name" : {
            "type" : "string",
            "description" : "Variable name (use as key in variables map)",
            "examples" : [ "customer_name" ]
          },
          "type" : {
            "type" : "string",
            "description" : "Variable type",
            "examples" : [ "text" ],
            "enum" : [ "text", "number", "email", "url", "phone", "date", "qrcode", "barcode", "image" ]
          },
          "label" : {
            "type" : "string",
            "description" : "Human-readable label",
            "examples" : [ "Customer Name" ]
          },
          "required" : {
            "type" : "boolean",
            "description" : "Whether this variable is required",
            "examples" : [ true ]
          },
          "defaultValue" : {
            "type" : "string",
            "description" : "Default value if not provided",
            "examples" : [ "John Doe" ]
          },
          "validation" : {
            "$ref" : "#/components/schemas/VariableValidationInfo"
          }
        }
      },
      "VariableValidationInfo" : {
        "type" : "object",
        "properties" : {
          "minLength" : {
            "type" : "integer",
            "format" : "int32"
          },
          "maxLength" : {
            "type" : "integer",
            "format" : "int32"
          },
          "pattern" : {
            "type" : "string"
          },
          "min" : {
            "type" : "number",
            "format" : "double"
          },
          "max" : {
            "type" : "number",
            "format" : "double"
          },
          "options" : {
            "type" : "array",
            "items" : {
              "type" : "string"
            }
          }
        }
      },
      "ViewportInfo" : {
        "type" : "object",
        "properties" : {
          "width" : {
            "type" : "integer",
            "format" : "int32"
          },
          "height" : {
            "type" : "integer",
            "format" : "int32"
          }
        }
      }
    },
    "securitySchemes" : {
      "apiKey" : {
        "type" : "apiKey",
        "description" : "API key for authentication. Contact admin for access.",
        "name" : "X-Api-Key",
        "in" : "header"
      }
    }
  },
  "paths" : {
    "/api/v1/projects" : {
      "get" : {
        "summary" : "List projects",
        "description" : "Returns a paginated list of projects visible to the API key owner: own projects (PRIVATE or SHARED) plus projects shared by other org members. Each item includes a visibility field indicating PRIVATE or SHARED.",
        "tags" : [ "Public API" ],
        "parameters" : [ {
          "description" : "Number of items per page (max 100)",
          "example" : 20,
          "name" : "limit",
          "in" : "query",
          "schema" : {
            "type" : "integer",
            "format" : "int32",
            "default" : 20
          }
        }, {
          "description" : "Page number (0-based)",
          "example" : 0,
          "name" : "page",
          "in" : "query",
          "schema" : {
            "type" : "integer",
            "format" : "int32",
            "default" : 0
          }
        } ],
        "responses" : {
          "200" : {
            "description" : "Project list retrieved successfully",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ProjectListItem"
                }
              }
            }
          },
          "401" : {
            "description" : "Missing or invalid API key",
            "content" : {
              "application/json" : { }
            }
          }
        },
        "security" : [ {
          "apiKey" : [ ]
        } ]
      }
    },
    "/api/v1/projects/{projectId}/templates" : {
      "get" : {
        "summary" : "List templates in a project",
        "description" : "Returns a paginated list of templates in the given project that are visible to the API key owner: own templates (PRIVATE or SHARED) plus templates shared by other org members. Does not include full canvas data.",
        "tags" : [ "Public API" ],
        "parameters" : [ {
          "description" : "Project ID",
          "required" : true,
          "name" : "projectId",
          "in" : "path",
          "schema" : {
            "$ref" : "#/components/schemas/UUID"
          }
        }, {
          "description" : "Number of items per page (max 100)",
          "example" : 20,
          "name" : "limit",
          "in" : "query",
          "schema" : {
            "type" : "integer",
            "format" : "int32",
            "default" : 20
          }
        }, {
          "description" : "Page number (0-based)",
          "example" : 0,
          "name" : "page",
          "in" : "query",
          "schema" : {
            "type" : "integer",
            "format" : "int32",
            "default" : 0
          }
        } ],
        "responses" : {
          "200" : {
            "description" : "Template list retrieved successfully",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/TemplateListItem"
                }
              }
            }
          },
          "401" : {
            "description" : "Missing or invalid API key",
            "content" : {
              "application/json" : { }
            }
          }
        },
        "security" : [ {
          "apiKey" : [ ]
        } ]
      }
    },
    "/api/v1/templates/{templateId}" : {
      "get" : {
        "summary" : "Get template detail",
        "description" : "Returns full template metadata including name, description, project, viewport dimensions, and all available variables with their types, labels, default values, and validation rules. The template owner can access PRIVATE templates; other org members can only access SHARED ones. Use this endpoint to discover what variables can be substituted when generating images.",
        "tags" : [ "Public API" ],
        "parameters" : [ {
          "description" : "Template ID",
          "required" : true,
          "name" : "templateId",
          "in" : "path",
          "schema" : {
            "$ref" : "#/components/schemas/UUID"
          }
        } ],
        "responses" : {
          "200" : {
            "description" : "Template detail retrieved successfully",
            "headers" : {
              "ETag" : {
                "description" : "Entity tag for conditional requests (based on updatedAt)"
              },
              "Cache-Control" : {
                "description" : "private, max-age=60"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/TemplateDetailResponse"
                }
              }
            }
          },
          "401" : {
            "description" : "Missing or invalid API key",
            "content" : {
              "application/json" : { }
            }
          },
          "404" : {
            "description" : "Template not found or not accessible",
            "content" : {
              "application/json" : { }
            }
          }
        },
        "security" : [ {
          "apiKey" : [ ]
        } ]
      }
    },
    "/api/v1/templates/{templateId}/generate" : {
      "post" : {
        "summary" : "Generate image from template",
        "description" : "Generates an image from a template with variable substitution. Provide variable values as a key-value map. Variable names must match those returned by the GET /{templateId} endpoint. Returns binary image data. Resolution defaults: when options contain neither outputDpi nor scale, templates with outputIntent 'print' render at their stored export DPI (viewportExportDpi from the GET /{templateId} endpoint), PDF output defaults to 300 DPI, and 'screen' templates render at 1x (96 DPI) otherwise. Set outputDpi or scale explicitly to override; if both are provided, outputDpi wins.",
        "tags" : [ "Public API" ],
        "parameters" : [ {
          "description" : "Template ID",
          "required" : true,
          "name" : "templateId",
          "in" : "path",
          "schema" : {
            "$ref" : "#/components/schemas/UUID"
          }
        } ],
        "requestBody" : {
          "description" : "Generation request with variables and optional render settings",
          "content" : {
            "application/json" : {
              "schema" : {
                "$ref" : "#/components/schemas/GenerateImageRequest"
              }
            }
          },
          "required" : true
        },
        "responses" : {
          "200" : {
            "description" : "Image generated successfully",
            "headers" : {
              "X-Request-Id" : {
                "description" : "Unique identifier for this request"
              },
              "X-Template-Id" : {
                "description" : "Template ID used for rendering"
              },
              "X-Quota-Limit" : {
                "description" : "Monthly API quota ceiling for the organisation"
              },
              "X-Quota-Remaining" : {
                "description" : "Remaining renders this billing period"
              },
              "X-Quota-Reset" : {
                "description" : "ISO 8601 UTC datetime when the quota resets"
              }
            },
            "content" : {
              "image/png" : { },
              "image/jpeg" : { },
              "image/webp" : { },
              "application/pdf" : { }
            }
          },
          "400" : {
            "description" : "Variable validation error — missing required variables or validation rules failed",
            "content" : {
              "application/json" : { }
            }
          },
          "401" : {
            "description" : "Missing or invalid API key",
            "content" : {
              "application/json" : { }
            }
          },
          "404" : {
            "description" : "Template not found",
            "content" : {
              "application/json" : { }
            }
          },
          "429" : {
            "description" : "Monthly quota exceeded — retry after the indicated seconds",
            "headers" : {
              "Retry-After" : {
                "description" : "Seconds until quota resets at start of next month"
              },
              "X-RateLimit-Remaining" : {
                "description" : "Always 0 when quota is exceeded"
              }
            },
            "content" : {
              "application/problem+json" : { }
            }
          },
          "502" : {
            "description" : "Image generator service error",
            "content" : {
              "application/json" : { }
            }
          },
          "503" : {
            "description" : "Image generator service unavailable",
            "content" : {
              "application/json" : { }
            }
          }
        },
        "security" : [ {
          "apiKey" : [ ]
        } ]
      }
    }
  },
  "tags" : [ {
    "name" : "Public API",
    "description" : "Public API for template description and image generation (requires API key)"
  } ],
  "info" : {
    "title" : "Zandovi API",
    "version" : "1.0.0",
    "description" : "API for template management and image rendering",
    "contact" : {
      "name" : "Zandovi Team"
    }
  },
  "servers" : [ {
    "url" : "https://app.zandovi.com",
    "description" : "Zandovi public API"
  } ]
}