{
  "openapi": "3.1.0",
  "info": {
    "title": "Sparkshed API",
    "description": "REST API for Sparkshed — a browser-native electronics simulator with real AVR emulation, honest fidelity labels, and a path from idea to ordered hardware.\n\n## Authentication\nMost endpoints are same-origin only (CSRF-gated). The `/api/design` endpoint supports optional Supabase JWT authentication for attributed requests.\n\n## Rate Limits\nAll endpoints are rate-limited via a Durable Object-backed limiter. Rate limits fail closed — if the limiter is unreachable, requests are rejected.\n\n## Error Format\nAll errors return JSON with an `error` field and optional `code` for machine-readable classification.",
    "version": "1.0.0",
    "contact": {
      "name": "Sparkshed",
      "url": "https://sparkshed.dev"
    },
    "license": {
      "name": "See /legal/terms"
    }
  },
  "servers": [
    {
      "url": "https://sparkshed.dev",
      "description": "Production"
    }
  ],
  "paths": {
    "/api/health": {
      "get": {
        "operationId": "healthCheck",
        "summary": "Health check",
        "description": "Returns deployment status, commit SHA, branch, and uptime. Used by monitors and post-deploy checks.",
        "tags": ["System"],
        "responses": {
          "200": {
            "description": "Service is healthy",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": { "type": "string", "example": "ok" },
                    "commit": {
                      "type": "string",
                      "description": "Git commit SHA of the deployment"
                    },
                    "branch": { "type": "string", "description": "Git branch of the deployment" },
                    "servedForSec": {
                      "type": "integer",
                      "description": "Seconds since this isolate served its first request"
                    },
                    "ts": { "type": "string", "format": "date-time" }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/design": {
      "post": {
        "operationId": "createDesign",
        "summary": "AI circuit design from natural language",
        "description": "Takes a plain-English intent and returns a catalog-grounded circuit design with firmware. Supports SSE streaming for progressive results.\n\n## Modes\n- **New design:** Provide `intent` field.\n- **Edit design:** Provide `intent` + `edit` (current design as EditContext).\n- **Clarification:** If the intent is ambiguous, returns `clarifying` questions instead.\n\n## Streaming\nReturns `text/event-stream` with progressive `stage` frames and a terminal `done` frame.",
        "tags": ["AI"],
        "security": [{ "bearerAuth": [] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["intent"],
                "properties": {
                  "intent": {
                    "type": "string",
                    "maxLength": 500,
                    "description": "Plain-English description of the circuit to design"
                  },
                  "answers": {
                    "type": "object",
                    "description": "Responses to clarifying questions, keyed by category",
                    "additionalProperties": { "type": "string" }
                  },
                  "edit": {
                    "type": "object",
                    "description": "Current design as EditContext for edit mode"
                  },
                  "conversation": {
                    "type": "object",
                    "description": "Conversation context (id, turnCount, clamped turns)"
                  },
                  "attachments": {
                    "type": "array",
                    "description": "Attachments (images, files) for multimodal design"
                  },
                  "references": {
                    "type": "array",
                    "description": "What the user pointed at on the canvas"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Design result (or streaming SSE, or clarifying questions)",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "type": "object",
                      "description": "Successful design",
                      "properties": {
                        "project": { "type": "object", "description": "The designed project IR" },
                        "usage": { "type": "object", "description": "Token usage statistics" }
                      }
                    },
                    {
                      "type": "object",
                      "description": "Clarifying questions needed",
                      "properties": {
                        "clarifying": {
                          "type": "array",
                          "items": { "type": "object" },
                          "description": "Ambiguity categories with questions"
                        }
                      }
                    },
                    {
                      "type": "object",
                      "description": "Soft-blocked for safety",
                      "properties": {
                        "softBlock": { "type": "string", "description": "Safety refusal message" }
                      }
                    }
                  ]
                }
              },
              "text/event-stream": {
                "schema": {
                  "type": "string",
                  "description": "SSE stream with stage frames and terminal done frame"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          },
          "401": {
            "description": "Session expired or invalid credentials",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded",
            "headers": {
              "Retry-After": { "schema": { "type": "integer" } }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": { "type": "string" },
                    "code": { "type": "string", "enum": ["rate_limited"] }
                  }
                }
              }
            }
          },
          "503": {
            "description": "LLM provider unavailable or rate limiter unconfigured",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          }
        }
      }
    },
    "/api/compile": {
      "post": {
        "operationId": "compileFirmware",
        "summary": "Compile Arduino firmware",
        "description": "Proxies an Arduino sketch to a cloud compile host (arduino-cli). Returns compiled binary or diagnostics. The browser's built-in compiler handles basic sketches independently.",
        "tags": ["Firmware"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["source"],
                "properties": {
                  "source": {
                    "type": "string",
                    "description": "Arduino sketch source code (C++)",
                    "maxLength": 65536
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Compilation succeeded",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "binary": { "type": "string", "description": "Base64-encoded compiled binary" },
                    "diagnostics": { "type": "array", "description": "Compiler warnings and notes" }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid source or source too large",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          },
          "501": {
            "description": "Compile host not configured (no upstream set)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": { "type": "string" },
                    "note": { "type": "string" },
                    "instructions": { "type": "string" }
                  }
                }
              }
            }
          },
          "502": {
            "description": "Compile host unreachable or failed",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          },
          "504": {
            "description": "Compile host timeout (25s)",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          }
        }
      }
    },
    "/api/price": {
      "get": {
        "operationId": "getPartPrice",
        "summary": "Live BOM pricing for a part",
        "description": "Returns live pricing and stock from Digi-Key and Mouser for a manufacturer part number (MPN). Responses are edge-cached for 10 minutes. When no provider matches, returns null with a reason — the client falls back to reference prices.",
        "tags": ["BOM"],
        "parameters": [
          {
            "name": "mpn",
            "in": "query",
            "required": true,
            "schema": { "type": "string", "maxLength": 64 },
            "description": "Manufacturer Part Number (exact match)"
          }
        ],
        "responses": {
          "200": {
            "description": "Price quote (or null if no match)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "quote": {
                      "oneOf": [
                        {
                          "type": "object",
                          "properties": {
                            "mpn": { "type": "string" },
                            "manufacturer": { "type": "string", "nullable": true },
                            "distributor": { "type": "string" },
                            "unitPrice": { "type": "number" },
                            "currency": { "type": "string" },
                            "inStock": { "type": "boolean" },
                            "url": { "type": "string", "format": "uri" },
                            "fetchedAt": { "type": "string", "format": "date-time" }
                          }
                        },
                        { "type": "null" }
                      ]
                    },
                    "reason": { "type": "string", "description": "Why no quote was found" }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid MPN",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          }
        }
      }
    },
    "/api/pcbway/quote": {
      "post": {
        "operationId": "pcbwayQuote",
        "summary": "PCBWay PCB quotation",
        "description": "Returns live PCB pricing and lead time from PCBWay. Requires PCBWay API key to be configured.",
        "tags": ["Manufacturing"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "PCBWay quote parameters (board dimensions, layers, quantity, finish)"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "PCBWay quote result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "Status": { "type": "string" },
                    "QuoteResult": { "type": "object" }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid parameters",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          },
          "503": {
            "description": "PCBWay API key not configured",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          }
        }
      }
    },
    "/api/pcbway/freight": {
      "post": {
        "operationId": "pcbwayFreight",
        "summary": "PCBWay shipping estimation",
        "description": "Returns estimated shipping cost from PCBWay based on destination and board specs.",
        "tags": ["Manufacturing"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Shipping estimation parameters"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Shipping estimate",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "Status": { "type": "string" },
                    "FreightResult": { "type": "object" }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          },
          "503": {
            "description": "PCBWay API key not configured",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          }
        }
      }
    },
    "/api/telemetry": {
      "post": {
        "operationId": "submitTelemetry",
        "summary": "Submit anonymous telemetry event",
        "description": "Accepts anonymous usage events via sendBeacon. Age-gated and consent-gated. No PII.",
        "tags": ["Telemetry"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Anonymous telemetry event payload"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Event accepted",
            "content": {
              "text/plain": {
                "schema": { "type": "string", "example": "ok" }
              }
            }
          },
          "400": {
            "description": "Empty payload",
            "content": {
              "text/plain": {
                "schema": { "type": "string", "example": "empty" }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded",
            "content": {
              "text/plain": {
                "schema": { "type": "string", "example": "rate limited" }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "description": "Supabase JWT (ES256). Optional — unauthenticated requests are attributed by IP."
      }
    },
    "schemas": {
      "ErrorResponse": {
        "type": "object",
        "properties": {
          "error": { "type": "string", "description": "Human-readable error message" },
          "code": {
            "type": "string",
            "description": "Machine-readable error code",
            "enum": ["unauthenticated", "rate_limited", "unconfigured"]
          },
          "note": { "type": "string", "description": "Additional context" }
        },
        "required": ["error"]
      }
    }
  },
  "tags": [
    { "name": "System", "description": "Health checks and deployment info" },
    { "name": "AI", "description": "AI-powered circuit design" },
    { "name": "Firmware", "description": "Arduino firmware compilation" },
    { "name": "BOM", "description": "Bill of materials and pricing" },
    { "name": "Manufacturing", "description": "PCB and enclosure ordering" },
    { "name": "Telemetry", "description": "Anonymous usage analytics" }
  ]
}
