{
  "openapi": "3.1.0",
  "info": {
    "title": "UIRender API",
    "version": "1.0.0",
    "description": "Deterministic online website cloner API that turns any public URL into clean, production-ready Next.js 15 and React codebases with 100% local assets and Tailwind CSS v4.",
    "contact": {
      "name": "UIRender Support",
      "email": "hey@uirender.com",
      "url": "https://uirender.com/contact"
    },
    "x-api-versioning": {
      "strategy": "url-path-and-header",
      "currentVersion": "v1",
      "supportedVersions": ["v1"],
      "urlPathPrefix": "/v1",
      "versionHeader": "X-API-Version",
      "currentVersionHeaderValue": "1.0.0",
      "deprecationPolicy": {
        "noticePeriod": "6 months minimum advance notice",
        "deprecationHeader": "Deprecation (RFC 8594)",
        "sunsetHeader": "Sunset (RFC 8594)",
        "policyUrl": "https://uirender.com/docs#versioning-policy",
        "communicationChannels": [
          "HTTP Deprecation and Sunset response headers",
          "Email notifications to registered API key accounts",
          "Developer documentation changelog at https://uirender.com/docs"
        ]
      }
    }
  },
  "servers": [
    {
      "url": "https://uirender.com",
      "description": "Production Server (Default)"
    },
    {
      "url": "https://uirender.com/v1",
      "description": "Production Server (v1 API)"
    }
  ],
  "paths": {
    "/api/clones": {
      "post": {
        "summary": "Create website clone job",
        "description": "Submits a public website URL to be cloned into a Next.js 15 App Router or Vite React repository.",
        "operationId": "createClone",
        "parameters": [
          { "$ref": "#/components/parameters/ApiVersionHeader" }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateCloneRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Clone job successfully queued or started",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CloneJobResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request — Invalid URL or input parameters",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } },
              "application/problem+json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } }
            }
          },
          "401": {
            "description": "Unauthorized — Missing or invalid API key / session",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } },
              "application/problem+json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } }
            }
          },
          "402": {
            "description": "Payment Required — Insufficient clone credits",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } },
              "application/problem+json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } }
            }
          },
          "500": {
            "description": "Internal Server Error",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } },
              "application/problem+json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } }
            }
          },
          "502": {
            "description": "Bad Gateway — Cloning engine communication failure",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } },
              "application/problem+json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } }
            }
          },
          "503": {
            "description": "Service Unavailable — Engine temporarily unconfigured or busy",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } },
              "application/problem+json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } }
            }
          }
        }
      },
      "get": {
        "summary": "List user clones",
        "description": "Returns all website clones created by the authenticated user.",
        "operationId": "listClones",
        "parameters": [
          { "$ref": "#/components/parameters/ApiVersionHeader" }
        ],
        "responses": {
          "200": {
            "description": "List of user clone jobs",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean" },
                    "clones": {
                      "type": "array",
                      "items": { "$ref": "#/components/schemas/CloneDetails" }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized — Missing or invalid authentication",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } },
              "application/problem+json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } }
            }
          },
          "500": {
            "description": "Internal Server Error",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } },
              "application/problem+json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } }
            }
          }
        }
      }
    },
    "/api/clones/{id}": {
      "get": {
        "summary": "Get clone status",
        "description": "Retrieves the status, worker progress, and download link for a specific clone job.",
        "operationId": "getCloneById",
        "parameters": [
          { "$ref": "#/components/parameters/CloneIdParam" },
          { "$ref": "#/components/parameters/ApiVersionHeader" }
        ],
        "responses": {
          "200": {
            "description": "Clone details",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean" },
                    "clone": { "$ref": "#/components/schemas/CloneDetails" }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } },
              "application/problem+json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } }
            }
          },
          "404": {
            "description": "Clone Not Found",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } },
              "application/problem+json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } }
            }
          },
          "500": {
            "description": "Internal Server Error",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } },
              "application/problem+json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } }
            }
          }
        }
      },
      "delete": {
        "summary": "Delete clone job",
        "description": "Soft-deletes a clone job from the user's project history.",
        "operationId": "deleteCloneById",
        "parameters": [
          { "$ref": "#/components/parameters/CloneIdParam" },
          { "$ref": "#/components/parameters/ApiVersionHeader" }
        ],
        "responses": {
          "200": {
            "description": "Clone deleted successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean" },
                    "deletedId": { "type": "string" }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } },
              "application/problem+json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } }
            }
          },
          "404": {
            "description": "Clone Not Found",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } },
              "application/problem+json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } }
            }
          },
          "500": {
            "description": "Internal Server Error",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } },
              "application/problem+json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } }
            }
          }
        }
      }
    },
    "/api/clones/{id}/download": {
      "get": {
        "summary": "Download generated codebase",
        "description": "Downloads the compiled project archive (.TGZ or .ZIP) containing all modular React/Next.js code and local assets.",
        "operationId": "downloadCloneArchive",
        "parameters": [
          { "$ref": "#/components/parameters/CloneIdParam" },
          {
            "name": "format",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": ["tgz", "zip"],
              "default": "tgz"
            }
          },
          { "$ref": "#/components/parameters/ApiVersionHeader" }
        ],
        "responses": {
          "200": {
            "description": "Project archive binary file stream (.tgz or .zip)",
            "content": {
              "application/gzip": {
                "schema": { "type": "string", "format": "binary" }
              },
              "application/zip": {
                "schema": { "type": "string", "format": "binary" }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } },
              "application/problem+json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } }
            }
          },
          "404": {
            "description": "Clone Not Found or Archive Not Ready",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } },
              "application/problem+json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } }
            }
          },
          "502": {
            "description": "Storage Retrieval Failure",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } },
              "application/problem+json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } }
            }
          },
          "500": {
            "description": "Internal Server Error",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } },
              "application/problem+json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } }
            }
          }
        }
      }
    },
    "/api/clones/{id}/github-export": {
      "post": {
        "summary": "Export clone to GitHub",
        "description": "Creates a new GitHub repository on the user's account and pushes the cloned codebase.",
        "operationId": "exportToGitHub",
        "parameters": [
          { "$ref": "#/components/parameters/CloneIdParam" },
          { "$ref": "#/components/parameters/ApiVersionHeader" }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "repoName": { "type": "string", "description": "Target GitHub repository name" },
                  "isPrivate": { "type": "boolean", "default": true },
                  "description": { "type": "string" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Repository created and pushed successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean" },
                    "repoUrl": { "type": "string", "format": "uri" },
                    "repoName": { "type": "string" }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid parameters or GitHub not connected",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } },
              "application/problem+json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } },
              "application/problem+json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } }
            }
          },
          "404": {
            "description": "Clone Not Found",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } },
              "application/problem+json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } }
            }
          },
          "500": {
            "description": "Internal Server Error",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } },
              "application/problem+json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } }
            }
          }
        }
      }
    },
    "/api/user/me": {
      "get": {
        "summary": "Get user profile and credits",
        "description": "Retrieves the authenticated user profile, credit balance, and subscription tier.",
        "operationId": "getCurrentUser",
        "parameters": [
          { "$ref": "#/components/parameters/ApiVersionHeader" }
        ],
        "responses": {
          "200": {
            "description": "User profile and credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } },
              "application/problem+json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } }
            }
          },
          "500": {
            "description": "Internal Server Error",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } },
              "application/problem+json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } }
            }
          }
        }
      }
    },
    "/v1/clones": {
      "post": {
        "$ref": "#/paths/~1api~1clones/post"
      },
      "get": {
        "$ref": "#/paths/~1api~1clones/get"
      }
    },
    "/v1/clones/{id}": {
      "get": {
        "$ref": "#/paths/~1api~1clones~1{id}/get"
      },
      "delete": {
        "$ref": "#/paths/~1api~1clones~1{id}/delete"
      }
    },
    "/v1/clones/{id}/download": {
      "get": {
        "$ref": "#/paths/~1api~1clones~1{id}~1download/get"
      }
    },
    "/v1/clones/{id}/github-export": {
      "post": {
        "$ref": "#/paths/~1api~1clones~1{id}~1github-export/post"
      }
    },
    "/v1/user/me": {
      "get": {
        "$ref": "#/paths/~1api~1user~1me/get"
      }
    }
  },
  "components": {
    "parameters": {
      "ApiVersionHeader": {
        "name": "X-API-Version",
        "in": "header",
        "required": false,
        "description": "API version requested by the client (default: 1.0.0)",
        "schema": {
          "type": "string",
          "default": "1.0.0"
        }
      },
      "CloneIdParam": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "The unique clone job ID (e.g. cln_1740000000_abc123)",
        "schema": {
          "type": "string"
        }
      }
    },
    "schemas": {
      "CreateCloneRequest": {
        "type": "object",
        "required": ["url"],
        "properties": {
          "url": {
            "type": "string",
            "format": "uri",
            "description": "The target public website URL to clone."
          },
          "framework": {
            "type": "string",
            "enum": ["nextjs", "vite"],
            "default": "nextjs",
            "description": "Target frontend framework: Next.js 15 App Router or Vite React SPA."
          },
          "styling": {
            "type": "string",
            "enum": ["tailwind", "css"],
            "default": "tailwind",
            "description": "Target CSS architecture: Tailwind CSS v4 or Vanilla CSS."
          },
          "mode": {
            "type": "string",
            "enum": ["single", "multi"],
            "default": "single",
            "description": "Single landing page (1 credit) or multi-page recursive crawl."
          },
          "maxRoutes": {
            "type": "integer",
            "minimum": 1,
            "maximum": 25,
            "default": 1,
            "description": "Maximum linked sub-pages to crawl in multi-page mode."
          },
          "verify": {
            "type": "boolean",
            "default": true,
            "description": "Run automated TypeScript build verification before packaging."
          }
        }
      },
      "CloneJobResponse": {
        "type": "object",
        "properties": {
          "success": { "type": "boolean" },
          "cloneId": { "type": "string" },
          "jobId": { "type": "string" },
          "status": { "type": "string", "enum": ["queued", "processing", "completed", "failed"] },
          "creditCost": { "type": "integer" },
          "availableCredits": { "type": "integer" }
        }
      },
      "CloneDetails": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "targetUrl": { "type": "string" },
          "status": { "type": "string", "enum": ["queued", "processing", "completed", "failed"] },
          "framework": { "type": "string" },
          "styling": { "type": "string" },
          "r2PublicUrl": { "type": "string", "nullable": true },
          "createdAt": { "type": "string", "format": "date-time" }
        }
      },
      "UserResponse": {
        "type": "object",
        "properties": {
          "cloneCredits": { "type": "integer", "description": "Remaining available clone credits" },
          "subscriptionTier": { "type": "string", "description": "Active subscription tier (e.g. starter, builder, pro, scale, none)" }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "required": ["error", "code", "message", "hint", "status", "docs_url"],
        "properties": {
          "error": {
            "type": "string",
            "description": "Human-readable short error summary or title"
          },
          "code": {
            "type": "string",
            "enum": [
              "UNAUTHORIZED",
              "FORBIDDEN",
              "INVALID_REQUEST",
              "PAYMENT_REQUIRED",
              "NOT_FOUND",
              "ROUTE_NOT_FOUND",
              "METHOD_NOT_ALLOWED",
              "RATE_LIMITED",
              "CLONE_DISPATCH_FAILED",
              "SERVICE_UNAVAILABLE",
              "INTERNAL_SERVER_ERROR"
            ],
            "description": "Machine-readable standard error code"
          },
          "message": {
            "type": "string",
            "description": "Detailed description explaining why the error occurred"
          },
          "hint": {
            "type": "string",
            "description": "Actionable resolution steps for AI agents and developers to resolve the issue"
          },
          "status": {
            "type": "integer",
            "description": "HTTP status code matching the response"
          },
          "docs_url": {
            "type": "string",
            "format": "uri",
            "description": "Direct URL to developer documentation covering this error and endpoint"
          }
        }
      },
      "ProblemDetails": {
        "type": "object",
        "description": "RFC 9457 Problem Details object for HTTP APIs",
        "required": ["type", "title", "status", "detail"],
        "properties": {
          "type": { "type": "string", "format": "uri" },
          "title": { "type": "string" },
          "status": { "type": "integer" },
          "detail": { "type": "string" },
          "instance": { "type": "string", "format": "uri" },
          "code": { "type": "string" },
          "hint": { "type": "string" }
        }
      }
    }
  }
}
