{
 "openapi": "3.0.3",
 "info": {
  "title": "Bramble Hub & account API",
  "version": "2026-11-13",
  "description": "The signed-in person's own account (profile, photo, password, two-step sign-in, app passwords, sessions and sign-in history, notifications, pinned apps), their organisation's basics and licences, platform search — and sign-in itself: the session endpoints, API keys and the OpenID Connect provider.\n"
 },
 "servers": [
  {
   "url": "https://{org}.brambleit.cloud/api",
   "variables": {
    "org": {
     "default": "your-org"
    }
   }
  },
  {
   "url": "https://{org}.brambleit.cloud",
   "variables": {
    "org": {
     "default": "your-org"
    }
   }
  },
  {
   "url": "https://{org}.brambleit.cloud/hub",
   "variables": {
    "org": {
     "default": "your-org"
    }
   }
  }
 ],
 "components": {
  "securitySchemes": {
   "apiKey": {
    "type": "apiKey",
    "in": "header",
    "name": "X-API-Key"
   },
   "session": {
    "type": "apiKey",
    "in": "cookie",
    "name": "sso_session"
   },
   "bearer": {
    "type": "http",
    "scheme": "bearer",
    "bearerFormat": "JWT"
   }
  }
 },
 "tags": [
  {
   "name": "Profile",
   "description": "The signed-in person's own details and photo."
  },
  {
   "name": "Password & two-step sign-in",
   "description": "Change your password; set up two-step sign-in (generate a secret, show it as a QR code, verify a code from the authenticator to switch it on); switch it off.\n"
  },
  {
   "name": "Sessions & sign-in history",
   "description": "Where you're signed in (and signing out of those), and your recent sign-ins."
  },
  {
   "name": "App passwords",
   "description": "Passwords for mail, calendar and contacts apps that can't do Bramble's two-step sign-in. Each is shown once when created, and can be revoked on its own.\n"
  },
  {
   "name": "Notifications",
   "description": "The notification centre (bell) and browser push: list and mark notifications read; register a browser for Web Push.\n"
  },
  {
   "name": "Pinned apps",
   "description": "Apps pinned to the launcher rail."
  },
  {
   "name": "Your organisation",
   "description": "Read-only views of your organisation for any member: its details, the licences it has, whether it's licensed for an app, its people, groups and domains. (Changing them is in the Admin Centre API.)\n"
  },
  {
   "name": "Search",
   "description": "Platform search across the apps you're licensed for."
  },
  {
   "name": "Sign-in",
   "description": "BRM-Auth's sign-in endpoints, used by the sign-in page and by Bramble's own apps. Passwords are sent as the **SHA3-512 hex digest** of the password (the sign-in page hashes it in the browser; Bramble stores an scrypt hash of that). A successful sign-in sets the `sso_session` and `session_id` cookies. Failed attempts are limited to 10 per account per 15 minutes.\n"
  },
  {
   "name": "API keys",
   "description": "Create, list and revoke your own API keys (the Hub account page uses these). These take the `session_id` cookie, so you create keys from a signed-in browser; the key itself is then used with `X-API-Key` everywhere else.\n"
  },
  {
   "name": "OpenID Connect",
   "description": "Bramble as an OpenID Connect provider (\"Sign in with Bramble\"): discovery, keys, authorise and consent, token (authorisation code with PKCE, refresh token, device code), device authorisation for apps without a browser, and user info. See [single sign-on](/using-the-api/authentication#single-sign-on-for-your-own-apps-openid-connect).\n"
  }
 ],
 "paths": {
  "/v1/user": {
   "get": {
    "tags": [
     "Profile"
    ],
    "summary": "Get your account",
    "operationId": "get-v1-user",
    "description": "Everything about the signed-in person — profile, organisation, roles and settings.\n\nRequires: Signed-in session, `X-API-Key`, or a Bramble app access token (`Authorization: Bearer`).",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {}
       }
      }
     },
     "404": {
      "description": "User not found"
     },
     "500": {
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "apiKey": []
     },
     {
      "session": []
     },
     {
      "bearer": []
     }
    ]
   }
  },
  "/v1/user/2fa": {
   "get": {
    "tags": [
     "Password & two-step sign-in"
    ],
    "summary": "Is two-step sign-in on?",
    "operationId": "get-v1-user-2fa",
    "description": "Requires: Signed-in session, `X-API-Key`, or a Bramble app access token (`Authorization: Bearer`).",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "totp_enabled": {}
         }
        }
       }
      }
     },
     "404": {
      "description": "User not found"
     },
     "500": {
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "apiKey": []
     },
     {
      "session": []
     },
     {
      "bearer": []
     }
    ]
   }
  },
  "/v1/user/email": {
   "get": {
    "tags": [
     "Profile"
    ],
    "summary": "Get your email address",
    "operationId": "get-v1-user-email",
    "description": "Get the users email. Returns the users primary email address used for authentication\n\nRequires: Signed-in session, `X-API-Key`, or a Bramble app access token (`Authorization: Bearer`).",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {}
       }
      }
     },
     "404": {
      "description": "User not found"
     },
     "500": {
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "apiKey": []
     },
     {
      "session": []
     },
     {
      "bearer": []
     }
    ]
   }
  },
  "/v1/user/picture": {
   "get": {
    "tags": [
     "Profile"
    ],
    "summary": "Get your photo",
    "operationId": "get-v1-user-picture",
    "description": "Requires: Signed-in session, `X-API-Key`, or a Bramble app access token (`Authorization: Bearer`).",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {}
       }
      }
     },
     "404": {
      "description": "User not found"
     },
     "500": {
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "apiKey": []
     },
     {
      "session": []
     },
     {
      "bearer": []
     }
    ]
   },
   "put": {
    "tags": [
     "Profile"
    ],
    "summary": "Set your photo",
    "operationId": "put-v1-user-picture",
    "description": "Requires: Signed-in session, `X-API-Key`, or a Bramble app access token (`Authorization: Bearer`).",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "profile_picture": {}
         }
        }
       }
      }
     },
     "404": {
      "description": "User not found"
     },
     "500": {
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "apiKey": []
     },
     {
      "session": []
     },
     {
      "bearer": []
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "image": {
          "description": "The image as a data URL (`data:image/png;base64,…`)."
         }
        }
       }
      }
     }
    }
   },
   "delete": {
    "tags": [
     "Profile"
    ],
    "summary": "Remove your photo",
    "operationId": "delete-v1-user-picture",
    "description": "Requires: Signed-in session, `X-API-Key`, or a Bramble app access token (`Authorization: Bearer`).",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "profile_picture": {}
         }
        }
       }
      }
     },
     "404": {
      "description": "User not found"
     },
     "500": {
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "apiKey": []
     },
     {
      "session": []
     },
     {
      "bearer": []
     }
    ]
   }
  },
  "/v1/user/login_history": {
   "get": {
    "tags": [
     "Sessions & sign-in history"
    ],
    "summary": "Your last 15 sign-ins",
    "operationId": "get-v1-user-login-history",
    "description": "Get the users last 15 login events. Returns the users last 15 login events\n\nRequires: Signed-in session, `X-API-Key`, or a Bramble app access token (`Authorization: Bearer`).",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "result": {}
         }
        }
       }
      }
     },
     "404": {
      "description": "Data not found"
     },
     "500": {
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "apiKey": []
     },
     {
      "session": []
     },
     {
      "bearer": []
     }
    ]
   }
  },
  "/v1/user/login_history/month": {
   "get": {
    "tags": [
     "Sessions & sign-in history"
    ],
    "summary": "Your sign-ins in the last month",
    "operationId": "get-v1-user-login-history-month",
    "description": "Get the users last 1 month of login events. Returns the users last 1 month of login events\n\nRequires: Signed-in session, `X-API-Key`, or a Bramble app access token (`Authorization: Bearer`).",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "result": {}
         }
        }
       }
      }
     },
     "404": {
      "description": "No login history found for the past 30 days"
     },
     "500": {
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "apiKey": []
     },
     {
      "session": []
     },
     {
      "bearer": []
     }
    ]
   }
  },
  "/v1/user/sessions": {
   "get": {
    "tags": [
     "Sessions & sign-in history"
    ],
    "summary": "Where you're signed in",
    "operationId": "get-v1-user-sessions",
    "description": "Get the users active authentication sessions. Returns the users active authentication sessions\n\nRequires: Signed-in session, `X-API-Key`, or a Bramble app access token (`Authorization: Bearer`).",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "result": {}
         }
        }
       }
      }
     },
     "404": {
      "description": "Data not found"
     },
     "500": {
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "apiKey": []
     },
     {
      "session": []
     },
     {
      "bearer": []
     }
    ]
   }
  },
  "/v1/user/sessions/revoke": {
   "post": {
    "tags": [
     "Sessions & sign-in history"
    ],
    "summary": "Sign out one session",
    "operationId": "post-v1-user-sessions-revoke",
    "description": "Revoke one of the user's own login sessions\n\nRequires: Signed-in session, `X-API-Key`, or a Bramble app access token (`Authorization: Bearer`).",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "message": {
           "type": "string"
          }
         }
        }
       }
      }
     },
     "400": {
      "description": "session_id is required"
     },
     "404": {
      "description": "Session not found"
     },
     "500": {
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "apiKey": []
     },
     {
      "session": []
     },
     {
      "bearer": []
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "session_id": {
          "type": "integer",
          "description": "The session to end, from `GET /v1/user/sessions`."
         }
        }
       }
      }
     }
    }
   }
  },
  "/v1/user/sessions/revoke_all": {
   "post": {
    "tags": [
     "Sessions & sign-in history"
    ],
    "summary": "Sign out everywhere",
    "operationId": "post-v1-user-sessions-revoke-all",
    "description": "Ends every session, including the one making the call.\n\nRequires: Signed-in session, `X-API-Key`, or a Bramble app access token (`Authorization: Bearer`).",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "message": {
           "type": "string"
          }
         }
        }
       }
      }
     },
     "500": {
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "apiKey": []
     },
     {
      "session": []
     },
     {
      "bearer": []
     }
    ]
   }
  },
  "/v1/user/faq/{service}": {
   "get": {
    "tags": [
     "Pinned apps"
    ],
    "summary": "Help articles for an app",
    "operationId": "get-v1-user-faq-service",
    "description": "If you want this protected, add authenticateJWT like your example: router.get(\"/faq/:service\", authenticateJWT, async (req, res) => {\n\nRequires: Signed-in session, `X-API-Key`, or a Bramble app access token (`Authorization: Bearer`).",
    "parameters": [
     {
      "name": "service",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "result": {}
         }
        }
       }
      }
     },
     "400": {
      "description": "Service is required"
     },
     "404": {
      "description": "Data not found"
     },
     "500": {
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "apiKey": []
     },
     {
      "session": []
     },
     {
      "bearer": []
     }
    ]
   }
  },
  "/v1/user/2fa/disable": {
   "post": {
    "tags": [
     "Password & two-step sign-in"
    ],
    "summary": "Switch off two-step sign-in",
    "operationId": "post-v1-user-2fa-disable",
    "description": "Disable Two-Factor Authentication (2FA) for the authenticated user\n\nRequires: Signed-in session, `X-API-Key`, or a Bramble app access token (`Authorization: Bearer`).",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "twofa": {}
         }
        }
       }
      }
     },
     "403": {
      "description": "Your organisation requires two-step sign-in (policy \"…\"), so it can't be turned off. Ask an administrator if you need help."
     },
     "404": {
      "description": "User not found"
     },
     "500": {
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "apiKey": []
     },
     {
      "session": []
     },
     {
      "bearer": []
     }
    ]
   }
  },
  "/v1/user/2fa/verify": {
   "post": {
    "tags": [
     "Password & two-step sign-in"
    ],
    "summary": "Switch on two-step sign-in",
    "operationId": "post-v1-user-2fa-verify",
    "description": "Verify a user's 2FA code and enable 2FA\n\nRequires: Signed-in session, `X-API-Key`, or a Bramble app access token (`Authorization: Bearer`).",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "message": {
           "type": "string"
          }
         }
        }
       }
      }
     },
     "400": {
      "description": "Verification code is required"
     },
     "404": {
      "description": "User not found"
     },
     "500": {
      "description": "Failed to enable 2FA"
     }
    },
    "security": [
     {
      "apiKey": []
     },
     {
      "session": []
     },
     {
      "bearer": []
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "verify_code_input": {
          "description": "The 6-digit code from the authenticator app."
         }
        },
        "required": [
         "verify_code_input"
        ]
       }
      }
     }
    }
   }
  },
  "/v1/user/2fa/generate": {
   "post": {
    "tags": [
     "Password & two-step sign-in"
    ],
    "summary": "Start setting up two-step sign-in",
    "operationId": "post-v1-user-2fa-generate",
    "description": "Returns a new secret and a QR code to scan into an authenticator app. It isn't switched on until a code is verified.\n\nRequires: Signed-in session, `X-API-Key`, or a Bramble app access token (`Authorization: Bearer`).",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "twofa": {}
         }
        }
       }
      }
     },
     "404": {
      "description": "User not found"
     },
     "500": {
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "apiKey": []
     },
     {
      "session": []
     },
     {
      "bearer": []
     }
    ]
   }
  },
  "/v1/user/app-passwords": {
   "get": {
    "tags": [
     "App passwords"
    ],
    "summary": "List your app passwords",
    "operationId": "get-v1-user-app-passwords",
    "description": "Requires: Signed-in session, `X-API-Key`, or a Bramble app access token (`Authorization: Bearer`).",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "success": {
           "type": "boolean"
          },
          "app_passwords": {
           "type": "array",
           "items": {}
          }
         }
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     },
     {
      "session": []
     },
     {
      "bearer": []
     }
    ]
   },
   "post": {
    "tags": [
     "App passwords"
    ],
    "summary": "Create an app password",
    "operationId": "post-v1-user-app-passwords",
    "description": "The password is in the response once; it can't be shown again.\n\nRequires: Signed-in session, `X-API-Key`, or a Bramble app access token (`Authorization: Bearer`).",
    "parameters": [],
    "responses": {
     "201": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "success": {
           "type": "boolean"
          },
          "app_password": {}
         }
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     },
     {
      "session": []
     },
     {
      "bearer": []
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "name": {
          "type": "string",
          "description": "What it's for, e.g. \"Phone calendar\"."
         }
        }
       }
      }
     }
    }
   }
  },
  "/v1/user/app-passwords/{id}": {
   "delete": {
    "tags": [
     "App passwords"
    ],
    "summary": "Revoke an app password",
    "operationId": "delete-v1-user-app-passwords-id",
    "description": "Requires: Signed-in session, `X-API-Key`, or a Bramble app access token (`Authorization: Bearer`).",
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "number"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "success": {
           "type": "boolean"
          }
         }
        }
       }
      }
     },
     "404": {
      "description": "App password not found"
     }
    },
    "security": [
     {
      "apiKey": []
     },
     {
      "session": []
     },
     {
      "bearer": []
     }
    ]
   }
  },
  "/v1/user/notifications": {
   "get": {
    "tags": [
     "Notifications"
    ],
    "summary": "List your notifications",
    "operationId": "get-v1-user-notifications",
    "description": "Requires: Signed-in session, `X-API-Key`, or a Bramble app access token (`Authorization: Bearer`).",
    "parameters": [
     {
      "name": "limit",
      "in": "query",
      "required": false,
      "schema": {
       "type": "integer"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "notifications": {
           "type": "array",
           "items": {
            "type": "object",
            "properties": {
             "id": {
              "type": "integer"
             },
             "app": {
              "type": "string"
             },
             "kind": {
              "type": "string"
             },
             "title": {
              "type": "string"
             },
             "body": {
              "type": "string",
              "nullable": true
             },
             "url": {
              "type": "string",
              "nullable": true
             },
             "created_at": {
              "type": "string",
              "format": "date-time"
             },
             "read_at": {
              "type": "string",
              "format": "date-time",
              "nullable": true
             }
            }
           }
          },
          "unread": {
           "type": "number"
          }
         }
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     },
     {
      "session": []
     },
     {
      "bearer": []
     }
    ]
   }
  },
  "/v1/user/notifications/read": {
   "post": {
    "tags": [
     "Notifications"
    ],
    "summary": "Mark notifications read",
    "operationId": "post-v1-user-notifications-read",
    "description": "Requires: Signed-in session, `X-API-Key`, or a Bramble app access token (`Authorization: Bearer`).",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "ok": {
           "type": "boolean"
          }
         }
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     },
     {
      "session": []
     },
     {
      "bearer": []
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "ids": {
          "type": "array",
          "items": {},
          "description": "Notification ids to mark read."
         },
         "all": {
          "description": "`true` marks every notification read."
         }
        }
       }
      }
     }
    }
   }
  },
  "/v1/user/push/key": {
   "get": {
    "tags": [
     "Notifications"
    ],
    "summary": "Get the Web Push public key",
    "operationId": "get-v1-user-push-key",
    "description": "Requires: Signed-in session, `X-API-Key`, or a Bramble app access token (`Authorization: Bearer`).",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "publicKey": {
           "type": "string"
          }
         }
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     },
     {
      "session": []
     },
     {
      "bearer": []
     }
    ]
   }
  },
  "/v1/user/push/subscribe": {
   "post": {
    "tags": [
     "Notifications"
    ],
    "summary": "Register a browser for push notifications",
    "operationId": "post-v1-user-push-subscribe",
    "description": "Requires: Signed-in session, `X-API-Key`, or a Bramble app access token (`Authorization: Bearer`).",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "ok": {
           "type": "boolean"
          }
         }
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     },
     {
      "session": []
     },
     {
      "bearer": []
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "subscription": {
          "description": "The browser's `PushSubscription` (as JSON)."
         },
         "scope": {}
        }
       }
      }
     }
    }
   }
  },
  "/v1/user/push/unsubscribe": {
   "post": {
    "tags": [
     "Notifications"
    ],
    "summary": "Stop push notifications to a browser",
    "operationId": "post-v1-user-push-unsubscribe",
    "description": "Requires: Signed-in session, `X-API-Key`, or a Bramble app access token (`Authorization: Bearer`).",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "ok": {
           "type": "boolean"
          }
         }
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     },
     {
      "session": []
     },
     {
      "bearer": []
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "endpoint": {
          "description": "The subscription's endpoint URL."
         }
        }
       }
      }
     }
    }
   }
  },
  "/user/info": {
   "get": {
    "tags": [
     "Profile"
    ],
    "summary": "Get your account (legacy)",
    "operationId": "get-user-info",
    "description": "Requires: Signed-in session, `X-API-Key`, or a Bramble app access token (`Authorization: Bearer`).",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "result": {}
         }
        }
       }
      }
     },
     "404": {
      "description": "User not found"
     },
     "500": {
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "apiKey": []
     },
     {
      "session": []
     },
     {
      "bearer": []
     }
    ]
   }
  },
  "/user/name": {
   "get": {
    "tags": [
     "Profile"
    ],
    "summary": "Get your name (legacy)",
    "operationId": "get-user-name",
    "description": "Requires: Signed-in session, `X-API-Key`, or a Bramble app access token (`Authorization: Bearer`).",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "result": {}
         }
        }
       }
      }
     },
     "404": {
      "description": "User not found"
     },
     "500": {
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "apiKey": []
     },
     {
      "session": []
     },
     {
      "bearer": []
     }
    ]
   }
  },
  "/user/email": {
   "get": {
    "tags": [
     "Profile"
    ],
    "summary": "Get your email address (legacy)",
    "operationId": "get-user-email",
    "description": "Requires: Signed-in session, `X-API-Key`, or a Bramble app access token (`Authorization: Bearer`).",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "result": {}
         }
        }
       }
      }
     },
     "404": {
      "description": "User not found"
     },
     "500": {
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "apiKey": []
     },
     {
      "session": []
     },
     {
      "bearer": []
     }
    ]
   }
  },
  "/user/2fa": {
   "get": {
    "tags": [
     "Password & two-step sign-in"
    ],
    "summary": "Is two-step sign-in on? (legacy)",
    "operationId": "get-user-2fa",
    "description": "Requires: Signed-in session, `X-API-Key`, or a Bramble app access token (`Authorization: Bearer`).",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "result": {}
         }
        }
       }
      }
     },
     "404": {
      "description": "User not found"
     },
     "500": {
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "apiKey": []
     },
     {
      "session": []
     },
     {
      "bearer": []
     }
    ]
   }
  },
  "/user/login_history": {
   "get": {
    "tags": [
     "Sessions & sign-in history"
    ],
    "summary": "Your recent sign-ins (legacy)",
    "operationId": "get-user-login-history",
    "description": "Requires: Signed-in session, `X-API-Key`, or a Bramble app access token (`Authorization: Bearer`).",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "result": {}
         }
        }
       }
      }
     },
     "404": {
      "description": "Data not found"
     },
     "500": {
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "apiKey": []
     },
     {
      "session": []
     },
     {
      "bearer": []
     }
    ]
   }
  },
  "/user/login_history/month": {
   "get": {
    "tags": [
     "Sessions & sign-in history"
    ],
    "summary": "Your sign-ins in the last month (legacy)",
    "operationId": "get-user-login-history-month",
    "description": "Requires: Signed-in session, `X-API-Key`, or a Bramble app access token (`Authorization: Bearer`).",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "result": {}
         }
        }
       }
      }
     },
     "404": {
      "description": "No login history found for the past 30 days"
     },
     "500": {
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "apiKey": []
     },
     {
      "session": []
     },
     {
      "bearer": []
     }
    ]
   }
  },
  "/user/picture": {
   "get": {
    "tags": [
     "Profile"
    ],
    "summary": "Get your photo (legacy)",
    "operationId": "get-user-picture",
    "description": "Requires: Signed-in session, `X-API-Key`, or a Bramble app access token (`Authorization: Bearer`).",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "result": {}
         }
        }
       }
      }
     },
     "404": {
      "description": "User not found"
     },
     "500": {
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "apiKey": []
     },
     {
      "session": []
     },
     {
      "bearer": []
     }
    ]
   }
  },
  "/user/2fa/generate": {
   "post": {
    "tags": [
     "Password & two-step sign-in"
    ],
    "summary": "Start setting up two-step sign-in (legacy)",
    "operationId": "post-user-2fa-generate",
    "description": "Requires: Signed-in session, `X-API-Key`, or a Bramble app access token (`Authorization: Bearer`).",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "twofa": {}
         }
        }
       }
      }
     },
     "404": {
      "description": "User not found"
     },
     "500": {
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "apiKey": []
     },
     {
      "session": []
     },
     {
      "bearer": []
     }
    ]
   }
  },
  "/user/2fa/verify": {
   "post": {
    "tags": [
     "Password & two-step sign-in"
    ],
    "summary": "Switch on two-step sign-in (legacy)",
    "operationId": "post-user-2fa-verify",
    "description": "Requires: Signed-in session, `X-API-Key`, or a Bramble app access token (`Authorization: Bearer`).",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "twofa": {}
         }
        }
       }
      }
     },
     "400": {
      "description": "Invalid Code"
     },
     "404": {
      "description": "User not found"
     },
     "500": {
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "apiKey": []
     },
     {
      "session": []
     },
     {
      "bearer": []
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "verify_code_input": {}
        }
       }
      }
     }
    }
   }
  },
  "/user/2fa/disable": {
   "post": {
    "tags": [
     "Password & two-step sign-in"
    ],
    "summary": "Switch off two-step sign-in (legacy)",
    "operationId": "post-user-2fa-disable",
    "description": "Requires: Signed-in session, `X-API-Key`, or a Bramble app access token (`Authorization: Bearer`).",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "message": {
           "type": "string"
          }
         }
        }
       }
      }
     },
     "404": {
      "description": "User not found"
     },
     "500": {
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "apiKey": []
     },
     {
      "session": []
     },
     {
      "bearer": []
     }
    ]
   }
  },
  "/user/password/change": {
   "post": {
    "tags": [
     "Password & two-step sign-in"
    ],
    "summary": "Change your password",
    "operationId": "post-user-password-change",
    "description": "Requires: Signed-in session, `X-API-Key`, or a Bramble app access token (`Authorization: Bearer`).",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "twofa": {}
         }
        }
       }
      }
     },
     "400": {
      "description": "2FA Verified"
     },
     "404": {
      "description": "User not found"
     },
     "500": {
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "apiKey": []
     },
     {
      "session": []
     },
     {
      "bearer": []
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "totp_code": {
          "description": "A code from your authenticator, if two-step sign-in is on."
         },
         "current_password": {
          "description": "Your current password."
         },
         "new_password": {
          "description": "The new password."
         }
        }
       }
      }
     }
    }
   }
  },
  "/user/pins": {
   "get": {
    "tags": [
     "Pinned apps"
    ],
    "summary": "List your pinned apps",
    "operationId": "get-user-pins",
    "description": "Pinned apps (Hub rail navigation). pin_key is either a real app's application_link (e.g. \"drive\") or the literal string \"admin\" — see BRM-Schemas/2026-07-28_user_pinned_apps.sql for why.\n\nRequires: Signed-in session, `X-API-Key`, or a Bramble app access token (`Authorization: Bearer`).",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "result": {
           "type": "array",
           "items": {
            "type": "string"
           }
          }
         }
        }
       }
      }
     },
     "404": {
      "description": "User not found"
     },
     "500": {
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "apiKey": []
     },
     {
      "session": []
     },
     {
      "bearer": []
     }
    ]
   },
   "post": {
    "tags": [
     "Pinned apps"
    ],
    "summary": "Pin an app",
    "operationId": "post-user-pins",
    "description": "Requires: Signed-in session, `X-API-Key`, or a Bramble app access token (`Authorization: Bearer`).",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "message": {
           "type": "string"
          }
         }
        }
       }
      }
     },
     "400": {
      "description": "pin_key is required"
     },
     "500": {
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "apiKey": []
     },
     {
      "session": []
     },
     {
      "bearer": []
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "pin_key": {
          "type": "string",
          "description": "The app or link to pin."
         }
        }
       }
      }
     }
    }
   }
  },
  "/user/pins/{pin_key}": {
   "delete": {
    "tags": [
     "Pinned apps"
    ],
    "summary": "Unpin an app",
    "operationId": "delete-user-pins-pin-key",
    "description": "Requires: Signed-in session, `X-API-Key`, or a Bramble app access token (`Authorization: Bearer`).",
    "parameters": [
     {
      "name": "pin_key",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "message": {
           "type": "string"
          }
         }
        }
       }
      }
     },
     "500": {
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "apiKey": []
     },
     {
      "session": []
     },
     {
      "bearer": []
     }
    ]
   }
  },
  "/v1/tenant/info": {
   "get": {
    "tags": [
     "Your organisation"
    ],
    "summary": "Get your organisation",
    "operationId": "get-v1-tenant-info",
    "description": "Requires: Signed-in session, `X-API-Key`, or a Bramble app access token (`Authorization: Bearer`).",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "tenant": {}
         }
        }
       }
      }
     },
     "404": {
      "description": "User not found"
     },
     "500": {
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "apiKey": []
     },
     {
      "session": []
     },
     {
      "bearer": []
     }
    ]
   }
  },
  "/v1/tenant/licenses": {
   "get": {
    "tags": [
     "Your organisation"
    ],
    "summary": "Your organisation's licences",
    "operationId": "get-v1-tenant-licenses",
    "description": "Requires: Signed-in session, `X-API-Key`, or a Bramble app access token (`Authorization: Bearer`).",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "user": {
           "type": "object",
           "properties": {
            "id": {
             "type": "integer"
            },
            "email": {
             "type": "string"
            }
           }
          },
          "tenant": {},
          "licensedApplications": {
           "type": "array",
           "items": {}
          }
         }
        }
       }
      }
     },
     "404": {
      "description": "User not found"
     },
     "500": {
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "apiKey": []
     },
     {
      "session": []
     },
     {
      "bearer": []
     }
    ]
   }
  },
  "/v1/tenant/check-license": {
   "post": {
    "tags": [
     "Your organisation"
    ],
    "summary": "Is the organisation licensed for an app?",
    "operationId": "post-v1-tenant-check-license",
    "description": "Requires: Signed-in session, `X-API-Key`, or a Bramble app access token (`Authorization: Bearer`).",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "message": {
           "type": "string"
          },
          "licensed": {
           "type": "boolean"
          },
          "user": {
           "type": "object",
           "properties": {
            "id": {
             "type": "integer"
            },
            "email": {
             "type": "string"
            }
           }
          },
          "tenant": {},
          "application": {
           "type": "object",
           "properties": {
            "application_id": {
             "type": "integer"
            },
            "application_name": {
             "type": "string"
            },
            "application_link": {},
            "application_logo": {}
           }
          },
          "license": {
           "type": "object",
           "properties": {
            "package_id": {
             "type": "integer"
            },
            "package_name": {
             "type": "string"
            },
            "package_description": {
             "type": "string"
            },
            "license_expiry": {}
           }
          }
         }
        }
       }
      }
     },
     "403": {
      "description": "User is not licensed for this application"
     },
     "404": {
      "description": "User not found"
     },
     "500": {
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "apiKey": []
     },
     {
      "session": []
     },
     {
      "bearer": []
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "application_id": {
          "type": "integer",
          "description": "The app's id (e.g. 2 for RMM, 7 for PSA)."
         }
        }
       }
      }
     }
    }
   }
  },
  "/v1/tenant/users": {
   "get": {
    "tags": [
     "Your organisation"
    ],
    "summary": "People in your organisation",
    "operationId": "get-v1-tenant-users",
    "description": "Requires: Signed-in session, `X-API-Key`, or a Bramble app access token (`Authorization: Bearer`).",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "users": {
           "type": "array",
           "items": {
            "type": "object",
            "properties": {
             "id": {
              "type": "integer"
             },
             "first_name": {
              "type": "string",
              "nullable": true
             },
             "last_name": {
              "type": "string",
              "nullable": true
             },
             "display_name": {
              "type": "string",
              "nullable": true
             },
             "email": {
              "type": "string"
             }
            }
           }
          }
         }
        }
       }
      }
     },
     "404": {
      "description": "User not found"
     },
     "500": {
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "apiKey": []
     },
     {
      "session": []
     },
     {
      "bearer": []
     }
    ]
   }
  },
  "/v1/tenant/groups": {
   "get": {
    "tags": [
     "Your organisation"
    ],
    "summary": "Groups in your organisation",
    "operationId": "get-v1-tenant-groups",
    "description": "Requires: Signed-in session, `X-API-Key`, or a Bramble app access token (`Authorization: Bearer`).",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "groups": {
           "type": "array",
           "items": {
            "type": "object",
            "properties": {
             "group_id": {
              "type": "integer"
             },
             "group_name": {
              "type": "string"
             },
             "members": {
              "type": "boolean"
             }
            }
           }
          }
         }
        }
       }
      }
     },
     "400": {
      "description": "tenant_id missing on token"
     },
     "500": {
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "apiKey": []
     },
     {
      "session": []
     },
     {
      "bearer": []
     }
    ]
   }
  },
  "/v1/tenant/groups/members": {
   "post": {
    "tags": [
     "Your organisation"
    ],
    "summary": "Members of a group",
    "operationId": "post-v1-tenant-groups-members",
    "description": "Requires: Signed-in session, `X-API-Key`, or a Bramble app access token (`Authorization: Bearer`).",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {}
       }
      }
     },
     "400": {
      "description": "tenant_id missing on token"
     },
     "404": {
      "description": "Group not found for this tenant"
     },
     "500": {
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "apiKey": []
     },
     {
      "session": []
     },
     {
      "bearer": []
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "group_id": {
          "type": "integer",
          "description": "The group."
         }
        },
        "required": [
         "group_id"
        ]
       }
      }
     }
    }
   }
  },
  "/v1/tenant/domains": {
   "get": {
    "tags": [
     "Your organisation"
    ],
    "summary": "Your organisation's domains",
    "operationId": "get-v1-tenant-domains",
    "description": "Requires: Signed-in session, `X-API-Key`, or a Bramble app access token (`Authorization: Bearer`).",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "data": {
           "type": "array",
           "items": {
            "type": "object",
            "properties": {
             "domain": {
              "type": "string"
             }
            }
           }
          }
         }
        }
       }
      }
     },
     "404": {
      "description": "User not found"
     },
     "500": {
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "apiKey": []
     },
     {
      "session": []
     },
     {
      "bearer": []
     }
    ]
   }
  },
  "/tenant/info": {
   "get": {
    "tags": [
     "Your organisation"
    ],
    "summary": "Get your organisation (legacy)",
    "operationId": "get-tenant-info",
    "description": "Requires: Signed-in session, `X-API-Key`, or a Bramble app access token (`Authorization: Bearer`).",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "tenant": {}
         }
        }
       }
      }
     },
     "404": {
      "description": "User not found"
     },
     "500": {
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "apiKey": []
     },
     {
      "session": []
     },
     {
      "bearer": []
     }
    ]
   }
  },
  "/tenant/licenses": {
   "get": {
    "tags": [
     "Your organisation"
    ],
    "summary": "Your organisation's licences (legacy)",
    "operationId": "get-tenant-licenses",
    "description": "Requires: Signed-in session, `X-API-Key`, or a Bramble app access token (`Authorization: Bearer`).",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "user": {
           "type": "object",
           "properties": {
            "id": {
             "type": "integer"
            },
            "email": {
             "type": "string"
            }
           }
          },
          "tenant": {},
          "licensedApplications": {
           "type": "array",
           "items": {}
          },
          "areas": {
           "type": "array",
           "items": {}
          },
          "oidcApps": {
           "type": "array",
           "items": {
            "type": "object",
            "properties": {
             "client_id": {
              "type": "string"
             },
             "name": {
              "type": "string"
             },
             "launch_url": {
              "type": "string",
              "nullable": true
             },
             "icon_url": {
              "type": "string",
              "nullable": true
             }
            }
           }
          },
          "customLinks": {
           "type": "array",
           "items": {
            "type": "object",
            "properties": {
             "id": {
              "type": "integer"
             },
             "name": {
              "type": "string"
             },
             "url": {
              "type": "string"
             },
             "icon_url": {
              "type": "string",
              "nullable": true
             }
            }
           }
          }
         }
        }
       }
      }
     },
     "404": {
      "description": "User not found"
     },
     "500": {
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "apiKey": []
     },
     {
      "session": []
     },
     {
      "bearer": []
     }
    ]
   }
  },
  "/tenant/check-license": {
   "post": {
    "tags": [
     "Your organisation"
    ],
    "summary": "Is the organisation licensed for an app? (legacy)",
    "operationId": "post-tenant-check-license",
    "description": "Requires: Signed-in session, `X-API-Key`, or a Bramble app access token (`Authorization: Bearer`).",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "message": {
           "type": "string"
          },
          "licensed": {
           "type": "boolean"
          },
          "user": {
           "type": "object",
           "properties": {
            "id": {
             "type": "integer"
            },
            "email": {
             "type": "string"
            }
           }
          },
          "tenant": {},
          "application": {
           "type": "object",
           "properties": {
            "application_id": {
             "type": "integer"
            },
            "application_name": {
             "type": "string"
            },
            "application_link": {},
            "application_logo": {}
           }
          },
          "license": {
           "type": "object",
           "properties": {
            "package_id": {
             "type": "integer"
            },
            "package_name": {
             "type": "string"
            },
            "package_description": {
             "type": "string"
            },
            "license_expiry": {}
           }
          }
         }
        }
       }
      }
     },
     "403": {
      "description": "User is not licensed for this application"
     },
     "404": {
      "description": "User not found"
     },
     "500": {
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "apiKey": []
     },
     {
      "session": []
     },
     {
      "bearer": []
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "application_id": {
          "type": "integer"
         }
        }
       }
      }
     }
    }
   }
  },
  "/v1/search": {
   "get": {
    "tags": [
     "Search"
    ],
    "summary": "Search",
    "operationId": "get-v1-search",
    "description": "Searches the apps you're licensed for and returns the best matches from each.\n\nRequires: Signed-in session, `X-API-Key`, or a Bramble app access token (`Authorization: Bearer`).",
    "parameters": [
     {
      "name": "q",
      "in": "query",
      "required": true,
      "schema": {},
      "description": "What to search for (up to 100 characters)."
     },
     {
      "name": "limit",
      "in": "query",
      "required": false,
      "schema": {
       "type": "integer"
      },
      "description": "Results per app, 1–20 (default 6)."
     }
    ],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "people": {},
          "tasks": {
           "type": "array",
           "items": {}
          },
          "devices": {
           "type": "array",
           "items": {}
          },
          "hr": {
           "type": "boolean"
          }
         }
        }
       }
      }
     },
     "500": {
      "description": "Search failed"
     }
    },
    "security": [
     {
      "apiKey": []
     },
     {
      "session": []
     },
     {
      "bearer": []
     }
    ]
   }
  },
  "/auth/mail/verify": {
   "post": {
    "tags": [
     "Sign-in"
    ],
    "summary": "Check a mail sign-in (mail server only)",
    "operationId": "post-auth-mail-verify",
    "description": "Used by Bramble's mail server to check IMAP, SMTP, CalDAV and CardDAV sign-ins. Needs the mail hook key.\n\nRequires: None: public, or protected by a token in the address or body.",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "ok": {
           "type": "boolean"
          },
          "user": {},
          "user_id": {
           "type": "integer"
          }
         }
        }
       }
      }
     }
    },
    "security": [
     {
      "session": []
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "user": {},
         "password": {},
         "service": {},
         "rip": {},
         "target": {}
        }
       }
      }
     }
    }
   }
  },
  "/auth/mail/token": {
   "post": {
    "tags": [
     "Sign-in"
    ],
    "summary": "Mail app sign-in (Bramble Mail only)",
    "operationId": "post-auth-mail-token",
    "description": "For BRM-MailApp only (X-Mail-App-Key), with the person's own session_id cookie forwarded. Returns { token, expires_at, mailbox } where mailbox is the address to sign in as.\n\nRequires: None: public, or protected by a token in the address or body.",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "token": {
           "type": "string"
          },
          "expires_at": {
           "type": "string"
          },
          "mailbox": {},
          "email": {
           "type": "string"
          }
         }
        }
       }
      }
     },
     "401": {
      "description": "Not signed in"
     },
     "403": {
      "description": "Forbidden"
     },
     "500": {
      "description": "Something went wrong"
     }
    },
    "security": [
     {
      "session": []
     }
    ]
   }
  },
  "/auth/login": {
   "post": {
    "tags": [
     "Sign-in"
    ],
    "summary": "Sign in",
    "operationId": "post-auth-login",
    "description": "Checks the password (and two-step code). On success sets the session cookies and returns where to go next. If two-step sign-in is on and `totp` is missing, answers `400 TOTP code is required`; send the same request again with the code. If a security policy requires two-step sign-in and it isn't set up yet, returns `{ mfaSetupRequired: true, setupToken }` instead.\n\n\nRequires: None: public, or protected by a token in the address or body.",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {}
       }
      }
     },
     "400": {
      "description": "TOTP code is required"
     },
     "401": {
      "description": "Invalid email or password"
     },
     "403": {
      "description": "Sign-in blocked by your organisation's security policy."
     },
     "500": {
      "description": "Internal server error"
     }
    },
    "security": [
     {
      "session": []
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "email": {
          "type": "string",
          "description": "Your username (email address)."
         },
         "shaPassword": {
          "description": "SHA3-512 hex digest of the password."
         },
         "totp": {
          "description": "The 6-digit authenticator code, when two-step sign-in is on."
         },
         "redirect": {
          "description": "Where to go after signing in."
         },
         "ip": {
          "description": "Your IP address as the page sees it (recorded in the sign-in log)."
         },
         "browser": {
          "description": "Browser name, for the sign-in log."
         },
         "platform": {
          "description": "Operating system, for the sign-in log."
         },
         "userAgent": {
          "description": "User agent, for the sign-in log."
         },
         "login_country": {
          "description": "Country, for the sign-in log."
         },
         "login_region": {
          "description": "Region, for the sign-in log."
         },
         "login_city": {
          "description": "City, for the sign-in log."
         }
        },
        "required": [
         "email",
         "shaPassword",
         "totp"
        ]
       }
      }
     }
    }
   }
  },
  "/auth/mfa/setup-generate": {
   "post": {
    "tags": [
     "Sign-in"
    ],
    "summary": "Start required two-step setup during sign-in",
    "operationId": "post-auth-mfa-setup-generate",
    "description": "Requires: None: public, or protected by a token in the address or body.",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "qrDataUrl": {
           "type": "string"
          },
          "secret": {}
         }
        }
       }
      }
     },
     "400": {
      "description": "MFA setup is not required for this account"
     },
     "401": {
      "description": "Invalid or expired setup session"
     },
     "403": {
      "description": "Sign-in blocked by your organisation's security policy."
     },
     "404": {
      "description": "User not found"
     },
     "500": {
      "description": "Internal server error"
     }
    },
    "security": [
     {
      "session": []
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "setupToken": {
          "type": "string",
          "description": "The `setupToken` from `POST /auth/login`."
         }
        }
       }
      }
     }
    }
   }
  },
  "/auth/mfa/setup-verify": {
   "post": {
    "tags": [
     "Sign-in"
    ],
    "summary": "Finish required two-step setup and sign in",
    "operationId": "post-auth-mfa-setup-verify",
    "description": "Requires: None: public, or protected by a token in the address or body.",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {}
       }
      }
     },
     "400": {
      "description": "Verification code is required"
     },
     "401": {
      "description": "Invalid or expired setup session"
     },
     "403": {
      "description": "Sign-in blocked by your organisation's security policy."
     },
     "404": {
      "description": "User not found"
     },
     "500": {
      "description": "Internal server error"
     }
    },
    "security": [
     {
      "session": []
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "setupToken": {
          "type": "string",
          "description": "The `setupToken` from `POST /auth/login`."
         },
         "code": {
          "description": "The 6-digit code from the authenticator app."
         },
         "ip": {},
         "browser": {},
         "platform": {},
         "userAgent": {},
         "login_country": {},
         "login_region": {},
         "login_city": {},
         "redirect": {}
        },
        "required": [
         "code"
        ]
       }
      }
     }
    }
   }
  },
  "/auth/forgot-password": {
   "post": {
    "tags": [
     "Sign-in"
    ],
    "summary": "Send a password reset email",
    "operationId": "post-auth-forgot-password",
    "description": "Always answers the same way, whether or not the address exists. Limited to 5 per address per hour.\n\nRequires: None: public, or protected by a token in the address or body.",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {}
       }
      }
     },
     "400": {
      "description": "Email is required"
     }
    },
    "security": [
     {
      "session": []
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "email": {
          "type": "string"
         }
        },
        "required": [
         "email"
        ]
       }
      }
     }
    }
   }
  },
  "/auth/reset-password": {
   "post": {
    "tags": [
     "Sign-in"
    ],
    "summary": "Set a new password from a reset link",
    "operationId": "post-auth-reset-password",
    "description": "Requires: None: public, or protected by a token in the address or body.",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "message": {
           "type": "string"
          }
         }
        }
       }
      }
     },
     "400": {
      "description": "Token and new password are required"
     },
     "500": {
      "description": "Internal server error"
     }
    },
    "security": [
     {
      "session": []
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "token": {
          "type": "string",
          "description": "The token from the reset email."
         },
         "shaPassword": {
          "description": "SHA3-512 hex digest of the new password."
         }
        },
        "required": [
         "token",
         "shaPassword"
        ]
       }
      }
     }
    }
   }
  },
  "/auth/register/check-slug": {
   "post": {
    "tags": [
     "Sign-in"
    ],
    "summary": "Preview an organisation's address",
    "operationId": "post-auth-register-check-slug",
    "description": "While someone types their company name at sign-up, shows the `<slug>.brambleit.cloud` address it would get.\n\nRequires: None: public, or protected by a token in the address or body.",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "domain": {
           "type": "string"
          }
         }
        }
       }
      }
     },
     "500": {
      "description": "Internal server error"
     }
    },
    "security": [
     {
      "session": []
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "company_name": {
          "type": "string"
         }
        }
       }
      }
     }
    }
   }
  },
  "/auth/find-workspace": {
   "post": {
    "tags": [
     "Sign-in"
    ],
    "summary": "Find your organisation's address",
    "operationId": "post-auth-find-workspace",
    "description": "Emails the person the sign-in address(es) for their account. Used on the shared sign-in page.\n\nRequires: None: public, or protected by a token in the address or body.",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "domain": {
           "type": "string"
          }
         }
        }
       }
      }
     },
     "400": {
      "description": "Enter a valid email address"
     },
     "404": {
      "description": "We couldn't find a workspace for that email."
     },
     "500": {
      "description": "Internal server error"
     }
    },
    "security": [
     {
      "session": []
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "email": {
          "type": "string"
         }
        }
       }
      }
     }
    }
   }
  },
  "/auth/register": {
   "post": {
    "tags": [
     "Sign-in"
    ],
    "summary": "Sign up a new organisation",
    "operationId": "post-auth-register",
    "description": "Requires: None: public, or protected by a token in the address or body.",
    "parameters": [],
    "responses": {
     "201": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "message": {
           "type": "string"
          },
          "email": {
           "type": "string"
          },
          "domain": {
           "type": "string"
          }
         }
        }
       }
      }
     },
     "400": {
      "description": "Company name is required"
     },
     "500": {
      "description": "Could not generate an available subdomain from that company name. Please try a slightly different name."
     }
    },
    "security": [
     {
      "session": []
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "company_name": {
          "type": "string"
         },
         "org_type": {
          "type": "string"
         },
         "first_name": {
          "type": "string"
         },
         "last_name": {
          "type": "string"
         },
         "recovery_email": {
          "type": "string"
         },
         "shaPassword": {},
         "terms_accepted": {}
        },
        "required": [
         "company_name",
         "first_name",
         "last_name",
         "recovery_email",
         "shaPassword",
         "terms_accepted"
        ]
       }
      }
     }
    }
   }
  },
  "/auth/verify-email": {
   "get": {
    "tags": [
     "Sign-in"
    ],
    "summary": "Confirm an email address from a sign-up link",
    "operationId": "get-auth-verify-email",
    "description": "Requires: None: public, or protected by a token in the address or body.",
    "parameters": [
     {
      "name": "token",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "File, page or redirect"
     }
    },
    "security": [
     {
      "session": []
     }
    ]
   }
  },
  "/auth/refresh": {
   "post": {
    "tags": [
     "Sign-in"
    ],
    "summary": "Renew the short-lived session token",
    "operationId": "post-auth-refresh",
    "description": "Uses the `session_id` cookie to issue a new `sso_session`. Apps call this automatically.\n\nRequires: None: public, or protected by a token in the address or body.",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "accessToken": {
           "type": "string"
          }
         }
        }
       }
      }
     }
    },
    "security": [
     {
      "session": []
     }
    ]
   }
  },
  "/auth/validate": {
   "get": {
    "tags": [
     "Sign-in"
    ],
    "summary": "Is this session still valid?",
    "operationId": "get-auth-validate",
    "description": "Requires: None: public, or protected by a token in the address or body.",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "user_type": {
           "type": "string"
          },
          "client_id": {
           "type": "integer"
          }
         }
        }
       }
      }
     }
    },
    "security": [
     {
      "session": []
     }
    ]
   }
  },
  "/auth/bridge": {
   "get": {
    "tags": [
     "Sign-in"
    ],
    "summary": "Carry a sign-in over to the organisation's address",
    "operationId": "get-auth-bridge",
    "description": "Reached via <tenant>.brambleit.cloud/auth/bridge (proxied to this service by a Pangolin target) right after a normal login on sso.cloud.brambleit.com — see the redirect logic in issueSession() above for why this hop exists. One-time, short-lived: re-issues the same session as a cookie scoped to whichever tenant domain this request actually arrived on, then continues to the originally-requested page.\n\nRequires: None: public, or protected by a token in the address or body.",
    "parameters": [
     {
      "name": "ott",
      "in": "query",
      "required": false,
      "schema": {}
     },
     {
      "name": "next",
      "in": "query",
      "required": false,
      "schema": {}
     }
    ],
    "responses": {
     "200": {
      "description": "File, page or redirect"
     }
    },
    "security": [
     {
      "session": []
     }
    ]
   }
  },
  "/auth/logout": {
   "post": {
    "tags": [
     "Sign-in"
    ],
    "summary": "Sign out",
    "operationId": "post-auth-logout",
    "description": "Requires: None: public, or protected by a token in the address or body.",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success"
     }
    },
    "security": [
     {
      "session": []
     }
    ]
   }
  },
  "/auth/logout-all": {
   "post": {
    "tags": [
     "Sign-in"
    ],
    "summary": "Sign out everywhere",
    "operationId": "post-auth-logout-all",
    "description": "Nothing on this router ever sets req.user, so the old `req.user.id` here threw on every call — resolve the user from the session cookie instead, same as /logout.\n\nRequires: None: public, or protected by a token in the address or body.",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success"
     }
    },
    "security": [
     {
      "session": []
     }
    ]
   }
  },
  "/auth/check": {
   "get": {
    "tags": [
     "Sign-in"
    ],
    "summary": "Who is signed in?",
    "operationId": "get-auth-check",
    "description": "Requires: None: public, or protected by a token in the address or body.",
    "parameters": [
     {
      "name": "redirect",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "userId": {
           "type": "integer"
          },
          "redirect": {
           "type": "string"
          }
         }
        }
       }
      }
     },
     "401": {
      "description": "Not signed in"
     },
     "500": {
      "description": "Check failed"
     }
    },
    "security": [
     {
      "session": []
     }
    ]
   }
  },
  "/auth/generate-api-key": {
   "post": {
    "tags": [
     "API keys"
    ],
    "summary": "Create an API key",
    "operationId": "post-auth-generate-api-key",
    "description": "Returns `{ apiKey }` once. It expires after 30 days. Needs the `session_id` cookie (create keys from Hub → Account → API keys).\n\nRequires: None: public, or protected by a token in the address or body.",
    "parameters": [],
    "responses": {
     "201": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "apiKey": {
           "type": "string"
          }
         }
        }
       }
      }
     },
     "500": {
      "description": "Failed to generate API key"
     }
    },
    "security": [
     {
      "session": []
     }
    ]
   }
  },
  "/auth/api-keys": {
   "get": {
    "tags": [
     "API keys"
    ],
    "summary": "List your API keys",
    "operationId": "get-auth-api-keys",
    "description": "The keys' records (created, expires, active) — never the key values.\n\nRequires: None: public, or protected by a token in the address or body.",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "apiKeys": {
           "type": "array",
           "items": {
            "type": "object",
            "properties": {
             "id": {
              "type": "integer"
             },
             "permissions": {
              "type": "object",
              "nullable": true
             },
             "is_active": {
              "type": "boolean",
              "nullable": true
             },
             "expires_at": {
              "type": "string",
              "format": "date-time",
              "nullable": true
             },
             "created_at": {
              "type": "string",
              "format": "date-time",
              "nullable": true
             }
            }
           }
          }
         }
        }
       }
      }
     },
     "500": {
      "description": "Failed to list API keys"
     }
    },
    "security": [
     {
      "session": []
     }
    ]
   }
  },
  "/auth/api-keys/{id}/revoke": {
   "post": {
    "tags": [
     "API keys"
    ],
    "summary": "Revoke an API key",
    "operationId": "post-auth-api-keys-id-revoke",
    "description": "Requires: None: public, or protected by a token in the address or body.",
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "integer"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "message": {
           "type": "string"
          }
         }
        }
       }
      }
     },
     "404": {
      "description": "API key not found"
     },
     "500": {
      "description": "Failed to revoke API key"
     }
    },
    "security": [
     {
      "session": []
     }
    ]
   }
  },
  "/.well-known/openid-configuration": {
   "get": {
    "tags": [
     "OpenID Connect"
    ],
    "summary": "OpenID Connect discovery",
    "operationId": "get-well-known-openid-configuration",
    "description": "Requires: None: public, or protected by a token in the address or body.",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "issuer": {},
          "authorization_endpoint": {
           "type": "string"
          },
          "token_endpoint": {
           "type": "string"
          },
          "userinfo_endpoint": {
           "type": "string"
          },
          "jwks_uri": {
           "type": "string"
          },
          "scopes_supported": {
           "type": "array",
           "items": {}
          },
          "response_types_supported": {
           "type": "array",
           "items": {
            "type": "string"
           }
          },
          "device_authorization_endpoint": {
           "type": "string"
          },
          "grant_types_supported": {
           "type": "array",
           "items": {
            "type": "string"
           }
          },
          "subject_types_supported": {
           "type": "array",
           "items": {
            "type": "string"
           }
          },
          "id_token_signing_alg_values_supported": {
           "type": "array",
           "items": {
            "type": "string"
           }
          },
          "token_endpoint_auth_methods_supported": {
           "type": "array",
           "items": {
            "type": "string"
           }
          },
          "code_challenge_methods_supported": {
           "type": "array",
           "items": {
            "type": "string"
           }
          },
          "claims_supported": {
           "type": "array",
           "items": {
            "type": "string"
           }
          }
         }
        }
       }
      }
     }
    },
    "security": [
     {
      "session": []
     }
    ]
   }
  },
  "/auth/oidc/jwks.json": {
   "get": {
    "tags": [
     "OpenID Connect"
    ],
    "summary": "Signing keys (JWKS)",
    "operationId": "get-auth-oidc-jwks-json",
    "description": "Requires: None: public, or protected by a token in the address or body.",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "keys": {
           "type": "array",
           "items": {}
          }
         }
        }
       }
      }
     },
     "500": {
      "description": "Internal server error"
     }
    },
    "security": [
     {
      "session": []
     }
    ]
   }
  },
  "/auth/oidc/authorize": {
   "get": {
    "tags": [
     "OpenID Connect"
    ],
    "summary": "Start sign-in for an app (authorise)",
    "operationId": "get-auth-oidc-authorize",
    "description": "The authorisation endpoint. Send the person here with `client_id`, `redirect_uri`, `response_type=code`, `scope`, `state` and (recommended) `code_challenge` + `code_challenge_method=S256`. After sign-in and consent, Bramble redirects back with `code` and `state`.\n\n\nRequires: None: public, or protected by a token in the address or body.",
    "parameters": [
     {
      "name": "client_id",
      "in": "query",
      "required": true,
      "schema": {
       "type": "integer"
      }
     },
     {
      "name": "redirect_uri",
      "in": "query",
      "required": true,
      "schema": {}
     },
     {
      "name": "response_type",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "scope",
      "in": "query",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "state",
      "in": "query",
      "required": false,
      "schema": {}
     },
     {
      "name": "code_challenge",
      "in": "query",
      "required": true,
      "schema": {}
     },
     {
      "name": "code_challenge_method",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "nonce",
      "in": "query",
      "required": false,
      "schema": {}
     }
    ],
    "responses": {
     "200": {
      "description": "File, page or redirect"
     },
     "400": {
      "description": "This app isn't set up correctly"
     },
     "403": {
      "description": "Single sign-on is turned off"
     }
    },
    "security": [
     {
      "session": []
     }
    ]
   }
  },
  "/auth/oidc/consent-info": {
   "get": {
    "tags": [
     "OpenID Connect"
    ],
    "summary": "What the consent screen should show",
    "operationId": "get-auth-oidc-consent-info",
    "description": "Requires: None: public, or protected by a token in the address or body.",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "clientName": {
           "type": "string"
          },
          "scopes": {
           "type": "array",
           "items": {}
          }
         }
        }
       }
      }
     },
     "400": {
      "description": "Consent request expired or missing"
     }
    },
    "security": [
     {
      "session": []
     }
    ]
   }
  },
  "/auth/oidc/consent": {
   "post": {
    "tags": [
     "OpenID Connect"
    ],
    "summary": "Allow or deny an app",
    "operationId": "post-auth-oidc-consent",
    "description": "Requires: None: public, or protected by a token in the address or body.",
    "parameters": [],
    "responses": {
     "200": {
      "description": "File, page or redirect"
     }
    },
    "security": [
     {
      "session": []
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "decision": {
          "type": "string",
          "description": "`allow` or `deny`."
         }
        }
       }
      }
     }
    }
   }
  },
  "/auth/oidc/token": {
   "post": {
    "tags": [
     "OpenID Connect"
    ],
    "summary": "Get tokens",
    "operationId": "post-auth-oidc-token",
    "description": "The token endpoint (form-encoded). `grant_type` is `authorization_code` (with `code`, `redirect_uri`, `code_verifier`), `refresh_token` (with `refresh_token`) or `urn:ietf:params:oauth:grant-type:device_code` (with `device_code`). Authenticate the app with `client_id` and `client_secret`. Returns `access_token`, `id_token`, `expires_in` and, where allowed, `refresh_token`.\n\n\nRequires: None: public, or protected by a token in the address or body.",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success"
     },
     "400": {
      "description": "invalid_client"
     },
     "401": {
      "description": "invalid_client"
     },
     "403": {
      "description": "access_denied"
     },
     "500": {
      "description": "server_error"
     }
    },
    "security": [
     {
      "session": []
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "grant_type": {
          "type": "string"
         }
        }
       }
      }
     }
    }
   }
  },
  "/auth/oidc/device_authorization": {
   "post": {
    "tags": [
     "OpenID Connect"
    ],
    "summary": "Start device sign-in",
    "operationId": "post-auth-oidc-device-authorization",
    "description": "For apps without a browser. Returns a `user_code` to show and a `verification_uri` where the person enters it; then poll the token endpoint with the `device_code`.\n\nRequires: None: public, or protected by a token in the address or body.",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "device_code": {},
          "user_code": {},
          "verification_uri": {},
          "verification_uri_complete": {
           "type": "string"
          },
          "expires_in": {
           "type": "number"
          },
          "interval": {
           "type": "array",
           "items": {}
          }
         }
        }
       }
      }
     },
     "400": {
      "description": "unauthorized_client"
     },
     "401": {
      "description": "invalid_client"
     },
     "500": {
      "description": "server_error"
     }
    },
    "security": [
     {
      "session": []
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "scope": {},
         "device_name": {
          "type": "string"
         }
        }
       }
      }
     }
    }
   }
  },
  "/auth/oidc/device": {
   "get": {
    "tags": [
     "OpenID Connect"
    ],
    "summary": "Under /oidc/ because BRM-Gateway proxies /oidc/* (and /auth/oidc/* on a tenant domain) on every host; a root /device isn't routed",
    "operationId": "get-auth-oidc-device",
    "description": "Under /oidc/ because BRM-Gateway proxies /oidc/* (and /auth/oidc/* on a tenant domain) on every host; a root /device isn't routed. Signed-out visitors go to /auth/, which is the login page on every gateway host.\n\nRequires: None: public, or protected by a token in the address or body.",
    "parameters": [],
    "responses": {
     "200": {
      "description": "File, page or redirect"
     }
    },
    "security": [
     {
      "session": []
     }
    ]
   }
  },
  "/auth/oidc/device/info": {
   "get": {
    "tags": [
     "OpenID Connect"
    ],
    "summary": "What a device code is for",
    "operationId": "get-auth-oidc-device-info",
    "description": "Requires: None: public, or protected by a token in the address or body.",
    "parameters": [
     {
      "name": "user_code",
      "in": "query",
      "required": false,
      "schema": {}
     }
    ],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "clientName": {
           "type": "string"
          },
          "deviceName": {
           "type": "string"
          },
          "requestedIp": {},
          "requestedAt": {
           "type": "string",
           "format": "date-time"
          },
          "scopes": {
           "type": "array",
           "items": {}
          },
          "user": {
           "type": "object",
           "properties": {
            "name": {
             "type": "string"
            },
            "email": {
             "type": "string"
            }
           }
          }
         }
        }
       }
      }
     },
     "401": {
      "description": "Sign in first."
     },
     "403": {
      "description": "Your account isn't allowed to use …. Ask your administrator."
     },
     "404": {
      "description": "That code isn't valid or has expired. Check the code on the device, or start again there."
     },
     "500": {
      "description": "Something went wrong. Try again."
     }
    },
    "security": [
     {
      "session": []
     }
    ]
   }
  },
  "/auth/oidc/device/decision": {
   "post": {
    "tags": [
     "OpenID Connect"
    ],
    "summary": "Approve or deny a device",
    "operationId": "post-auth-oidc-device-decision",
    "description": "Requires: None: public, or protected by a token in the address or body.",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "approved": {}
         }
        }
       }
      }
     },
     "401": {
      "description": "Sign in first."
     },
     "403": {
      "description": "Your account isn't allowed to use …."
     },
     "404": {
      "description": "That code isn't valid or has expired."
     },
     "409": {
      "description": "This request was already answered."
     },
     "415": {
      "description": "Unsupported request"
     },
     "500": {
      "description": "Something went wrong. Try again."
     }
    },
    "security": [
     {
      "session": []
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "user_code": {},
         "decision": {
          "type": "string"
         }
        }
       }
      }
     }
    }
   }
  },
  "/auth/oidc/userinfo": {
   "get": {
    "tags": [
     "OpenID Connect"
    ],
    "summary": "The signed-in person's claims",
    "operationId": "get-auth-oidc-userinfo",
    "description": "With the access token as `Authorization: Bearer`. Returns `sub` plus profile, email and groups claims for the scopes granted.\n\nRequires: None: public, or protected by a token in the address or body.",
    "parameters": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {}
       }
      }
     },
     "401": {
      "description": "invalid_token"
     }
    },
    "security": [
     {
      "session": []
     }
    ]
   }
  }
 }
}