{
  "openapi": "3.1.0",
  "info": {
    "title": "Firmngin API",
    "version": "1.0.0",
    "description": "REST API for the Firmngin AIoT platform — device management, firmware OTA, automations, monetization, and MCP agent integrations.",
    "contact": {
      "name": "Firmngin Support",
      "email": "team@firmngin.dev",
      "url": "https://firmngin.dev"
    },
    "license": {
      "name": "Proprietary",
      "url": "https://firmngin.dev/terms"
    }
  },
  "servers": [
    {
      "url": "https://firmngin.dev",
      "description": "Production"
    }
  ],
  "tags": [
    { "name": "Health", "description": "Service health and readiness probes" },
    { "name": "Plans", "description": "Public subscription plan catalog" },
    { "name": "Applications", "description": "Public application marketplace catalog" },
    { "name": "Boards", "description": "Supported hardware board catalog" },
    { "name": "AI Credits", "description": "Public AI credit package catalog" },
    { "name": "Public Merchant", "description": "Guest-facing merchant endpoints (no auth)" },
    { "name": "OAuth", "description": "OAuth 2.0 authorization server (MCP and Factory flows)" }
  ],
  "paths": {
    "/health": {
      "get": {
        "operationId": "getHealth",
        "summary": "Health check",
        "description": "Returns service health status. No authentication required.",
        "tags": ["Health"],
        "responses": {
          "200": {
            "description": "Service is healthy",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/HealthStatus" }
              }
            }
          }
        }
      }
    },
    "/api/v1/plans": {
      "get": {
        "operationId": "listPlans",
        "summary": "List subscription plans",
        "description": "Returns all publicly available subscription plans. No authentication required.",
        "tags": ["Plans"],
        "responses": {
          "200": {
            "description": "Plan list",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": { "$ref": "#/components/schemas/Plan" }
                    }
                  }
                }
              }
            }
          },
          "500": { "$ref": "#/components/responses/InternalError" }
        }
      }
    },
    "/api/v1/plans/{id}": {
      "get": {
        "operationId": "getPlan",
        "summary": "Get a subscription plan",
        "description": "Returns a single plan by ID. No authentication required.",
        "tags": ["Plans"],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "format": "uuid" }
          }
        ],
        "responses": {
          "200": {
            "description": "Plan details",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": { "$ref": "#/components/schemas/Plan" }
                  }
                }
              }
            }
          },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/api/v1/applications": {
      "get": {
        "operationId": "listApplications",
        "summary": "List published applications",
        "description": "Returns the public application marketplace catalog. No authentication required.",
        "tags": ["Applications"],
        "responses": {
          "200": {
            "description": "Application list",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": { "$ref": "#/components/schemas/Application" }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/applications/{application_id}": {
      "get": {
        "operationId": "getApplication",
        "summary": "Get an application",
        "description": "Returns a single published application by public ID. No authentication required.",
        "tags": ["Applications"],
        "parameters": [
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "minLength": 8, "maxLength": 8 }
          }
        ],
        "responses": {
          "200": {
            "description": "Application details",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": { "$ref": "#/components/schemas/Application" }
                  }
                }
              }
            }
          },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/api/v1/boards": {
      "get": {
        "operationId": "listBoards",
        "summary": "List supported hardware boards",
        "description": "Returns supported device board models. No authentication required.",
        "tags": ["Boards"],
        "parameters": [
          {
            "name": "board_model",
            "in": "query",
            "required": false,
            "schema": { "type": "string" },
            "description": "Filter by board model name"
          }
        ],
        "responses": {
          "200": {
            "description": "Board list",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": { "$ref": "#/components/schemas/Board" }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/ai-credit/packages": {
      "get": {
        "operationId": "listAICreditPackages",
        "summary": "List AI credit packages",
        "description": "Returns publicly available AI credit packages. No authentication required.",
        "tags": ["AI Credits"],
        "responses": {
          "200": {
            "description": "AI credit package list",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": { "$ref": "#/components/schemas/AICreditPackage" }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/devices": {
      "get": {
        "operationId": "listDevices",
        "summary": "List workspace devices",
        "description": "Returns devices in the authenticated user's workspace.",
        "tags": ["Devices"],
        "security": [{ "oauth2": ["devices:read"] }],
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "schema": { "type": "integer", "minimum": 1, "default": 1 }
          },
          {
            "name": "page_size",
            "in": "query",
            "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 20 }
          }
        ],
        "responses": {
          "200": { "description": "Device list" },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      },
      "post": {
        "operationId": "createDevice",
        "summary": "Create a device",
        "tags": ["Devices"],
        "security": [{ "oauth2": ["devices:manage"] }],
        "responses": {
          "201": { "description": "Device created" },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      }
    },
    "/api/v1/automations": {
      "get": {
        "operationId": "listAutomations",
        "summary": "List automations",
        "tags": ["Automations"],
        "security": [{ "oauth2": ["automations:read"] }],
        "responses": {
          "200": { "description": "Automation list" },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      }
    },
    "/.well-known/oauth-authorization-server": {
      "get": {
        "operationId": "getOAuthAuthorizationServerMetadata",
        "summary": "OAuth 2.0 authorization server metadata (RFC 8414)",
        "description": "Machine-readable OAuth authorization server metadata including supported scopes.",
        "tags": ["OAuth"],
        "responses": {
          "200": {
            "description": "Authorization server metadata",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/OAuthAuthorizationServerMetadata" }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "oauth2": {
        "type": "oauth2",
        "description": "OAuth 2.0 with PKCE (S256). Register a client dynamically or use a pre-registered MCP client. Scopes are least-privilege — request only what your agent needs.",
        "flows": {
          "authorizationCode": {
            "authorizationUrl": "https://firmngin.dev/oauth/mcp",
            "tokenUrl": "https://firmngin.dev/api/v1/oauth/mcp/token",
            "refreshUrl": "https://firmngin.dev/api/v1/oauth/mcp/token",
            "scopes": {
              "devices:read": "Read devices and entity states",
              "devices:control": "Send control commands to devices (GPIO, relays)",
              "devices:manage": "Create, update, and delete devices",
              "automations:read": "Read automations, schedules, and execution history",
              "automations:manage": "Create, update, and delete automations and schedules",
              "mandates:read": "Read proactive agent mandates and capabilities",
              "mandates:manage": "Create, update, activate, and delete proactive agent mandates",
              "entities:logs": "Read entity state change logs"
            }
          }
        }
      },
      "factoryOAuth2": {
        "type": "oauth2",
        "description": "OAuth 2.0 for Factory CLI provisioning flows.",
        "flows": {
          "authorizationCode": {
            "authorizationUrl": "https://firmngin.dev/oauth/factory",
            "tokenUrl": "https://firmngin.dev/api/v1/oauth/factory/token",
            "scopes": {
              "devices:read": "View fleet batches and device status",
              "devices:manage": "Bulk register devices and download provisioning bundles"
            }
          }
        }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": ["error", "message"],
        "properties": {
          "error": {
            "type": "string",
            "description": "Machine-readable error code in UPPER_SNAKE_CASE",
            "example": "NOT_FOUND"
          },
          "message": {
            "type": "string",
            "description": "Human-readable error message",
            "example": "Plan not found"
          }
        }
      },
      "HealthStatus": {
        "type": "object",
        "properties": {
          "status": { "type": "string", "example": "ok" },
          "version": { "type": "string" },
          "uptime": { "type": "string" }
        }
      },
      "Plan": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "name": { "type": "string" },
          "price": { "type": "number" },
          "currency": { "type": "string", "example": "USD" },
          "billing_period": { "type": "string", "enum": ["monthly", "yearly"] },
          "device_limit": { "type": "integer" },
          "mqtt_message_limit": { "type": "integer" }
        }
      },
      "Application": {
        "type": "object",
        "properties": {
          "application_id": { "type": "string", "minLength": 8, "maxLength": 8 },
          "name": { "type": "string" },
          "description": { "type": "string" },
          "category": { "type": "string" },
          "publisher": { "type": "string" }
        }
      },
      "Board": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "name": { "type": "string" },
          "board_model": { "type": "string" },
          "manufacturer": { "type": "string" }
        }
      },
      "AICreditPackage": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "name": { "type": "string" },
          "credits": { "type": "integer" },
          "price": { "type": "number" }
        }
      },
      "OAuthAuthorizationServerMetadata": {
        "type": "object",
        "properties": {
          "issuer": { "type": "string", "format": "uri", "example": "https://firmngin.dev" },
          "authorization_endpoint": { "type": "string", "format": "uri" },
          "token_endpoint": { "type": "string", "format": "uri" },
          "registration_endpoint": { "type": "string", "format": "uri" },
          "revocation_endpoint": { "type": "string", "format": "uri" },
          "scopes_supported": {
            "type": "array",
            "items": { "type": "string" },
            "example": [
              "devices:read",
              "devices:control",
              "devices:manage",
              "automations:read",
              "automations:manage",
              "mandates:read",
              "mandates:manage",
              "entities:logs"
            ]
          },
          "response_types_supported": {
            "type": "array",
            "items": { "type": "string" },
            "example": ["code"]
          },
          "grant_types_supported": {
            "type": "array",
            "items": { "type": "string" },
            "example": ["authorization_code", "refresh_token"]
          },
          "code_challenge_methods_supported": {
            "type": "array",
            "items": { "type": "string" },
            "example": ["S256"]
          }
        }
      }
    },
    "responses": {
      "NotFound": {
        "description": "Resource not found",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" }
          }
        }
      },
      "Unauthorized": {
        "description": "Authentication required",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" }
          }
        },
        "headers": {
          "WWW-Authenticate": {
            "schema": { "type": "string" },
            "example": "Bearer resource_metadata=\"https://mcp.firmngin.dev/.well-known/oauth-protected-resource\""
          }
        }
      },
      "InternalError": {
        "description": "Internal server error",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" }
          }
        }
      }
    }
  },
  "externalDocs": {
    "description": "Firmngin Developer Documentation",
    "url": "https://firmngin.dev/docs"
  }
}
