{
  "openapi": "3.0.3",
  "info": {
    "title": "CountertopSwap API",
    "version": "1.1.0",
    "description": "Programmatic access to CountertopSwap's AI countertop visualizer. Send a photo of a kitchen or bathroom and a material description, and receive a photorealistic preview with the countertop, island, and backsplash replaced. Designed for AI agents, contractor sales tools, interior design assistants, and renovation planning workflows. Authentication via x-api-key header. 1 credit per successful render; failed renders auto-refund.",
    "contact": {
      "name": "CountertopSwap",
      "url": "https://www.countertopswap.com/contact"
    }
  },
  "servers": [
    {
      "url": "https://urbdulnhxberioelwleo.supabase.co/functions/v1",
      "description": "Production API"
    }
  ],
  "security": [{ "ApiKeyAuth": [] }],
  "paths": {
    "/health": {
      "get": {
        "operationId": "getHealth",
        "summary": "Service health check",
        "description": "Returns service status. No authentication required. Useful for agent frameworks verifying the API is reachable before issuing render calls.",
        "tags": ["status"],
        "security": [],
        "responses": {
          "200": {
            "description": "Service is up",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["status", "service"],
                  "properties": {
                    "status": { "type": "string", "example": "ok" },
                    "service": { "type": "string", "example": "CountertopSwap Render API" },
                    "version": { "type": "string" },
                    "timestamp": { "type": "string", "format": "date-time" },
                    "endpoints": {
                      "type": "object",
                      "additionalProperties": { "type": "string" }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/render-api": {
      "post": {
        "operationId": "renderCountertop",
        "summary": "Render a countertop preview",
        "description": "Replaces the countertop (and matching backsplash) in the provided kitchen or bathroom image with the specified material. Returns a hosted PNG URL. Requires a valid API key in the x-api-key header. Each successful render consumes 1 credit from the key owner's balance. Rate-limited to 30 requests / key / hour.",
        "tags": ["render"],
        "security": [{ "ApiKeyAuth": [] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/RenderRequest" },
              "examples": {
                "url": {
                  "summary": "Calacatta quartz from a public image URL",
                  "value": {
                    "image_url": "https://example.com/my-kitchen.jpg",
                    "material": "calacatta quartz with soft gold veining"
                  }
                },
                "base64": {
                  "summary": "Absolute black granite via base64",
                  "value": {
                    "image_base64": "data:image/jpeg;base64,/9j/4AAQSkZJRg...",
                    "material": "absolute black granite, polished finish"
                  }
                }
              }
            },
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": ["image", "material"],
                "properties": {
                  "image": {
                    "type": "string",
                    "format": "binary",
                    "description": "Kitchen or bathroom photo (JPEG or PNG, max 12MB)."
                  },
                  "material": {
                    "type": "string",
                    "description": "Plain-English material description.",
                    "minLength": 2,
                    "maxLength": 300
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Rendered image URL",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RenderResponse" } } }
          },
          "400": {
            "description": "Invalid input (invalid_image, invalid_material, unsupported_material, invalid_body)",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiError" } } }
          },
          "401": {
            "description": "Missing or invalid API key (missing_api_key, invalid_api_key)",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiError" } } }
          },
          "402": {
            "description": "Insufficient credits — top up at /billing",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiError" } } }
          },
          "429": {
            "description": "Rate limit exceeded (30 / hour / key)",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiError" } } }
          },
          "502": {
            "description": "Upstream render failed; credit auto-refunded",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiError" } } }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "x-api-key",
        "description": "CountertopSwap API key. Create one at https://www.countertopswap.com/api-keys"
      }
    },
    "schemas": {
      "RenderRequest": {
        "type": "object",
        "required": ["material"],
        "properties": {
          "image_url": {
            "type": "string",
            "format": "uri",
            "description": "Publicly reachable https URL of a kitchen or bathroom photo (JPEG/PNG, max 12MB). Provide either image_url OR image_base64."
          },
          "image_base64": {
            "type": "string",
            "description": "Base64-encoded image, with or without a data URI prefix. Max ~12MB decoded."
          },
          "material": {
            "type": "string",
            "minLength": 2,
            "maxLength": 300,
            "description": "Plain-English material description, e.g. 'calacatta quartz', 'absolute black granite'. Must reference a supported stone type."
          }
        }
      },
      "RenderResponse": {
        "type": "object",
        "required": ["result_url", "credits_used"],
        "properties": {
          "result_url": { "type": "string", "format": "uri", "description": "Public PNG URL." },
          "material": { "type": "string", "description": "Echoed material label." },
          "credits_used": { "type": "integer", "description": "Always 1 on success." },
          "render_id": { "type": "string", "format": "uuid" }
        }
      },
      "ApiError": {
        "type": "object",
        "required": ["error"],
        "properties": {
          "error": {
            "type": "string",
            "description": "Stable machine-readable error code.",
            "enum": [
              "missing_api_key",
              "invalid_api_key",
              "insufficient_credits",
              "invalid_image",
              "invalid_material",
              "unsupported_material",
              "invalid_body",
              "rate_limit_exceeded",
              "render_failed",
              "upstream_rate_limit",
              "method_not_allowed",
              "server_misconfigured"
            ]
          },
          "message": { "type": "string", "description": "Human-readable explanation." },
          "supported": {
            "type": "array",
            "items": { "type": "string" },
            "description": "Present on unsupported_material; lists allowed material types."
          }
        }
      }
    }
  }
}
