{
  "openapi": "3.0.3",
  "info": {
    "title": "floow.design API",
    "version": "1.0.0",
    "description": "Convert mobile app screenshots to pixel-perfect HTML, export to Figma, and generate production-ready component code — all via a simple REST API.",
    "contact": {
      "name": "floow.design",
      "url": "https://www.floow.design/docs"
    }
  },
  "servers": [
    {
      "url": "https://www.floow.design/api/v1",
      "description": "Production"
    }
  ],
  "security": [
    {
      "ApiKeyAuth": []
    }
  ],
  "components": {
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "API Key",
        "description": "Your floow.design API key. Generate one from Dashboard → Settings → API Keys. Prefix: fl_"
      },
      "OAuth2": {
        "type": "oauth2",
        "description": "OAuth 2.0 authorization code flow with PKCE, for apps acting on a user's behalf. Access tokens are prefixed fla_ and are accepted by the project, frame, theme and agent endpoints (see /docs/api-reference), each of which requires the scope named below. Server metadata: https://www.floow.design/.well-known/oauth-authorization-server — protected resource metadata: https://www.floow.design/.well-known/oauth-protected-resource",
        "flows": {
          "authorizationCode": {
            "authorizationUrl": "https://www.floow.design/api/oauth/authorize",
            "tokenUrl": "https://www.floow.design/api/oauth/token",
            "refreshUrl": "https://www.floow.design/api/oauth/token",
            "scopes": {
              "profile:read": "View your basic profile (email, name, plan, credit balance)",
              "inspirations:read": "Browse the public ASO inspirations library",
              "projects:read": "Read your projects and frames",
              "projects:write": "Create and modify your projects and frames"
            }
          }
        }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string",
            "description": "Human-readable error message"
          },
          "upgrade": {
            "type": "boolean",
            "description": "true when the account plan is too low"
          },
          "requiredPlan": {
            "type": "string",
            "description": "Minimum plan required"
          }
        },
        "required": ["error"]
      },
      "StyleGuide": {
        "type": "object",
        "description": "Design tokens extracted from the source image",
        "properties": {
          "colors": {
            "type": "object",
            "properties": {
              "primary": {
                "type": "string",
                "example": "#6366f1"
              },
              "background": {
                "type": "string",
                "example": "#0f0f10"
              },
              "surface": {
                "type": "string",
                "example": "#1c1c1e"
              },
              "foreground": {
                "type": "string",
                "example": "#f5f5f7"
              },
              "muted": {
                "type": "string",
                "example": "#8e8e93"
              },
              "border": {
                "type": "string",
                "example": "#2c2c2e"
              },
              "accent": {
                "type": "string"
              },
              "destructive": {
                "type": "string"
              }
            },
            "required": [
              "primary",
              "background",
              "surface",
              "foreground",
              "muted",
              "border"
            ]
          },
          "typography": {
            "type": "object",
            "properties": {
              "fontFamily": {
                "type": "string",
                "example": "Inter, sans-serif"
              },
              "headingSize": {
                "type": "string",
                "example": "24px"
              },
              "bodySize": {
                "type": "string",
                "example": "14px"
              },
              "headingWeight": {
                "type": "string",
                "example": "700"
              },
              "bodyWeight": {
                "type": "string",
                "example": "400"
              }
            }
          },
          "spacing": {
            "type": "object",
            "properties": {
              "containerPadding": {
                "type": "string",
                "example": "20px"
              },
              "cardPadding": {
                "type": "string",
                "example": "16px"
              },
              "gap": {
                "type": "string",
                "example": "12px"
              }
            }
          },
          "borderRadius": {
            "type": "object",
            "properties": {
              "card": {
                "type": "string",
                "example": "16px"
              },
              "button": {
                "type": "string",
                "example": "8px"
              },
              "badge": {
                "type": "string"
              }
            }
          },
          "shadows": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "themeVariables": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "CSS custom property map. Keys start with --.",
            "example": {
              "--primary": "#6366f1",
              "--background": "#0f0f10",
              "--foreground": "#f5f5f7"
            }
          }
        }
      },
      "Component": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "example": "Bottom Navigation"
          },
          "type": {
            "type": "string",
            "example": "bottom-nav"
          },
          "description": {
            "type": "string"
          },
          "elements": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "UploadResult": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Permanent CDN URL — pass directly to image-to-html",
            "example": "https://blob.vercel-storage.com/image-to-html/..."
          },
          "filename": {
            "type": "string"
          },
          "contentType": {
            "type": "string",
            "example": "image/png"
          },
          "size": {
            "type": "integer",
            "description": "File size in bytes"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ImageToHtmlResult": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "html": {
            "type": "string",
            "description": "Complete self-contained HTML document. Render in a 390px-wide iframe."
          },
          "bodyHtml": {
            "type": "string",
            "description": "Unwrapped body content only."
          },
          "styleGuide": {
            "$ref": "#/components/schemas/StyleGuide"
          },
          "components": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Component"
            },
            "description": "Only present when breakdown: true was sent"
          }
        },
        "required": ["id", "html", "bodyHtml", "styleGuide"]
      },
      "ExportCodeResult": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Production-ready component code"
          },
          "language": {
            "type": "string",
            "enum": ["dart", "tsx", "swift", "kotlin"]
          },
          "fileExtension": {
            "type": "string",
            "enum": [".dart", ".tsx", ".swift", ".kt"]
          },
          "fileName": {
            "type": "string",
            "example": "HomeScreen.tsx"
          },
          "framework": {
            "type": "string",
            "enum": ["flutter", "react_native", "swiftui", "jetpack_compose"]
          },
          "cached": {
            "type": "boolean",
            "description": "true when a cached result was returned"
          }
        },
        "required": [
          "code",
          "language",
          "fileExtension",
          "fileName",
          "framework",
          "cached"
        ]
      },
      "UsageResult": {
        "type": "object",
        "properties": {
          "period": {
            "type": "object",
            "properties": {
              "start": {
                "type": "string",
                "format": "date-time"
              },
              "end": {
                "type": "string",
                "format": "date-time"
              },
              "days": {
                "type": "integer"
              }
            }
          },
          "key": {
            "type": "object",
            "description": "Present when scoped to a specific API key",
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "lastUsed": {
                "type": "string",
                "format": "date-time",
                "nullable": true
              }
            }
          },
          "summary": {
            "type": "object",
            "properties": {
              "totalCalls": {
                "type": "integer"
              },
              "totalCredits": {
                "type": "integer"
              },
              "byEndpoint": {
                "type": "object",
                "additionalProperties": {
                  "type": "object",
                  "properties": {
                    "calls": {
                      "type": "integer"
                    },
                    "credits": {
                      "type": "integer"
                    },
                    "label": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "daily": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "date": {
                  "type": "string",
                  "format": "date"
                },
                "calls": {
                  "type": "integer"
                },
                "credits": {
                  "type": "integer"
                }
              }
            }
          }
        }
      },
      "CreditPurchaseResult": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "format": "uri",
            "description": "One-time Stripe Checkout URL — redirect the user here"
          },
          "pack": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "credits": {
                "type": "integer"
              },
              "price": {
                "type": "string"
              }
            }
          }
        },
        "required": ["url", "pack"]
      }
    },
    "parameters": {
      "IdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": false,
        "description": "A unique value identifying this operation, so a retry cannot run it twice. The first request stores its response; replaying the same key returns that stored response with `Idempotency-Replayed: true`. Keys are scoped to the caller and the endpoint, and expire after 24 hours. Reusing a key with a different body returns 422 `idempotency_key_reuse`.",
        "schema": {
          "type": "string",
          "minLength": 8,
          "maxLength": 255,
          "example": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"
        }
      }
    }
  },
  "paths": {
    "/upload": {
      "post": {
        "operationId": "uploadImage",
        "summary": "Upload an image",
        "description": "Upload a screenshot or design image to the floow.design CDN. Returns a permanent URL you can pass directly to the Image → HTML endpoint.",
        "tags": ["Upload"],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary",
                    "description": "PNG, JPEG, WEBP, or GIF. Max 10 MB."
                  }
                },
                "required": ["file"]
              }
            },
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "image": {
                    "type": "string",
                    "description": "Base64 data URL — e.g. data:image/png;base64,…",
                    "example": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUg..."
                  },
                  "filename": {
                    "type": "string",
                    "description": "Optional filename hint",
                    "example": "home-screen.png"
                  }
                },
                "required": ["image"]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Upload successful",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UploadResult"
                }
              }
            }
          },
          "400": {
            "description": "Invalid file type or missing file",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Free plan — API access requires Lite or higher",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/image-to-html": {
      "post": {
        "operationId": "imageToHtml",
        "summary": "Convert image to HTML",
        "description": "Pass any UI screenshot or image and get back pixel-perfect HTML with extracted design tokens. Deducts 30 credits per call.",
        "tags": ["Image → HTML"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "image": {
                    "type": "string",
                    "description": "Base64 data URL or any public https:// URL.",
                    "example": "https://blob.vercel-storage.com/image-to-html/home.png"
                  },
                  "label": {
                    "type": "string",
                    "description": "Optional name for this conversion",
                    "example": "Home Screen"
                  },
                  "breakdown": {
                    "type": "boolean",
                    "default": false,
                    "description": "When true, also returns a component breakdown of every UI element."
                  }
                },
                "required": ["image"]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Conversion successful",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ImageToHtmlResult"
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid image",
            "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",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Free plan — upgrade to Lite or higher",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ]
      }
    },
    "/export-code": {
      "post": {
        "operationId": "exportCode",
        "summary": "Export screen to component code",
        "description": "Convert any screen HTML to production-ready component code. Supports Flutter, React Native, SwiftUI, and Jetpack Compose. Deducts 15 credits per call.",
        "tags": ["Export"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "html": {
                    "type": "string",
                    "description": "Raw HTML of the screen. Use this or frameId+projectId."
                  },
                  "frameId": {
                    "type": "string",
                    "description": "Frame ID from a floow.design project."
                  },
                  "projectId": {
                    "type": "string",
                    "description": "Project ID — required when using frameId."
                  },
                  "framework": {
                    "type": "string",
                    "enum": [
                      "flutter",
                      "react_native",
                      "swiftui",
                      "jetpack_compose"
                    ],
                    "description": "Target framework for code generation.",
                    "example": "react_native"
                  },
                  "label": {
                    "type": "string",
                    "description": "Screen name — used as the component/file name.",
                    "example": "HomeScreen"
                  }
                },
                "required": ["framework"]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Code generated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExportCodeResult"
                }
              }
            }
          },
          "400": {
            "description": "Missing required fields",
            "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",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ]
      }
    },
    "/figma-export": {
      "post": {
        "operationId": "figmaExport",
        "summary": "Export screen to Figma",
        "description": "Convert any screen HTML into Figma-compatible clipboard data. Paste directly into Figma to get native layers. Deducts 10 credits per call.",
        "tags": ["Export"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "html": {
                    "type": "string",
                    "description": "Full HTML of the screen to export."
                  },
                  "width": {
                    "type": "integer",
                    "default": 430,
                    "description": "Canvas width in px"
                  },
                  "height": {
                    "type": "integer",
                    "default": 932,
                    "description": "Canvas height in px"
                  },
                  "label": {
                    "type": "string",
                    "description": "Layer name in Figma",
                    "example": "Home Screen"
                  }
                },
                "required": ["html"]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Figma clipboard data — paste into Figma",
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "Missing html field",
            "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",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ]
      }
    },
    "/usage": {
      "get": {
        "operationId": "getUsage",
        "summary": "Get API usage stats",
        "description": "Returns call counts and credits consumed for your API key, broken down by endpoint and by day.",
        "tags": ["Usage & Credits"],
        "parameters": [
          {
            "name": "days",
            "in": "query",
            "required": false,
            "description": "Lookback window in days (1–90). Default: 30.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 90,
              "default": 30
            }
          },
          {
            "name": "keyId",
            "in": "query",
            "required": false,
            "description": "Filter to a different API key on your account.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Usage data",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UsageResult"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/credits/purchase": {
      "post": {
        "operationId": "purchaseCredits",
        "summary": "Buy a credit pack",
        "description": "Create a Stripe checkout session to purchase a credit pack. Returns a one-time checkout URL. Credits are added immediately after payment. Requires Lite plan or higher.",
        "tags": ["Usage & Credits"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "pack": {
                    "type": "string",
                    "enum": [
                      "credits_1000",
                      "credits_5000",
                      "credits_20000",
                      "credits_100000"
                    ],
                    "description": "ID of the credit pack to purchase.",
                    "example": "credits_5000"
                  }
                },
                "required": ["pack"]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Checkout session created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreditPurchaseResult"
                }
              }
            }
          },
          "400": {
            "description": "Invalid pack ID",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Free plan — upgrade to Lite or higher to buy packs",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ]
      }
    }
  },
  "tags": [
    {
      "name": "Upload",
      "description": "Host images on the floow.design CDN before converting them"
    },
    {
      "name": "Image → HTML",
      "description": "Convert UI screenshots to pixel-perfect HTML"
    },
    {
      "name": "Export",
      "description": "Export HTML screens to Figma or framework code"
    },
    {
      "name": "Usage & Credits",
      "description": "Track usage and manage credit top-ups"
    }
  ]
}
