{
  "openapi": "3.1.0",
  "info": {
    "title": "VULK Public API",
    "summary": "Build production-ready apps from natural-language prompts.",
    "description": "The VULK Public API lets AI agents and developer tooling drive\nthe VULK app generator end-to-end: create a project from a prompt,\nlist projects, fetch generated source files, and manage credits.\n\nAuthentication is API-key only. Users generate keys at\nhttps://app.vulk.dev/settings/api-keys and pass them as\n`Authorization: Bearer vk_<api_key>`. Each key is scoped to a single\nuser account, rate-limited via the credit ledger, and can be revoked\nat any time.\n\nFor an integration quickstart with copy-pasteable Claude Desktop\nand Cursor configs, see https://vulk.dev/developers.",
    "version": "1.0.0",
    "contact": {
      "name": "VULK Support",
      "url": "https://vulk.dev/contact",
      "email": "support@vulk.dev"
    },
    "termsOfService": "https://vulk.dev/terms-conditions",
    "license": {
      "name": "Proprietary",
      "url": "https://vulk.dev/terms-conditions"
    }
  },
  "servers": [
    {
      "url": "https://app.vulk.dev/api/v1",
      "description": "Production"
    }
  ],
  "externalDocs": {
    "description": "Developer quickstart + Claude Desktop / Cursor setup",
    "url": "https://vulk.dev/developers"
  },
  "components": {
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "vk_*",
        "description": "Generate a key at https://app.vulk.dev/settings/api-keys. Send as `Authorization: Bearer vk_<key>`."
      }
    },
    "schemas": {
      "Project": {
        "type": "object",
        "description": "Note: list and single endpoints return slightly different field sets. The list endpoint returns `deploymentUrl`; the single-project endpoint returns `deployedUrl` and `uiType`. Both URL fields point at the deployed site — the dual-naming is a legacy DB artifact, treat them as interchangeable. Always pick the one that's present.",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "prompt": {
            "type": "string"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "deploymentUrl": {
            "type": "string",
            "nullable": true,
            "description": "Returned by GET /projects (list)."
          },
          "deployedUrl": {
            "type": "string",
            "nullable": true,
            "description": "Returned by GET /projects/{id} (detail)."
          },
          "customSubdomain": {
            "type": "string",
            "nullable": true
          },
          "visibility": {
            "type": "string",
            "enum": [
              "public",
              "private"
            ]
          },
          "uiType": {
            "type": "string",
            "description": "Platform tag, e.g. \"react\", \"nextjs\", \"flutter\". Returned by GET /projects/{id}."
          }
        },
        "required": [
          "id",
          "prompt",
          "createdAt"
        ]
      },
      "ProjectList": {
        "type": "object",
        "properties": {
          "projects": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Project"
            }
          },
          "total": {
            "type": "integer"
          },
          "limit": {
            "type": "integer"
          },
          "offset": {
            "type": "integer"
          }
        }
      },
      "ProjectFile": {
        "type": "object",
        "properties": {
          "path": {
            "type": "string",
            "description": "Path inside the project, e.g. src/App.tsx"
          },
          "content": {
            "type": "string",
            "description": "File body as UTF-8 text"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "path",
          "content"
        ]
      },
      "CreditBalance": {
        "type": "object",
        "properties": {
          "balance": {
            "type": "integer",
            "description": "Credits remaining this billing period"
          },
          "plan": {
            "type": "string",
            "enum": [
              "free",
              "builder",
              "pro",
              "max",
              "team",
              "business"
            ]
          },
          "renewsAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "Model": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Model id passed to POST /projects",
            "example": "gemini-3-pro"
          },
          "name": {
            "type": "string"
          },
          "provider": {
            "type": "string",
            "example": "google"
          },
          "minPlan": {
            "type": "string",
            "enum": [
              "free",
              "builder",
              "pro",
              "max",
              "team",
              "business"
            ]
          },
          "contextWindow": {
            "type": "integer"
          }
        }
      },
      "UsageStats": {
        "type": "object",
        "properties": {
          "requestsToday": {
            "type": "integer"
          },
          "requestsMonth": {
            "type": "integer"
          },
          "creditsSpentMonth": {
            "type": "integer"
          },
          "lastRequestAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string"
          }
        },
        "required": [
          "error"
        ]
      }
    }
  },
  "security": [
    {
      "ApiKeyAuth": []
    }
  ],
  "tags": [
    {
      "name": "Projects",
      "description": "Generate, list, fetch, and delete VULK projects."
    },
    {
      "name": "Credits",
      "description": "Check the credit balance that gates generation."
    },
    {
      "name": "Models",
      "description": "List available AI models."
    },
    {
      "name": "Usage",
      "description": "API-key usage stats."
    }
  ],
  "paths": {
    "/projects": {
      "get": {
        "tags": [
          "Projects"
        ],
        "summary": "List projects",
        "description": "Returns the authenticated user's projects, paginated.",
        "operationId": "listProjects",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            }
          },
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProjectList"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Projects"
        ],
        "summary": "Create a project from a prompt",
        "description": "Creates a new VULK project record from a natural-language prompt and\nreturns immediately. The generation pipeline picks the project up\nasynchronously — poll `GET /projects/{id}` for status, or fetch\ngenerated files via `GET /projects/{id}/files` once ready.\n\nA floor of 25 credits is checked synchronously at create time; the\nreal generation cost is debited later by the pipeline based on prompt\ncomplexity and model. Call `GET /credits/balance` to forecast.\n\nPer-key rate limit: 30 creates per 5 minutes (HTTP 429 with\n`Retry-After` header on breach).",
        "operationId": "createProject",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "prompt": {
                    "type": "string",
                    "description": "Natural-language description of the app to build.",
                    "example": "Build a SaaS dashboard with auth, Stripe billing, and a Postgres backend."
                  },
                  "model": {
                    "type": "string",
                    "description": "Optional model id (see GET /models). Defaults to the user's plan default.",
                    "example": "gemini-3-pro"
                  }
                },
                "required": [
                  "prompt"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Project queued for generation",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "project": {
                      "$ref": "#/components/schemas/Project"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing prompt or unknown model id",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits — under the create-time floor of 25 credits. Call `GET /credits/balance` and have the user top up.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "balance": {
                      "type": "integer"
                    },
                    "required": {
                      "type": "integer"
                    },
                    "blockedReason": {
                      "type": "string",
                      "nullable": true
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded — 30 creates per 5 minutes per API key. Honour the `Retry-After` header.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the rate-limit window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/projects/{id}": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        }
      ],
      "get": {
        "tags": [
          "Projects"
        ],
        "summary": "Get a project",
        "operationId": "getProject",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Project"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key"
          },
          "404": {
            "description": "Project not found or not owned by this key"
          }
        }
      },
      "delete": {
        "tags": [
          "Projects"
        ],
        "summary": "Delete a project",
        "operationId": "deleteProject",
        "responses": {
          "204": {
            "description": "Deleted"
          },
          "401": {
            "description": "Missing or invalid API key"
          },
          "404": {
            "description": "Project not found"
          }
        }
      }
    },
    "/projects/{id}/files": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        }
      ],
      "get": {
        "tags": [
          "Projects"
        ],
        "summary": "List project files",
        "description": "Fetches every file in the project as a flat array (path + content).",
        "operationId": "listProjectFiles",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "files": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ProjectFile"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key"
          },
          "404": {
            "description": "Project not found"
          }
        }
      }
    },
    "/credits/balance": {
      "get": {
        "tags": [
          "Credits"
        ],
        "summary": "Get credit balance",
        "operationId": "getCreditBalance",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreditBalance"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key"
          }
        }
      }
    },
    "/models": {
      "get": {
        "tags": [
          "Models"
        ],
        "summary": "List available models",
        "description": "Public catalog of every model VULK can route to. No auth required — the actual gating (which models the caller can invoke) happens at generation time, based on the API key's plan and credit balance.",
        "operationId": "listModels",
        "security": [],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "models": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Model"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/usage": {
      "get": {
        "tags": [
          "Usage"
        ],
        "summary": "Get API key usage stats",
        "operationId": "getUsage",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UsageStats"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key"
          }
        }
      }
    }
  }
}