{
  "openapi": "3.1.0",
  "info": {
    "title": "BuildHut API (machine contract)",
    "version": "1.0.0",
    "description": "Single-source contract generated from scripts/contract/registry.ts by scripts/gen-contract.ts - do not edit public/openapi.json by hand; change the registry and re-run `bun scripts/contract:generate`. Hand-written sibling: openapi.yaml (broader surface incl. OTLP/feature flags).",
    "license": {
      "name": "MIT",
      "url": "https://opensource.org/licenses/MIT"
    }
  },
  "servers": [
    {
      "url": "https://hut.buildr.fun",
      "description": "Production (self-hosted, k8s)"
    },
    {
      "url": "http://localhost:5173",
      "description": "Local development"
    }
  ],
  "tags": [
    {
      "name": "Apps"
    },
    {
      "name": "Directory"
    },
    {
      "name": "Upload"
    },
    {
      "name": "Publishing"
    },
    {
      "name": "Telemetry"
    },
    {
      "name": "Utility"
    }
  ],
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "CI/CD and CLI API token: `bh_` + 64 hex chars (portal/tokens)"
      },
      "sessionAuth": {
        "type": "apiKey",
        "in": "cookie",
        "name": "session-token",
        "description": "Web portal session cookie"
      },
      "appSecret": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Secret",
        "description": "32-char hex app telemetry secret (X-Secret header, ?secret= or body secret)"
      }
    }
  },
  "paths": {
    "/api/apps": {
      "get": {
        "summary": "List apps",
        "tags": [
          "Directory",
          "Apps"
        ],
        "security": [
          {}
        ],
        "responses": {
          "200": {
            "description": "Paginated list of apps",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "apps": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "name": {
                            "type": "string"
                          },
                          "description": {
                            "anyOf": [
                              {
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "iconUrl": {
                            "anyOf": [
                              {
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "screenshots": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          },
                          "tags": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          },
                          "createdAt": {
                            "type": "string",
                            "format": "date-time",
                            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
                          },
                          "updatedAt": {
                            "type": "string",
                            "format": "date-time",
                            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
                          },
                          "buildCount": {
                            "type": "integer",
                            "minimum": -9007199254740991,
                            "maximum": 9007199254740991
                          },
                          "platforms": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          },
                          "dev": {
                            "anyOf": [
                              {
                                "type": "object",
                                "properties": {
                                  "id": {
                                    "type": "string"
                                  },
                                  "name": {
                                    "type": "string"
                                  },
                                  "avatarUrl": {
                                    "anyOf": [
                                      {
                                        "type": "string"
                                      },
                                      {
                                        "type": "null"
                                      }
                                    ]
                                  }
                                },
                                "required": [
                                  "id",
                                  "name",
                                  "avatarUrl"
                                ]
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "org": {
                            "anyOf": [
                              {
                                "type": "object",
                                "properties": {
                                  "id": {
                                    "type": "string"
                                  },
                                  "name": {
                                    "type": "string"
                                  },
                                  "avatarUrl": {
                                    "anyOf": [
                                      {
                                        "type": "string"
                                      },
                                      {
                                        "type": "null"
                                      }
                                    ]
                                  }
                                },
                                "required": [
                                  "id",
                                  "name",
                                  "avatarUrl"
                                ]
                              },
                              {
                                "type": "null"
                              }
                            ]
                          }
                        },
                        "required": [
                          "id",
                          "name",
                          "description",
                          "iconUrl",
                          "screenshots",
                          "tags",
                          "createdAt",
                          "updatedAt",
                          "buildCount",
                          "platforms",
                          "dev",
                          "org"
                        ]
                      }
                    },
                    "pagination": {
                      "type": "object",
                      "properties": {
                        "page": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991
                        },
                        "pageSize": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991
                        },
                        "totalPages": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991
                        },
                        "totalCount": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991
                        }
                      },
                      "required": [
                        "page",
                        "pageSize",
                        "totalPages",
                        "totalCount"
                      ]
                    }
                  },
                  "required": [
                    "apps",
                    "pagination"
                  ]
                }
              }
            }
          },
          "500": {
            "description": "Unable to list apps",
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        },
                        "received": {}
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        },
                        "upgrade": {
                          "type": "boolean"
                        }
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "message"
                      ]
                    }
                  ]
                }
              }
            }
          }
        },
        "description": "Public directory listing with substring search, organisation filter and pagination (page size 20, ordered by updatedAt desc). Cache-Control: public, max-age=120.",
        "parameters": [
          {
            "name": "search",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "org",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "default": 1,
              "type": "integer",
              "minimum": 1,
              "maximum": 9007199254740991
            }
          }
        ]
      }
    },
    "/api/apps/{name}": {
      "get": {
        "summary": "Get app detail",
        "tags": [
          "Directory",
          "Apps"
        ],
        "security": [
          {}
        ],
        "responses": {
          "200": {
            "description": "App detail with builds, banner and related apps",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "app": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string"
                        },
                        "name": {
                          "type": "string"
                        },
                        "description": {
                          "anyOf": [
                            {
                              "type": "string"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "iconUrl": {
                          "anyOf": [
                            {
                              "type": "string"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "screenshots": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        },
                        "tags": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        },
                        "sourceType": {
                          "anyOf": [
                            {
                              "type": "string",
                              "enum": [
                                "github",
                                "sourcehut",
                                "custom"
                              ]
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "sourceUrl": {
                          "anyOf": [
                            {
                              "type": "string"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "supportedOses": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        },
                        "createdAt": {
                          "type": "string",
                          "format": "date-time",
                          "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
                        },
                        "updatedAt": {
                          "type": "string",
                          "format": "date-time",
                          "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
                        },
                        "totalDownloads": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991
                        },
                        "buildCount": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991
                        },
                        "dev": {
                          "anyOf": [
                            {
                              "type": "object",
                              "properties": {
                                "id": {
                                  "type": "string"
                                },
                                "name": {
                                  "type": "string"
                                },
                                "email": {
                                  "anyOf": [
                                    {
                                      "type": "string"
                                    },
                                    {
                                      "type": "null"
                                    }
                                  ]
                                },
                                "avatarUrl": {
                                  "anyOf": [
                                    {
                                      "type": "string"
                                    },
                                    {
                                      "type": "null"
                                    }
                                  ]
                                },
                                "createdAt": {
                                  "anyOf": [
                                    {
                                      "type": "string",
                                      "format": "date-time",
                                      "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
                                    },
                                    {
                                      "type": "null"
                                    }
                                  ]
                                },
                                "pgpPublicKey": {
                                  "anyOf": [
                                    {
                                      "type": "string"
                                    },
                                    {
                                      "type": "null"
                                    }
                                  ]
                                },
                                "pgpKeyId": {
                                  "anyOf": [
                                    {
                                      "type": "string"
                                    },
                                    {
                                      "type": "null"
                                    }
                                  ]
                                }
                              },
                              "required": [
                                "id",
                                "name",
                                "email",
                                "avatarUrl",
                                "createdAt",
                                "pgpPublicKey",
                                "pgpKeyId"
                              ]
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "org": {
                          "anyOf": [
                            {
                              "type": "object",
                              "properties": {
                                "id": {
                                  "type": "string"
                                },
                                "name": {
                                  "type": "string"
                                },
                                "avatarUrl": {
                                  "anyOf": [
                                    {
                                      "type": "string"
                                    },
                                    {
                                      "type": "null"
                                    }
                                  ]
                                },
                                "createdAt": {
                                  "anyOf": [
                                    {
                                      "type": "string",
                                      "format": "date-time",
                                      "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
                                    },
                                    {
                                      "type": "null"
                                    }
                                  ]
                                }
                              },
                              "required": [
                                "id",
                                "name",
                                "avatarUrl",
                                "createdAt"
                              ]
                            },
                            {
                              "type": "null"
                            }
                          ]
                        }
                      },
                      "required": [
                        "id",
                        "name",
                        "description",
                        "iconUrl",
                        "screenshots",
                        "tags",
                        "sourceType",
                        "sourceUrl",
                        "supportedOses",
                        "createdAt",
                        "updatedAt",
                        "totalDownloads",
                        "buildCount",
                        "dev",
                        "org"
                      ]
                    },
                    "builds": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "version": {
                            "type": "string"
                          },
                          "os": {
                            "anyOf": [
                              {
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "architecture": {
                            "anyOf": [
                              {
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "fileName": {
                            "type": "string",
                            "minLength": 1,
                            "description": "Artifact file name with its extension"
                          },
                          "description": {
                            "anyOf": [
                              {
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "iconUrl": {
                            "anyOf": [
                              {
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "screenshots": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          },
                          "tags": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          },
                          "downloadCount": {
                            "type": "integer",
                            "minimum": -9007199254740991,
                            "maximum": 9007199254740991
                          },
                          "uploadedAt": {
                            "type": "string",
                            "format": "date-time",
                            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
                          },
                          "hasSignature": {
                            "anyOf": [
                              {
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          }
                        },
                        "required": [
                          "id",
                          "version",
                          "os",
                          "architecture",
                          "fileName",
                          "description",
                          "iconUrl",
                          "screenshots",
                          "tags",
                          "downloadCount",
                          "uploadedAt",
                          "hasSignature"
                        ]
                      }
                    },
                    "banner": {},
                    "otherAppsByDev": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "name": {
                            "type": "string"
                          },
                          "description": {
                            "anyOf": [
                              {
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "iconUrl": {
                            "anyOf": [
                              {
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "updatedAt": {
                            "anyOf": [
                              {
                                "type": "string",
                                "format": "date-time",
                                "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          }
                        },
                        "required": [
                          "id",
                          "name",
                          "description",
                          "iconUrl",
                          "updatedAt"
                        ]
                      }
                    },
                    "otherAppsByOrg": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "name": {
                            "type": "string"
                          },
                          "description": {
                            "anyOf": [
                              {
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "iconUrl": {
                            "anyOf": [
                              {
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "updatedAt": {
                            "anyOf": [
                              {
                                "type": "string",
                                "format": "date-time",
                                "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          }
                        },
                        "required": [
                          "id",
                          "name",
                          "description",
                          "iconUrl",
                          "updatedAt"
                        ]
                      }
                    }
                  },
                  "required": [
                    "app",
                    "builds",
                    "banner",
                    "otherAppsByDev",
                    "otherAppsByOrg"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "App not found",
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        },
                        "received": {}
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        },
                        "upgrade": {
                          "type": "boolean"
                        }
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "message"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "500": {
            "description": "Unable to load app",
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        },
                        "received": {}
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        },
                        "upgrade": {
                          "type": "boolean"
                        }
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "message"
                      ]
                    }
                  ]
                }
              }
            }
          }
        },
        "description": "Full app detail with all builds, banner, developer and organisation info, plus up to 5 other apps by the same developer / organisation. Cache-Control: public, max-age=120.",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1
            },
            "description": "Path parameter"
          }
        ]
      }
    },
    "/api/apps/{name}/latest": {
      "get": {
        "summary": "Download latest build (redirect)",
        "tags": [
          "Apps"
        ],
        "security": [
          {}
        ],
        "responses": {
          "303": {
            "description": "Redirect to presigned S3 URL (Location header)"
          },
          "404": {
            "description": "App not found, or no build matching the platform"
          },
          "500": {
            "description": "Storage misconfiguration"
          }
        },
        "description": "302/303 redirect to a presigned S3 download URL for the latest build (any platform). A catch-all suffix ({os}[/{arch}[/{format}[/signature]]]) selects the platform - see the platform param. Increments the download counter with a 30s per-IP debounce.",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1
            },
            "description": "Path parameter"
          }
        ]
      }
    },
    "/api/upload": {
      "post": {
        "summary": "Upload build (direct) / finalize presigned upload",
        "tags": [
          "Upload"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "201": {
            "description": "Build record created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "buildId": {
                      "type": "string"
                    },
                    "appName": {
                      "type": "string"
                    },
                    "version": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "success",
                    "buildId",
                    "appName",
                    "version"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Missing/invalid fields, unsupported extension, bad icon or signature file",
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        },
                        "received": {}
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        },
                        "upgrade": {
                          "type": "boolean"
                        }
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "message"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        },
                        "received": {}
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        },
                        "upgrade": {
                          "type": "boolean"
                        }
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "message"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "402": {
            "description": "Build limit reached (plan upgrade needed)",
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        },
                        "received": {}
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        },
                        "upgrade": {
                          "type": "boolean"
                        }
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "message"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "404": {
            "description": "No build to attach a signature-only upload to",
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        },
                        "received": {}
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        },
                        "upgrade": {
                          "type": "boolean"
                        }
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "message"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "413": {
            "description": "File exceeds 200 MB limit",
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        },
                        "received": {}
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        },
                        "upgrade": {
                          "type": "boolean"
                        }
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "message"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "500": {
            "description": "Storage or icon upload failure",
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        },
                        "received": {}
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        },
                        "upgrade": {
                          "type": "boolean"
                        }
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "message"
                      ]
                    }
                  ]
                }
              }
            }
          }
        },
        "description": "Two flows by content type: (1) multipart/form-data with a `file` field streams the binary straight to S3 (max 200 MB, supported extensions apk/aab/exe/msi/msix/appimage/deb/rpm/flatpak/snap/appbundle/bin/tar.zst/tar.gz/tar.xz/tgz); (2) JSON (or form without file) finalizes an earlier presigned PUT - s3Key must start with builds/. App name is lowercased server-side. Auth: Bearer API token (bh_...) via hooks or a dev session.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "minLength": 1
                  },
                  "version": {
                    "type": "string",
                    "minLength": 1
                  },
                  "description": {
                    "type": "string"
                  },
                  "fileName": {
                    "type": "string",
                    "minLength": 1,
                    "description": "Artifact file name with its extension"
                  },
                  "s3Key": {
                    "type": "string",
                    "minLength": 1,
                    "pattern": "^builds\\/",
                    "description": "S3 object key, must start with builds/"
                  },
                  "os": {
                    "type": "string"
                  },
                  "architecture": {
                    "type": "string"
                  },
                  "iconMode": {
                    "type": "string",
                    "enum": [
                      "upload",
                      "url"
                    ]
                  },
                  "iconUrl": {
                    "type": "string"
                  }
                },
                "required": [
                  "name",
                  "version",
                  "fileName",
                  "s3Key"
                ]
              }
            },
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "minLength": 1
                  },
                  "version": {
                    "type": "string",
                    "minLength": 1
                  },
                  "description": {
                    "type": "string"
                  },
                  "fileName": {
                    "type": "string",
                    "minLength": 1,
                    "description": "Artifact file name with its extension"
                  },
                  "s3Key": {
                    "type": "string",
                    "minLength": 1,
                    "pattern": "^builds\\/",
                    "description": "S3 object key, must start with builds/"
                  },
                  "os": {
                    "type": "string"
                  },
                  "architecture": {
                    "type": "string"
                  },
                  "iconMode": {
                    "type": "string",
                    "enum": [
                      "upload",
                      "url"
                    ]
                  },
                  "iconUrl": {
                    "type": "string"
                  },
                  "iconFile": {
                    "type": "string",
                    "format": "binary",
                    "contentEncoding": "binary"
                  },
                  "file": {
                    "type": "string",
                    "format": "binary",
                    "contentEncoding": "binary"
                  },
                  "signature": {
                    "type": "string",
                    "format": "binary",
                    "contentEncoding": "binary"
                  },
                  "signatureS3Key": {
                    "type": "string",
                    "minLength": 1,
                    "pattern": "^builds\\/",
                    "description": "S3 object key, must start with builds/"
                  }
                },
                "required": [
                  "name",
                  "version"
                ]
              }
            }
          }
        }
      }
    },
    "/api/upload/multipart": {
      "post": {
        "summary": "Chunked upload API (large artifacts)",
        "tags": [
          "Upload"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "part-url / abort / signature-complete result (URL, aborted id, or updated-signature build)",
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "url": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "url"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "success": {
                          "type": "boolean",
                          "const": true
                        },
                        "aborted": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "success",
                        "aborted"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "success": {
                          "type": "boolean",
                          "const": true
                        },
                        "buildId": {
                          "type": "string"
                        },
                        "appName": {
                          "type": "string"
                        },
                        "version": {
                          "type": "string"
                        },
                        "updated": {
                          "type": "string",
                          "const": "signature"
                        }
                      },
                      "required": [
                        "success",
                        "buildId",
                        "appName",
                        "version",
                        "updated"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "201": {
            "description": "Init session created, or binary complete finalized",
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "url": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "url"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "success": {
                          "type": "boolean",
                          "const": true
                        },
                        "aborted": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "success",
                        "aborted"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "success": {
                          "type": "boolean",
                          "const": true
                        },
                        "buildId": {
                          "type": "string"
                        },
                        "appName": {
                          "type": "string"
                        },
                        "version": {
                          "type": "string"
                        },
                        "updated": {
                          "type": "string",
                          "const": "signature"
                        }
                      },
                      "required": [
                        "success",
                        "buildId",
                        "appName",
                        "version",
                        "updated"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        },
                        "received": {}
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        },
                        "upgrade": {
                          "type": "boolean"
                        }
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "message"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        },
                        "received": {}
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        },
                        "upgrade": {
                          "type": "boolean"
                        }
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "message"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "404": {
            "description": "Unknown or expired uploadId; no build to attach signature",
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        },
                        "received": {}
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        },
                        "upgrade": {
                          "type": "boolean"
                        }
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "message"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "413": {
            "description": "File exceeds 200 MB limit",
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        },
                        "received": {}
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        },
                        "upgrade": {
                          "type": "boolean"
                        }
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "message"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "500": {
            "description": "S3/storage failure or signature verification failure",
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        },
                        "received": {}
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        },
                        "upgrade": {
                          "type": "boolean"
                        }
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "message"
                      ]
                    }
                  ]
                }
              }
            }
          }
        },
        "description": "JSON action API that bypasses the Cloudflare proxy's ~100 MB request-body cap: `init` ({kind: binary|signature, name, version, fileName, size, contentType?, parts?}) returns {uploadId, key, partSize, partUrls[], expiresIn}; PUT every part to S3 directly and collect ETags (retry one part with `part-url`); `complete` {uploadId, parts:[{partNumber,etag}]} finishes the S3 upload and creates the build rows exactly like POST /api/upload (for kind=signature complete takes {uploadId} only); `abort` abandons the upload. Auth: Bearer token or dev session.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "anyOf": [
                  {
                    "type": "object",
                    "properties": {
                      "action": {
                        "type": "string",
                        "const": "init"
                      },
                      "name": {
                        "type": "string",
                        "minLength": 1
                      },
                      "version": {
                        "type": "string",
                        "minLength": 1
                      },
                      "size": {
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 200000000
                      },
                      "contentType": {
                        "type": "string",
                        "minLength": 1
                      },
                      "kind": {
                        "type": "string",
                        "const": "binary"
                      },
                      "fileName": {
                        "type": "string",
                        "minLength": 1,
                        "pattern": "(.([aA][pP][kK]|[aA][aA][bB]|[eE][xX][eE]|[mM][sS][iI]|[mM][sS][iI][xX]|[aA][pP][pP][iI][mM][aA][gG][eE]|[dD][eE][bB]|[rR][pP][mM]|[fF][lL][aA][tT][pP][aA][kK]|[sS][nN][aA][pP]|[aA][pP][pP][bB][uU][nN][dD][lL][eE]|[bB][iI][nN]|[tT][aA][rR]\\.[zZ][sS][tT]|[tT][aA][rR]\\.[gG][zZ]|[tT][aA][rR]\\.[xX][zZ]|[tT][gG][zZ]))$",
                        "description": "Artifact file name; must end with one of: apk, aab, exe, msi, msix, appimage, deb, rpm, flatpak, snap, appbundle, bin, tar.zst, tar.gz, tar.xz, tgz"
                      },
                      "parts": {
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 10000
                      }
                    },
                    "required": [
                      "action",
                      "name",
                      "version",
                      "size",
                      "kind",
                      "fileName"
                    ]
                  },
                  {
                    "type": "object",
                    "properties": {
                      "action": {
                        "type": "string",
                        "const": "init"
                      },
                      "name": {
                        "type": "string",
                        "minLength": 1
                      },
                      "version": {
                        "type": "string",
                        "minLength": 1
                      },
                      "size": {
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 200000000
                      },
                      "contentType": {
                        "type": "string",
                        "minLength": 1
                      },
                      "kind": {
                        "type": "string",
                        "const": "signature"
                      },
                      "fileName": {
                        "type": "string",
                        "minLength": 1,
                        "pattern": "(.([aA][sS][cC]|[sS][iI][gG]))$",
                        "description": "PGP detached signature file name (.asc or .sig)"
                      }
                    },
                    "required": [
                      "action",
                      "name",
                      "version",
                      "size",
                      "kind",
                      "fileName"
                    ]
                  },
                  {
                    "type": "object",
                    "properties": {
                      "action": {
                        "type": "string",
                        "const": "part-url"
                      },
                      "uploadId": {
                        "type": "string",
                        "minLength": 1
                      },
                      "partNumber": {
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 10000
                      }
                    },
                    "required": [
                      "action",
                      "uploadId",
                      "partNumber"
                    ]
                  },
                  {
                    "type": "object",
                    "properties": {
                      "action": {
                        "type": "string",
                        "const": "complete"
                      },
                      "uploadId": {
                        "type": "string",
                        "minLength": 1
                      },
                      "parts": {
                        "minItems": 1,
                        "maxItems": 10000,
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "partNumber": {
                              "type": "integer",
                              "minimum": 1,
                              "maximum": 9007199254740991
                            },
                            "etag": {
                              "type": "string",
                              "minLength": 1
                            }
                          },
                          "required": [
                            "partNumber",
                            "etag"
                          ]
                        }
                      },
                      "description": {
                        "type": "string"
                      },
                      "os": {
                        "type": "string"
                      },
                      "architecture": {
                        "type": "string"
                      }
                    },
                    "required": [
                      "action",
                      "uploadId",
                      "parts"
                    ]
                  },
                  {
                    "type": "object",
                    "properties": {
                      "action": {
                        "type": "string",
                        "const": "complete"
                      },
                      "uploadId": {
                        "type": "string",
                        "minLength": 1
                      }
                    },
                    "required": [
                      "action",
                      "uploadId"
                    ]
                  },
                  {
                    "type": "object",
                    "properties": {
                      "action": {
                        "type": "string",
                        "const": "abort"
                      },
                      "uploadId": {
                        "type": "string",
                        "minLength": 1
                      }
                    },
                    "required": [
                      "action",
                      "uploadId"
                    ]
                  }
                ]
              }
            }
          }
        }
      }
    },
    "/api/branches": {
      "get": {
        "summary": "List git branches of an app's source repo",
        "tags": [
          "Publishing",
          "Utility"
        ],
        "security": [
          {
            "sessionAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Branch list",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "branches": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  },
                  "required": [
                    "branches"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Missing app parameter",
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        },
                        "received": {}
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        },
                        "upgrade": {
                          "type": "boolean"
                        }
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "message"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "403": {
            "description": "Not authenticated or not the owner of the app",
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        },
                        "received": {}
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        },
                        "upgrade": {
                          "type": "boolean"
                        }
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "message"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "404": {
            "description": "App not found",
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        },
                        "received": {}
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        },
                        "upgrade": {
                          "type": "boolean"
                        }
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "message"
                      ]
                    }
                  ]
                }
              }
            }
          }
        },
        "description": "Lists branches from the app's source host (GitHub/SourceHut) using the developer's stored OAuth token; requires the app query parameter and ownership of the app (session or Bearer token).",
        "parameters": [
          {
            "name": "app",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1
            }
          }
        ]
      }
    },
    "/api/pgp/fetch-key": {
      "post": {
        "summary": "Look up a PGP public key from keys.openpgp.org",
        "tags": [
          "Utility"
        ],
        "security": [
          {
            "sessionAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "PGP key details",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "armoredKey": {
                      "type": "string"
                    },
                    "keyId": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "uid": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    }
                  },
                  "required": [
                    "armoredKey",
                    "keyId",
                    "uid"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON or missing query field",
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        },
                        "received": {}
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        },
                        "upgrade": {
                          "type": "boolean"
                        }
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "message"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        },
                        "received": {}
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        },
                        "upgrade": {
                          "type": "boolean"
                        }
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "message"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "404": {
            "description": "Key not found on keys.openpgp.org",
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        },
                        "received": {}
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        },
                        "upgrade": {
                          "type": "boolean"
                        }
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "message"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "502": {
            "description": "Keyserver lookup failed",
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        },
                        "received": {}
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        },
                        "upgrade": {
                          "type": "boolean"
                        }
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "message"
                      ]
                    }
                  ]
                }
              }
            }
          }
        },
        "description": "Query by email address or key ID / fingerprint. Returns the armored public key with optional key ID and uid. Requires a dev session or Bearer token.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "query": {
                    "type": "string",
                    "minLength": 1
                  }
                },
                "required": [
                  "query"
                ]
              }
            }
          }
        }
      }
    },
    "/api/telemetry": {
      "post": {
        "summary": "Log a telemetry event",
        "tags": [
          "Telemetry"
        ],
        "security": [
          {
            "appSecret": []
          }
        ],
        "responses": {
          "201": {
            "description": "Telemetry accepted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    }
                  },
                  "required": [
                    "ok"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Missing appName or invalid payload",
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        },
                        "received": {}
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        },
                        "upgrade": {
                          "type": "boolean"
                        }
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "message"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid secret; app telemetry not configured",
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        },
                        "received": {}
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        },
                        "upgrade": {
                          "type": "boolean"
                        }
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "message"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "404": {
            "description": "App not found",
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        },
                        "received": {}
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "error": {
                          "type": "string"
                        },
                        "upgrade": {
                          "type": "boolean"
                        }
                      },
                      "required": [
                        "error"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "message"
                      ]
                    }
                  ]
                }
              }
            }
          }
        },
        "description": "Authenticated with the app's 32-char hex telemetry secret via the X-Secret header, ?secret= query, or a body `secret` field. appName may arrive via ?appName= or the body. Payload validation re-uses the route's telemetryIn schema: kind is one of error/warning/info/trace/debug (default info) and bits is any JSON value. Responds { ok: true } with 201 when accepted.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "appName": {
                    "type": "string",
                    "minLength": 1
                  },
                  "version": {
                    "type": "string"
                  },
                  "kind": {
                    "default": "info",
                    "type": "string",
                    "enum": [
                      "error",
                      "warning",
                      "info",
                      "trace",
                      "debug"
                    ]
                  },
                  "bits": {},
                  "secret": {
                    "type": "string",
                    "minLength": 1
                  }
                },
                "required": [
                  "bits"
                ]
              }
            }
          }
        }
      }
    }
  },
  "x-tools": [
    {
      "name": "list_apps",
      "description": "List published buildhut apps with substring search, org filter and pagination. Returns app summaries with dev/org, tags and platforms.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "search": {
            "type": "string"
          },
          "org": {
            "type": "string"
          },
          "page": {
            "default": 1,
            "type": "integer",
            "minimum": 1,
            "maximum": 9007199254740991
          }
        }
      }
    },
    {
      "name": "get_app",
      "description": "Fetch full detail for one app by name: builds (version, os/arch, downloads, signature availability), banner, developer and organisation info.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "description": "App name (lowercased)"
          }
        },
        "required": [
          "name"
        ]
      }
    },
    {
      "name": "start_build_upload",
      "description": "Begin a large build upload: create a multipart session (JSON, kind binary or signature). Follow up with PUTs to the returned partUrls, then POST action=complete to finalize the build record. Max 200 MB.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "action": {
            "type": "string",
            "const": "init"
          },
          "name": {
            "type": "string",
            "minLength": 1
          },
          "version": {
            "type": "string",
            "minLength": 1
          },
          "size": {
            "type": "integer",
            "minimum": 1,
            "maximum": 200000000
          },
          "contentType": {
            "type": "string",
            "minLength": 1
          },
          "kind": {
            "type": "string",
            "const": "binary"
          },
          "fileName": {
            "type": "string",
            "minLength": 1,
            "pattern": "(.([aA][pP][kK]|[aA][aA][bB]|[eE][xX][eE]|[mM][sS][iI]|[mM][sS][iI][xX]|[aA][pP][pP][iI][mM][aA][gG][eE]|[dD][eE][bB]|[rR][pP][mM]|[fF][lL][aA][tT][pP][aA][kK]|[sS][nN][aA][pP]|[aA][pP][pP][bB][uU][nN][dD][lL][eE]|[bB][iI][nN]|[tT][aA][rR]\\.[zZ][sS][tT]|[tT][aA][rR]\\.[gG][zZ]|[tT][aA][rR]\\.[xX][zZ]|[tT][gG][zZ]))$",
            "description": "Artifact file name; must end with one of: apk, aab, exe, msi, msix, appimage, deb, rpm, flatpak, snap, appbundle, bin, tar.zst, tar.gz, tar.xz, tgz"
          },
          "parts": {
            "type": "integer",
            "minimum": 1,
            "maximum": 10000
          }
        },
        "required": [
          "action",
          "name",
          "version",
          "size",
          "kind",
          "fileName"
        ]
      }
    },
    {
      "name": "authorize_build_upload",
      "description": "JSON-body alternative to the multipart form for finalizing a presigned upload: creates the DB build record for a fileName whose S3 object key (builds/...) was already PUT directly to S3.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1
          },
          "version": {
            "type": "string",
            "minLength": 1
          },
          "description": {
            "type": "string"
          },
          "fileName": {
            "type": "string",
            "minLength": 1,
            "description": "Artifact file name with its extension"
          },
          "s3Key": {
            "type": "string",
            "minLength": 1,
            "pattern": "^builds\\/",
            "description": "S3 object key, must start with builds/"
          },
          "os": {
            "type": "string"
          },
          "architecture": {
            "type": "string"
          },
          "iconMode": {
            "type": "string",
            "enum": [
              "upload",
              "url"
            ]
          },
          "iconUrl": {
            "type": "string"
          }
        },
        "required": [
          "name",
          "version",
          "fileName",
          "s3Key"
        ]
      }
    },
    {
      "name": "fetch_pgp_key",
      "description": "Look up a PGP public key on keys.openpgp.org by email or key ID/fingerprint. Returns the armored key, short key ID and uid when available.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "query": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "query"
        ]
      }
    },
    {
      "name": "submit_telemetry",
      "description": "Send one telemetry event for an app (needs its telemetry secret): kind error/warning/info/trace/debug and arbitrary JSON bits.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "appName": {
            "type": "string",
            "minLength": 1
          },
          "version": {
            "type": "string"
          },
          "kind": {
            "default": "info",
            "type": "string",
            "enum": [
              "error",
              "warning",
              "info",
              "trace",
              "debug"
            ]
          },
          "bits": {},
          "secret": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "bits"
        ]
      }
    }
  ]
}
