Install plugin
Install a new plugin. The request body is a pluginInfo.json structure with branch and sha fields added to specify which branch and commit to install.
privacyAccepted (optional, null allowed) is the privacy block the caller showed the operator, the same field POST /plugin/{RepoName}/upgrade takes. After the clone and before any dependency or the plugin's own install script it is compared with the cloned copy's block (sends, collects, sensors, remoteAccess, systemChanges, closedCode, other): when they differ -- the listing is behind the repository, or the selected version pins an older commit -- the install is refused, the clone removed, and the reply is {Status: "Error", Code: "PrivacyMismatch", privacyChanged: true, plugin, pending} with pending the cloned block, so the caller can show it and post again with it as privacyAccepted (streaming: the same object follows on one line starting @@PRIVACY-PENDING@@). When they match, the block is recorded as accepted in config/pluginPrivacyAccepted.json once its dependencies are in place, before the plugin's own install script runs. A body without the field is compared the same way with the block recorded for that plugin by an earlier install, if any (the record survives an uninstall); with no record either, the install goes ahead and nothing is recorded, so the next update check reports privacyChanged. A dependency plugin named in dependencyPrivacyAccepted is gated the same way; with that map present, a dependency plugin not in it (declared only in the cloned copy) is refused before it is cloned, pending being its listed block. Without the map, dependencies are installed as before.
Request body
Response
Plugin installed, or refused. Refused on privacy grounds: {"Status": "Error", "Code": "PrivacyMismatch", "Message": "...", "privacyChanged": true, "plugin": "fpp-x", "pending": {...}} -- plugin is the plugin (or dependency plugin) whose block must be reviewed and pending that block (null = no disclosure). The same shape POST /api/plugin/{RepoName}/upgrade returns for its refusal.