# Create Access Request Rule Source: https://mintlify.hoop.dev/docs/api-reference/access-request-rules/create-access-request-rule https://use.hoop.dev/api/openapiv3.json post /access-requests/rules Create a new access request rule for the organization # Delete Access Request Rule Source: https://mintlify.hoop.dev/docs/api-reference/access-request-rules/delete-access-request-rule https://use.hoop.dev/api/openapiv3.json delete /access-requests/rules/{name} Delete an access request rule by name # Get Access Request Rule Source: https://mintlify.hoop.dev/docs/api-reference/access-request-rules/get-access-request-rule https://use.hoop.dev/api/openapiv3.json get /access-requests/rules/{name} Get an access request rule by ID # List Access Request Rules Source: https://mintlify.hoop.dev/docs/api-reference/access-request-rules/list-access-request-rules https://use.hoop.dev/api/openapiv3.json get /access-requests/rules List all access request rules for the organization with pagination # Update Access Request Rule Source: https://mintlify.hoop.dev/docs/api-reference/access-request-rules/update-access-request-rule https://use.hoop.dev/api/openapiv3.json put /access-requests/rules/{name} Update an access request rule by ID # Create Agent Key Source: https://mintlify.hoop.dev/docs/api-reference/agents/create-agent-key https://use.hoop.dev/api/openapiv3.json post /agents Create an agent key in a DSN format: `grpc(s)://:@:?mode=standard|embedded`. This key is used to deploy agents and expose internal resources from your infra-structure # Delete Agent Key Source: https://mintlify.hoop.dev/docs/api-reference/agents/delete-agent-key https://use.hoop.dev/api/openapiv3.json delete /agents/{nameOrID} Remove an agent key. It will invalidate a running agent # Get Agent Key Source: https://mintlify.hoop.dev/docs/api-reference/agents/get-agent-key https://use.hoop.dev/api/openapiv3.json get /agents/{nameOrID} Get an agent key by name or ID # List Agent Keys Source: https://mintlify.hoop.dev/docs/api-reference/agents/list-agent-keys https://use.hoop.dev/api/openapiv3.json get /agents List all agent keys # List Agent Tags Source: https://mintlify.hoop.dev/docs/api-reference/agents/list-agent-tags https://use.hoop.dev/api/openapiv3.json get /agent-tags List the agent tag suggestions: the predefined tags and every key/value in use on the agents of the organization. # Update Agent Tags Source: https://mintlify.hoop.dev/docs/api-reference/agents/update-agent-tags https://use.hoop.dev/api/openapiv3.json put /agents/{nameOrID}/tags Replace the tags of an agent. Send `{}` to remove all tags. No other attribute changes. # Create AI Agent Source: https://mintlify.hoop.dev/docs/api-reference/ai-agents/create-ai-agent https://use.hoop.dev/api/openapiv3.json post /ai-agents Generate a new AI Agent. The raw key is returned only once in the response and cannot be retrieved after creation. # Get AI Agent Source: https://mintlify.hoop.dev/docs/api-reference/ai-agents/get-ai-agent https://use.hoop.dev/api/openapiv3.json get /ai-agents/{nameOrID} Get an AI Agent by name or ID # List AI Agents Source: https://mintlify.hoop.dev/docs/api-reference/ai-agents/list-ai-agents https://use.hoop.dev/api/openapiv3.json get /ai-agents List all AI Agents for the organization # Reactivate AI Agent Source: https://mintlify.hoop.dev/docs/api-reference/ai-agents/reactivate-ai-agent https://use.hoop.dev/api/openapiv3.json post /ai-agents/{nameOrID}/reactivate Reactivate a revoked AI Agent. Sets status back to active and clears deactivation metadata. # Revoke AI Agent Source: https://mintlify.hoop.dev/docs/api-reference/ai-agents/revoke-ai-agent https://use.hoop.dev/api/openapiv3.json delete /ai-agents/{nameOrID} Revoke an AI Agent (soft delete). The agent status is set to revoked. # Update AI Agent Source: https://mintlify.hoop.dev/docs/api-reference/ai-agents/update-ai-agent https://use.hoop.dev/api/openapiv3.json put /ai-agents/{nameOrID} Update an AI Agent's name and/or groups. Works for both active and revoked agents. # Create AI Session Analyzer Rule Source: https://mintlify.hoop.dev/docs/api-reference/ai/create-ai-session-analyzer-rule https://use.hoop.dev/api/openapiv3.json post /ai/session-analyzer/rules Create a new AI session analyzer rule # Delete AI Session Analyzer Provider Source: https://mintlify.hoop.dev/docs/api-reference/ai/delete-ai-session-analyzer-provider https://use.hoop.dev/api/openapiv3.json delete /ai/session-analyzer/providers Delete the AI provider configured for the session analyzer feature in the organization # Delete AI Session Analyzer Rule Source: https://mintlify.hoop.dev/docs/api-reference/ai/delete-ai-session-analyzer-rule https://use.hoop.dev/api/openapiv3.json delete /ai/session-analyzer/rules/{name} Delete an AI session analyzer rule # Get AI Session Analyzer Provider Source: https://mintlify.hoop.dev/docs/api-reference/ai/get-ai-session-analyzer-provider https://use.hoop.dev/api/openapiv3.json get /ai/session-analyzer/providers Get the AI provider configured for the session analyzer feature in the organization # Get AI Session Analyzer Rule Source: https://mintlify.hoop.dev/docs/api-reference/ai/get-ai-session-analyzer-rule https://use.hoop.dev/api/openapiv3.json get /ai/session-analyzer/rules/{name} Get an AI session analyzer rule by name # Get AI Session Analyzer Rule by Connection Source: https://mintlify.hoop.dev/docs/api-reference/ai/get-ai-session-analyzer-rule-by-connection https://use.hoop.dev/api/openapiv3.json get /connections/{nameOrId}/ai-session-analyzer-rule Get the AI session analyzer rule configured for a specific connection # Get AI Session Analyzer System Prompt Source: https://mintlify.hoop.dev/docs/api-reference/ai/get-ai-session-analyzer-system-prompt https://use.hoop.dev/api/openapiv3.json get /ai/session-analyzer/system-prompt Returns the read-only system prompt that the gateway prepends before any custom_prompt configured on a rule # List AI Session Analyzer Rules Source: https://mintlify.hoop.dev/docs/api-reference/ai/list-ai-session-analyzer-rules https://use.hoop.dev/api/openapiv3.json get /ai/session-analyzer/rules List all AI session analyzer rules for the organization, optionally filtered by connection names # Update AI Session Analyzer Rule Source: https://mintlify.hoop.dev/docs/api-reference/ai/update-ai-session-analyzer-rule https://use.hoop.dev/api/openapiv3.json put /ai/session-analyzer/rules/{name} Update an existing AI session analyzer rule # Upsert AI Session Analyzer Provider Source: https://mintlify.hoop.dev/docs/api-reference/ai/upsert-ai-session-analyzer-provider https://use.hoop.dev/api/openapiv3.json post /ai/session-analyzer/providers Create or update the AI provider for the session analyzer feature in the organization (one per org) # Create API Key Source: https://mintlify.hoop.dev/docs/api-reference/api-keys/create-api-key https://use.hoop.dev/api/openapiv3.json post /api-keys Generate a new API key. The raw key is returned only once in the response and cannot be retrieved after creation. # Get API Key Source: https://mintlify.hoop.dev/docs/api-reference/api-keys/get-api-key https://use.hoop.dev/api/openapiv3.json get /api-keys/{nameOrID} Get an API key by name or ID # List API Keys Source: https://mintlify.hoop.dev/docs/api-reference/api-keys/list-api-keys https://use.hoop.dev/api/openapiv3.json get /api-keys List all API keys for the organization # Reactivate API Key Source: https://mintlify.hoop.dev/docs/api-reference/api-keys/reactivate-api-key https://use.hoop.dev/api/openapiv3.json post /api-keys/{nameOrID}/reactivate Reactivate a revoked API key. Sets status back to active and clears deactivation metadata. # Revoke API Key Source: https://mintlify.hoop.dev/docs/api-reference/api-keys/revoke-api-key https://use.hoop.dev/api/openapiv3.json delete /api-keys/{nameOrID} Revoke an API key (soft delete). The key status is set to revoked. # Update API Key Source: https://mintlify.hoop.dev/docs/api-reference/api-keys/update-api-key https://use.hoop.dev/api/openapiv3.json put /api-keys/{nameOrID} Update an API key's name and/or groups. Works for both active and revoked keys. # Get Approval Source: https://mintlify.hoop.dev/docs/api-reference/approvals/get-approval https://use.hoop.dev/api/openapiv3.json get /approvals/{id} Get an approval request by the id or session id. An approval request the user did not make and cannot decide answers 404; admins and auditors get any approval request. `/reviews/{id}` is an alias. # Get Approval Source: https://mintlify.hoop.dev/docs/api-reference/approvals/get-approval-1 https://use.hoop.dev/api/openapiv3.json get /reviews/{id} Get an approval request by the id or session id. An approval request the user did not make and cannot decide answers 404; admins and auditors get any approval request. `/reviews/{id}` is an alias. # Get Approval List Source: https://mintlify.hoop.dev/docs/api-reference/approvals/get-approval-list https://use.hoop.dev/api/openapiv3.json get /approvals Get the approval requests the user made or can decide. Admins and auditors get all approval requests. `/reviews` is an alias. # Get Approval List Source: https://mintlify.hoop.dev/docs/api-reference/approvals/get-approval-list-1 https://use.hoop.dev/api/openapiv3.json get /reviews Get the approval requests the user made or can decide. Admins and auditors get all approval requests. `/reviews` is an alias. # Update Approval Status Source: https://mintlify.hoop.dev/docs/api-reference/approvals/update-approval-status https://use.hoop.dev/api/openapiv3.json put /approvals/{id} Update the status of an approval request resource by its resource ID or session ID. This endpoint is used to approve, reject, or revoke approval requests for session execution requests. ## Overview When a user interacts with a session, an approval request resource is automatically created containing the configured approver groups, each initially set to `PENDING` status. **All groups must be approved before the session can be executed.** The approval status updates affect each approver group based on the caller's context. Once all groups are `APPROVED`, or if any group becomes `REJECTED` or `REVOKED`, the overall resource status updates accordingly. ## Approver Groups Approver groups contain individual approval entries that must be completed by authorized users from specific groups. Each entry represents a required approval from a designated approver group. ### Initial State When an approval request is created, each group entry is populated with the following structure: ```json { "id": "aaa257be-5cc9-401d-ae7e-18ae806d366a", "group": "banking", "status": "PENDING", "reviewed_by": null, "review_date": null } ``` ### Completed Approval State After an approval entry is completed, it includes the status, decision timestamp, and approver information: ```json { "id": "a546dfba-d917-4c2b-bc38-7852a7932573", "group": "banking", "status": "REJECTED", "reviewed_by": { "id": "17e4ff1a-104c-482c-be68-3c01bfc7028e", "name": "John Doe", "email": "john.doe@domain.tld", "slack_id": "" }, "review_date": "2025-05-27T16:40:05.519754143Z" } ``` ## Approval States ### User-Controlled States These states are set directly by approvers: - **`APPROVED`** - The resource has been approved by the approver - **`REJECTED`** - The resource is rejected and cannot be updated further - **`REVOKED`** - The resource is revoked and cannot be updated further ### System-Controlled States These states are managed automatically by the gateway: - **`PENDING`** - Initial state when the approval request is created - **`PROCESSING`** - Session is being executed; approval request cannot be updated - **`EXECUTED`** - Session completed successfully; approval request cannot be updated - **`UNKNOWN`** - Session executed but outcome is indeterminate - **`EXPIRED`** - A sidecar approval request passed its `expires_at` before it was decided or used; nothing was released. Only a control plane sets it ## General Rules ### Approval Permissions - An approval request the user cannot get with `GET /reviews/{id}` answers `404`, the same as an approval request that does not exist - Approvals can only be decided when the resource status is `PENDING` or `APPROVED` - **Resource owners cannot self-approve** - approval requires another member of the same group - Users are only eligible to approve if they are **not the resource owner** or are **administrators** ### Multi-Group Approvals - If a user belongs to multiple groups, separate approval entries are updated for each group - All group approvals must be completed before session execution ### Status Transitions - Setting any approval to `REJECTED` immediately changes the overall resource status and prevents further updates - `APPROVED` approval requests can still be changed to `REJECTED` at any time by the resource owner or administrators - `REVOKED` applies only to an `APPROVED` approval request of type `jit`, or to an `APPROVED` approval request a sidecar filed (it has a `listener_name`). A sidecar approval request can be revoked until the sidecar uses the approval; after that it is `EXECUTED` and the request answers `400`. A revoke of any other approval request answers `400` - Once an approval request reaches `REJECTED` or `REVOKED` the resource is considered as immutable and it cannot be updated again - A decision on a sidecar approval request past its `expires_at` answers `400` (`approval request expired`), and the approval request is `EXPIRED` ### Final States Approval requests in `PROCESSING`, `EXECUTED`, `UNKNOWN`, or `EXPIRED` states are immutable and cannot be modified. # Update Approval Status Source: https://mintlify.hoop.dev/docs/api-reference/approvals/update-approval-status-1 https://use.hoop.dev/api/openapiv3.json put /reviews/{id} Update the status of an approval request resource by its resource ID or session ID. This endpoint is used to approve, reject, or revoke approval requests for session execution requests. ## Overview When a user interacts with a session, an approval request resource is automatically created containing the configured approver groups, each initially set to `PENDING` status. **All groups must be approved before the session can be executed.** The approval status updates affect each approver group based on the caller's context. Once all groups are `APPROVED`, or if any group becomes `REJECTED` or `REVOKED`, the overall resource status updates accordingly. ## Approver Groups Approver groups contain individual approval entries that must be completed by authorized users from specific groups. Each entry represents a required approval from a designated approver group. ### Initial State When an approval request is created, each group entry is populated with the following structure: ```json { "id": "aaa257be-5cc9-401d-ae7e-18ae806d366a", "group": "banking", "status": "PENDING", "reviewed_by": null, "review_date": null } ``` ### Completed Approval State After an approval entry is completed, it includes the status, decision timestamp, and approver information: ```json { "id": "a546dfba-d917-4c2b-bc38-7852a7932573", "group": "banking", "status": "REJECTED", "reviewed_by": { "id": "17e4ff1a-104c-482c-be68-3c01bfc7028e", "name": "John Doe", "email": "john.doe@domain.tld", "slack_id": "" }, "review_date": "2025-05-27T16:40:05.519754143Z" } ``` ## Approval States ### User-Controlled States These states are set directly by approvers: - **`APPROVED`** - The resource has been approved by the approver - **`REJECTED`** - The resource is rejected and cannot be updated further - **`REVOKED`** - The resource is revoked and cannot be updated further ### System-Controlled States These states are managed automatically by the gateway: - **`PENDING`** - Initial state when the approval request is created - **`PROCESSING`** - Session is being executed; approval request cannot be updated - **`EXECUTED`** - Session completed successfully; approval request cannot be updated - **`UNKNOWN`** - Session executed but outcome is indeterminate - **`EXPIRED`** - A sidecar approval request passed its `expires_at` before it was decided or used; nothing was released. Only a control plane sets it ## General Rules ### Approval Permissions - An approval request the user cannot get with `GET /reviews/{id}` answers `404`, the same as an approval request that does not exist - Approvals can only be decided when the resource status is `PENDING` or `APPROVED` - **Resource owners cannot self-approve** - approval requires another member of the same group - Users are only eligible to approve if they are **not the resource owner** or are **administrators** ### Multi-Group Approvals - If a user belongs to multiple groups, separate approval entries are updated for each group - All group approvals must be completed before session execution ### Status Transitions - Setting any approval to `REJECTED` immediately changes the overall resource status and prevents further updates - `APPROVED` approval requests can still be changed to `REJECTED` at any time by the resource owner or administrators - `REVOKED` applies only to an `APPROVED` approval request of type `jit`, or to an `APPROVED` approval request a sidecar filed (it has a `listener_name`). A sidecar approval request can be revoked until the sidecar uses the approval; after that it is `EXECUTED` and the request answers `400`. A revoke of any other approval request answers `400` - Once an approval request reaches `REJECTED` or `REVOKED` the resource is considered as immutable and it cannot be updated again - A decision on a sidecar approval request past its `expires_at` answers `400` (`approval request expired`), and the approval request is `EXPIRED` ### Final States Approval requests in `PROCESSING`, `EXECUTED`, `UNKNOWN`, or `EXPIRED` states are immutable and cannot be modified. # Update Approval Status By Sid Source: https://mintlify.hoop.dev/docs/api-reference/approvals/update-approval-status-by-sid https://use.hoop.dev/api/openapiv3.json put /sessions/{session_id}/approval Update the status of an approval request resource by its resource ID or session ID. This endpoint is used to approve, reject, or revoke approval requests for session execution requests. ## Overview When a user interacts with a session, an approval request resource is automatically created containing the configured approver groups, each initially set to `PENDING` status. **All groups must be approved before the session can be executed.** The approval status updates affect each approver group based on the caller's context. Once all groups are `APPROVED`, or if any group becomes `REJECTED` or `REVOKED`, the overall resource status updates accordingly. ## Approver Groups Approver groups contain individual approval entries that must be completed by authorized users from specific groups. Each entry represents a required approval from a designated approver group. ### Initial State When an approval request is created, each group entry is populated with the following structure: ```json { "id": "aaa257be-5cc9-401d-ae7e-18ae806d366a", "group": "banking", "status": "PENDING", "reviewed_by": null, "review_date": null } ``` ### Completed Approval State After an approval entry is completed, it includes the status, decision timestamp, and approver information: ```json { "id": "a546dfba-d917-4c2b-bc38-7852a7932573", "group": "banking", "status": "REJECTED", "reviewed_by": { "id": "17e4ff1a-104c-482c-be68-3c01bfc7028e", "name": "John Doe", "email": "john.doe@domain.tld", "slack_id": "" }, "review_date": "2025-05-27T16:40:05.519754143Z" } ``` ## Approval States ### User-Controlled States These states are set directly by approvers: - **`APPROVED`** - The resource has been approved by the approver - **`REJECTED`** - The resource is rejected and cannot be updated further - **`REVOKED`** - The resource is revoked and cannot be updated further ### System-Controlled States These states are managed automatically by the gateway: - **`PENDING`** - Initial state when the approval request is created - **`PROCESSING`** - Session is being executed; approval request cannot be updated - **`EXECUTED`** - Session completed successfully; approval request cannot be updated - **`UNKNOWN`** - Session executed but outcome is indeterminate - **`EXPIRED`** - A sidecar approval request passed its `expires_at` before it was decided or used; nothing was released. Only a control plane sets it ## General Rules ### Approval Permissions - An approval request the user cannot get with `GET /reviews/{id}` answers `404`, the same as an approval request that does not exist - Approvals can only be decided when the resource status is `PENDING` or `APPROVED` - **Resource owners cannot self-approve** - approval requires another member of the same group - Users are only eligible to approve if they are **not the resource owner** or are **administrators** ### Multi-Group Approvals - If a user belongs to multiple groups, separate approval entries are updated for each group - All group approvals must be completed before session execution ### Status Transitions - Setting any approval to `REJECTED` immediately changes the overall resource status and prevents further updates - `APPROVED` approval requests can still be changed to `REJECTED` at any time by the resource owner or administrators - `REVOKED` applies only to an `APPROVED` approval request of type `jit`, or to an `APPROVED` approval request a sidecar filed (it has a `listener_name`). A sidecar approval request can be revoked until the sidecar uses the approval; after that it is `EXECUTED` and the request answers `400`. A revoke of any other approval request answers `400` - Once an approval request reaches `REJECTED` or `REVOKED` the resource is considered as immutable and it cannot be updated again - A decision on a sidecar approval request past its `expires_at` answers `400` (`approval request expired`), and the approval request is `EXPIRED` ### Final States Approval requests in `PROCESSING`, `EXECUTED`, `UNKNOWN`, or `EXPIRED` states are immutable and cannot be modified. # Update Approval Status By Sid Source: https://mintlify.hoop.dev/docs/api-reference/approvals/update-approval-status-by-sid-1 https://use.hoop.dev/api/openapiv3.json put /sessions/{session_id}/review Update the status of an approval request resource by its resource ID or session ID. This endpoint is used to approve, reject, or revoke approval requests for session execution requests. ## Overview When a user interacts with a session, an approval request resource is automatically created containing the configured approver groups, each initially set to `PENDING` status. **All groups must be approved before the session can be executed.** The approval status updates affect each approver group based on the caller's context. Once all groups are `APPROVED`, or if any group becomes `REJECTED` or `REVOKED`, the overall resource status updates accordingly. ## Approver Groups Approver groups contain individual approval entries that must be completed by authorized users from specific groups. Each entry represents a required approval from a designated approver group. ### Initial State When an approval request is created, each group entry is populated with the following structure: ```json { "id": "aaa257be-5cc9-401d-ae7e-18ae806d366a", "group": "banking", "status": "PENDING", "reviewed_by": null, "review_date": null } ``` ### Completed Approval State After an approval entry is completed, it includes the status, decision timestamp, and approver information: ```json { "id": "a546dfba-d917-4c2b-bc38-7852a7932573", "group": "banking", "status": "REJECTED", "reviewed_by": { "id": "17e4ff1a-104c-482c-be68-3c01bfc7028e", "name": "John Doe", "email": "john.doe@domain.tld", "slack_id": "" }, "review_date": "2025-05-27T16:40:05.519754143Z" } ``` ## Approval States ### User-Controlled States These states are set directly by approvers: - **`APPROVED`** - The resource has been approved by the approver - **`REJECTED`** - The resource is rejected and cannot be updated further - **`REVOKED`** - The resource is revoked and cannot be updated further ### System-Controlled States These states are managed automatically by the gateway: - **`PENDING`** - Initial state when the approval request is created - **`PROCESSING`** - Session is being executed; approval request cannot be updated - **`EXECUTED`** - Session completed successfully; approval request cannot be updated - **`UNKNOWN`** - Session executed but outcome is indeterminate - **`EXPIRED`** - A sidecar approval request passed its `expires_at` before it was decided or used; nothing was released. Only a control plane sets it ## General Rules ### Approval Permissions - An approval request the user cannot get with `GET /reviews/{id}` answers `404`, the same as an approval request that does not exist - Approvals can only be decided when the resource status is `PENDING` or `APPROVED` - **Resource owners cannot self-approve** - approval requires another member of the same group - Users are only eligible to approve if they are **not the resource owner** or are **administrators** ### Multi-Group Approvals - If a user belongs to multiple groups, separate approval entries are updated for each group - All group approvals must be completed before session execution ### Status Transitions - Setting any approval to `REJECTED` immediately changes the overall resource status and prevents further updates - `APPROVED` approval requests can still be changed to `REJECTED` at any time by the resource owner or administrators - `REVOKED` applies only to an `APPROVED` approval request of type `jit`, or to an `APPROVED` approval request a sidecar filed (it has a `listener_name`). A sidecar approval request can be revoked until the sidecar uses the approval; after that it is `EXECUTED` and the request answers `400`. A revoke of any other approval request answers `400` - Once an approval request reaches `REJECTED` or `REVOKED` the resource is considered as immutable and it cannot be updated again - A decision on a sidecar approval request past its `expires_at` answers `400` (`approval request expired`), and the approval request is `EXPIRED` ### Final States Approval requests in `PROCESSING`, `EXECUTED`, `UNKNOWN`, or `EXPIRED` states are immutable and cannot be modified. # Create Attribute Source: https://mintlify.hoop.dev/docs/api-reference/attributes/create-attribute https://use.hoop.dev/api/openapiv3.json post /attributes Create a new attribute for the organization. # Delete Attribute Source: https://mintlify.hoop.dev/docs/api-reference/attributes/delete-attribute https://use.hoop.dev/api/openapiv3.json delete /attributes/{name} Delete an attribute by name or ID. # Get Attribute Source: https://mintlify.hoop.dev/docs/api-reference/attributes/get-attribute https://use.hoop.dev/api/openapiv3.json get /attributes/{name} Get an attribute by name or ID. # List Attributes Source: https://mintlify.hoop.dev/docs/api-reference/attributes/list-attributes https://use.hoop.dev/api/openapiv3.json get /attributes List attributes for the organization with optional pagination and search. # Update Attribute Source: https://mintlify.hoop.dev/docs/api-reference/attributes/update-attribute https://use.hoop.dev/api/openapiv3.json put /attributes/{name} Rename an existing attribute. # List security audit logs Source: https://mintlify.hoop.dev/docs/api-reference/audit-logs/list-security-audit-logs https://use.hoop.dev/api/openapiv3.json get /audit/logs Lists security audit log entries for the organization. Only admins can access this API. Supports filtering by actor, resource type, action, HTTP method, HTTP status, client IP, path, outcome, and date range. Results are ordered by created_at descending. # Local | Login Source: https://mintlify.hoop.dev/docs/api-reference/authentication/local-|-login https://use.hoop.dev/api/openapiv3.json get /localauth/login Generate a new access token to interact with the API that expires in 12 hours. # Local | Register User Source: https://mintlify.hoop.dev/docs/api-reference/authentication/local-|-register-user https://use.hoop.dev/api/openapiv3.json post /localauth/register It registers a new user in the system with the provided email and password. Additionall users are only registered when they are invited by an existing admin user. # OIDC | Login Source: https://mintlify.hoop.dev/docs/api-reference/authentication/oidc-|-login https://use.hoop.dev/api/openapiv3.json get /login Returns the login url to perform the signin on the identity provider # OIDC | Login Callback Source: https://mintlify.hoop.dev/docs/api-reference/authentication/oidc-|-login-callback https://use.hoop.dev/api/openapiv3.json get /callback Exchanges and validates the authorization code for an access token after being redirect by the external provider. A success authentication will redirect the user back to the default redirect url provided in the /login route. In case of error it will include the query string `error=unexpected_error` when redirecting. # OIDC | Signup Source: https://mintlify.hoop.dev/docs/api-reference/authentication/oidc-|-signup https://use.hoop.dev/api/openapiv3.json post /signup Signup anonymous authenticated user. This endpoint is only used for multi tenant setups. # SAML | Login Source: https://mintlify.hoop.dev/docs/api-reference/authentication/saml-|-login https://use.hoop.dev/api/openapiv3.json get /saml/login Returns the login url to perform the signin on the identity provider. # SAML | Login Callback Source: https://mintlify.hoop.dev/docs/api-reference/authentication/saml-|-login-callback https://use.hoop.dev/api/openapiv3.json post /saml/callback It redirects the user to the redirect URL with a JWT access token on success. A success authentication will redirect the user back to the default redirect url provided in the /saml/login route. In case of error it will include the query string error= when redirecting. # Create Database Role Job Source: https://mintlify.hoop.dev/docs/api-reference/aws/create-database-role-job https://use.hoop.dev/api/openapiv3.json post /dbroles/jobs It creates a job that performs the provisioning of default database roles # Create RDS Root Password Source: https://mintlify.hoop.dev/docs/api-reference/aws/create-rds-root-password https://use.hoop.dev/api/openapiv3.json post /integrations/aws/rds/credentials It creates password for RDS instances that is used to reset the root password when executing the database role job. The password are used only once and expire after 30 minutes. # Delete IAM Access Key Source: https://mintlify.hoop.dev/docs/api-reference/aws/delete-iam-access-key https://use.hoop.dev/api/openapiv3.json delete /integrations/aws/iam/accesskeys Remove IAM Access Key from memory # Get Caller Identity Source: https://mintlify.hoop.dev/docs/api-reference/aws/get-caller-identity https://use.hoop.dev/api/openapiv3.json get /integrations/aws/iam/userinfo It obtain the aws identity of the instance role or credentials # Get DB Role Job Source: https://mintlify.hoop.dev/docs/api-reference/aws/get-db-role-job https://use.hoop.dev/api/openapiv3.json get /dbroles/jobs/{id} Get DB Role job by id # List AWS Accounts Source: https://mintlify.hoop.dev/docs/api-reference/aws/list-aws-accounts https://use.hoop.dev/api/openapiv3.json get /integrations/aws/organizations It list all AWS accounts associated with the access key credentials # List Database Instances Source: https://mintlify.hoop.dev/docs/api-reference/aws/list-database-instances https://use.hoop.dev/api/openapiv3.json post /integrations/aws/rds/describe-db-instances It list RDS Database Instances # List DB Role Jobs Source: https://mintlify.hoop.dev/docs/api-reference/aws/list-db-role-jobs https://use.hoop.dev/api/openapiv3.json get /dbroles/jobs List all db role jobs # Update IAM Access Key Source: https://mintlify.hoop.dev/docs/api-reference/aws/update-iam-access-key https://use.hoop.dev/api/openapiv3.json put /integrations/aws/iam/accesskeys Update IAM Access Key or set a region when using IAM instance role # Close Connection Credentials Session Source: https://mintlify.hoop.dev/docs/api-reference/connections/close-connection-credentials-session https://use.hoop.dev/api/openapiv3.json post /connections/{nameOrID}/credentials/{credentialID}/close Ends the current audit session for a credential and tears down any active proxy connections, but keeps the credential itself usable. The stored token is preserved so the next credential request for the same (user, connection) pair returns the same value. For explicit token invalidation use the revoke endpoint. # Create Connection Source: https://mintlify.hoop.dev/docs/api-reference/connections/create-connection https://use.hoop.dev/api/openapiv3.json post /connections The connection resource allows exposing internal services from your internal infra structure to users. ### Types of Connections The definition of this resource represent how clients will be able to interact with internal resources. Each type/subtype may represent a distinct implementation: - `application/` - An alias to map distinct types of shell applications (e.g.: python, ruby, etc) - `application/tcp` - Forward TCP connections This type requires the following environment variables: - `HOST`: ip or dns of the internal service - `PORT`: the port of the internal service - `custom` - Any custom shell application - `database/` - Allow connecting to databases through multiple clients (Webapp, cli, IDE's) Each `` has distinct environment variables that are allowed to be configured, refer to our [documentation](https://hoop.dev/docs) for more information. ### Tags Tags are key/value pairs that are attached to objects such as Connections. Tags are intended to be used to specify identifying attributes of objects that are meaningful and relevant to users, but do not directly imply semantics to the core system. ```json { "connection_tags": { "environment": "production", "component": "backend" } } ``` Equality- or inequality-based requirements allow filtering by tags keys and values. Matching objects must satisfy all of the specified tag constraints, though they may have additional tags as well. Three kinds of operators are admitted `=`,`!=`. The first represent equality, while the last represents inequality. For example: ``` environment = production tier != frontend ``` The former selects all resources with key equal to `environment` and value equal to `production`. The latter selects all resources with key equal to `tier` and value distinct from `frontend`. One could filter for resources in production excluding frontend using the comma operator: environment=production,tier!=frontend # Create Connection Credentials Source: https://mintlify.hoop.dev/docs/api-reference/connections/create-connection-credentials https://use.hoop.dev/api/openapiv3.json post /connections/{nameOrID}/credentials Create Connection Credentials # Delete Connection Source: https://mintlify.hoop.dev/docs/api-reference/connections/delete-connection https://use.hoop.dev/api/openapiv3.json delete /connections/{nameOrID} Delete a connection resource. A connection that mirrors a sidecar listener answers 409: remove the listener from the sidecar instead. # Delete Federation Configuration for a Connection Source: https://mintlify.hoop.dev/docs/api-reference/connections/delete-federation-configuration-for-a-connection https://use.hoop.dev/api/openapiv3.json delete /connections/{nameOrID}/federation Removes the IAM federation configuration for a connection. Subsequent sessions on this connection revert to the static connection envs. # Get Active Connection Credentials Source: https://mintlify.hoop.dev/docs/api-reference/connections/get-active-connection-credentials https://use.hoop.dev/api/openapiv3.json get /connections/{nameOrID}/credentials Returns the current active, non-expired credentials for the authenticated user on the given connection without creating a new session. Returns 404 if no active credentials exist or they have expired. # Get Connection Source: https://mintlify.hoop.dev/docs/api-reference/connections/get-connection https://use.hoop.dev/api/openapiv3.json get /connections/{nameOrID} Get resource by name or id # Get Federation Configuration for a Connection Source: https://mintlify.hoop.dev/docs/api-reference/connections/get-federation-configuration-for-a-connection https://use.hoop.dev/api/openapiv3.json get /connections/{nameOrID}/federation Returns the IAM federation configuration for a connection. The admin credentials are never returned in plaintext; only a presence indicator is included. # Get Table Columns Source: https://mintlify.hoop.dev/docs/api-reference/connections/get-table-columns https://use.hoop.dev/api/openapiv3.json get /connections/{nameOrID}/columns Get columns from a specific table # List Active Connection Credentials Source: https://mintlify.hoop.dev/docs/api-reference/connections/list-active-connection-credentials https://use.hoop.dev/api/openapiv3.json get /connection-credentials Returns the authenticated user's active (non-revoked, non-expired) credentials, AT MOST ONE PER CONNECTION. Several rows can be live for the same connection — issuing reuses the existing credential while resuming an approved request mints a parallel one — so the list resolves them the same way the rest of the API does: the credential still attached to a session first, then the most recently created. Use GET /connections/{nameOrID}/credentials for the full set on a single connection. The response is secret-less: it never includes the connection_credentials payload (hostnames, usernames, passwords, proxy tokens). # List Connection Tags Source: https://mintlify.hoop.dev/docs/api-reference/connections/list-connection-tags https://use.hoop.dev/api/openapiv3.json get /connections-tags List all Connection Tags. # List Connections Source: https://mintlify.hoop.dev/docs/api-reference/connections/list-connections https://use.hoop.dev/api/openapiv3.json get /connections List all connections. # List Database Tables Source: https://mintlify.hoop.dev/docs/api-reference/connections/list-database-tables https://use.hoop.dev/api/openapiv3.json get /connections/{nameOrID}/tables List tables from a database without column details # List Databases Source: https://mintlify.hoop.dev/docs/api-reference/connections/list-databases https://use.hoop.dev/api/openapiv3.json get /connections/{nameOrID}/databases List all available databases for a database connection # List MCP Server Catalog Source: https://mintlify.hoop.dev/docs/api-reference/connections/list-mcp-server-catalog https://use.hoop.dev/api/openapiv3.json get /mcp-catalog List the built-in catalog of publicly hosted remote MCP servers. Used by the connection create page to pre-fill an `mcpproxy` connection's endpoint, transport and auth mode from a picker. # OAuth callback for MCP connection login Source: https://mintlify.hoop.dev/docs/api-reference/connections/oauth-callback-for-mcp-connection-login https://use.hoop.dev/api/openapiv3.json get /mcp-oauth/callback The upstream authorization server's redirect target. Validates the state issued by the authorize endpoint, exchanges the authorization code for an access token, stores it on the flow row, and redirects the browser back to the connection create page with mcp_oauth=success|error and the flow_id. This endpoint is unauthenticated but state-validated, and is not called directly by clients. # Patch Connection Source: https://mintlify.hoop.dev/docs/api-reference/connections/patch-connection https://use.hoop.dev/api/openapiv3.json patch /connections/{nameOrID} Partial update of a connection resource. Only provided fields will be updated. # Resume Connection Credentials Request Source: https://mintlify.hoop.dev/docs/api-reference/connections/resume-connection-credentials-request https://use.hoop.dev/api/openapiv3.json post /connections/{nameOrID}/credentials/{sessionID} Resume a connection credentials request after approval # Retrieve the token obtained by an MCP OAuth login Source: https://mintlify.hoop.dev/docs/api-reference/connections/retrieve-the-token-obtained-by-an-mcp-oauth-login https://use.hoop.dev/api/openapiv3.json get /mcp-oauth/token/{flowID} Returns the access token obtained by a completed MCP OAuth login so the connection create page can freeze it into the connection's HEADER_AUTHORIZATION configuration. The token is returned at most once: the flow row is deleted on read. # Revoke Connection Credentials Source: https://mintlify.hoop.dev/docs/api-reference/connections/revoke-connection-credentials https://use.hoop.dev/api/openapiv3.json post /connections/{nameOrID}/credentials/{credentialID}/revoke Revokes a connection credential, invalidating the stored token and disconnecting any active sessions. The next credential request for the same (user, connection) pair will issue a fresh token. # Start the OAuth login flow for an MCP connection Source: https://mintlify.hoop.dev/docs/api-reference/connections/start-the-oauth-login-flow-for-an-mcp-connection https://use.hoop.dev/api/openapiv3.json post /mcp-oauth/authorize Discovers the MCP server's authorization server (RFC 9728 / RFC 8414), optionally performs Dynamic Client Registration (RFC 7591) when no client credentials are supplied, and returns the authorization URL for the admin's browser to complete an Authorization Code + PKCE login. The browser is redirected there; the upstream provider redirects back to the gateway callback, which exchanges the code for a token. Used by the connection create page. # Test Connection Source: https://mintlify.hoop.dev/docs/api-reference/connections/test-connection https://use.hoop.dev/api/openapiv3.json get /connections/{nameOrID}/test Test resource by name or id (only for database connections, it will attempt a simple ping). # Update Connection Source: https://mintlify.hoop.dev/docs/api-reference/connections/update-connection https://use.hoop.dev/api/openapiv3.json put /connections/{nameOrID} Update a connection resource # Update Data Masking Rule Connections Source: https://mintlify.hoop.dev/docs/api-reference/connections/update-data-masking-rule-connections https://use.hoop.dev/api/openapiv3.json put /connections/{nameOrID}/datamasking-rules Update Data Masking Rule Connections # Upsert Federation Configuration for a Connection Source: https://mintlify.hoop.dev/docs/api-reference/connections/upsert-federation-configuration-for-a-connection https://use.hoop.dev/api/openapiv3.json put /connections/{nameOrID}/federation Creates or updates the IAM federation configuration for a connection. AdminCredentialsJSON is write-only; omit on update to preserve the stored value. # Create Data Masking Rule Source: https://mintlify.hoop.dev/docs/api-reference/data-masking-rules/create-data-masking-rule https://use.hoop.dev/api/openapiv3.json post /datamasking-rules Create Data Masking Rule # Delete Data Masking Rule Source: https://mintlify.hoop.dev/docs/api-reference/data-masking-rules/delete-data-masking-rule https://use.hoop.dev/api/openapiv3.json delete /datamasking-rules/{id} Delete a Data Masking Rule resource. # Get Data Masking Rule Source: https://mintlify.hoop.dev/docs/api-reference/data-masking-rules/get-data-masking-rule https://use.hoop.dev/api/openapiv3.json get /datamasking-rules/{id} Get Data Masking Rule # List Data Masking Rules Source: https://mintlify.hoop.dev/docs/api-reference/data-masking-rules/list-data-masking-rules https://use.hoop.dev/api/openapiv3.json get /datamasking-rules List Data Masking Rules # Update Data Masking Rule Source: https://mintlify.hoop.dev/docs/api-reference/data-masking-rules/update-data-masking-rule https://use.hoop.dev/api/openapiv3.json put /datamasking-rules/{id} Update Data Masking Rule # List Feature Flags Source: https://mintlify.hoop.dev/docs/api-reference/feature-flags/list-feature-flags https://use.hoop.dev/api/openapiv3.json get /feature-flags List all feature flags from the catalog with their per-org state # Update Feature Flag Source: https://mintlify.hoop.dev/docs/api-reference/feature-flags/update-feature-flag https://use.hoop.dev/api/openapiv3.json put /feature-flags/{name} Enable or disable a feature flag for the organization # Feature Update Source: https://mintlify.hoop.dev/docs/api-reference/features/feature-update https://use.hoop.dev/api/openapiv3.json put /orgs/features Updates a feature configuration. It will report if this feature is available in the user info endpoint. # Get Webhooks Dashboard Source: https://mintlify.hoop.dev/docs/api-reference/features/get-webhooks-dashboard https://use.hoop.dev/api/openapiv3.json get /webhooks-dashboard Get webhooks dashboard url # OpenAI Chat Completions Source: https://mintlify.hoop.dev/docs/api-reference/features/openai-chat-completions https://use.hoop.dev/api/openapiv3.json post /features/ask-ai/v1/chat/completions Proxy to OpenAI chat completions `/vi/chat/completions` # Disconnect a user's Google account from a connection Source: https://mintlify.hoop.dev/docs/api-reference/federation/disconnect-a-users-google-account-from-a-connection https://use.hoop.dev/api/openapiv3.json delete /connections/{nameOrID}/federation/oauth Deletes the authenticated user's stored Google refresh token for a gcp_oauth-federated connection. Subsequent sessions fail until the user re-consents. # Google OAuth callback for connection federation Source: https://mintlify.hoop.dev/docs/api-reference/federation/google-oauth-callback-for-connection-federation https://use.hoop.dev/api/openapiv3.json get /federation/oauth/callback Google's OAuth redirect target. Validates the state issued by the authorize endpoint, exchanges the authorization code for a refresh token, stores it for the user/connection, and redirects the browser back to the application with federation_oauth=success|error. This endpoint is unauthenticated but state-validated, and is not called directly by clients. # Report the user's per-user federation connection status Source: https://mintlify.hoop.dev/docs/api-reference/federation/report-the-users-per-user-federation-connection-status https://use.hoop.dev/api/openapiv3.json get /connections/{nameOrID}/federation/oauth Reports, for the authenticated user, whether they have connected a per-user account (e.g. their Google account for gcp_oauth) to a connection. Clients use this to decide whether to prompt the user to connect before running. Access is scoped to connections the user is allowed to run. # Start the Google OAuth consent flow for a connection Source: https://mintlify.hoop.dev/docs/api-reference/federation/start-the-google-oauth-consent-flow-for-a-connection https://use.hoop.dev/api/openapiv3.json get /connections/{nameOrID}/federation/oauth/authorize Returns the Google consent URL for the authenticated user to connect their Google account to a gcp_oauth-federated connection. The browser should be redirected to the returned URL; Google redirects back to the gateway callback, which stores the resulting refresh token. # Test a Federation Configuration End-to-End Source: https://mintlify.hoop.dev/docs/api-reference/federation/test-a-federation-configuration-end-to-end https://use.hoop.dev/api/openapiv3.json post /federation/test Resolves the candidate federation configuration against a synthetic user AND dispatches a one-shot smoke probe (the caller-supplied test_script, e.g. "SELECT 1") to the agent identified in the request body. Persisted state is never read or written: the entire candidate connection + federation pair lives in the body. Returns the resolved principal, the env-var keys that were injected (values are never returned), and the agent-side stdout/stderr of the probe. Success requires both phases to succeed. # Create Guard Rail Rules Source: https://mintlify.hoop.dev/docs/api-reference/guard-rails/create-guard-rail-rules https://use.hoop.dev/api/openapiv3.json post /guardrails Create Guard Rail Rules # Delete a Rule Source: https://mintlify.hoop.dev/docs/api-reference/guard-rails/delete-a-rule https://use.hoop.dev/api/openapiv3.json delete /guardrails/{id} Delete a Guard Rail Rule resource. # Get Guard Rail Rules Source: https://mintlify.hoop.dev/docs/api-reference/guard-rails/get-guard-rail-rules https://use.hoop.dev/api/openapiv3.json get /guardrails/{id} Get Guard Rail Rules # List Guard Rail Rules Source: https://mintlify.hoop.dev/docs/api-reference/guard-rails/list-guard-rail-rules https://use.hoop.dev/api/openapiv3.json get /guardrails List Guard Rail Rules # Update Guard Rail Rules Source: https://mintlify.hoop.dev/docs/api-reference/guard-rails/update-guard-rail-rules https://use.hoop.dev/api/openapiv3.json put /guardrails/{id} Update Guard Rail Rules # Create Issue Templates Source: https://mintlify.hoop.dev/docs/api-reference/jira/create-issue-templates https://use.hoop.dev/api/openapiv3.json post /integrations/jira/issuetemplates Create Issue Templates # Create Jira Integration Source: https://mintlify.hoop.dev/docs/api-reference/jira/create-jira-integration https://use.hoop.dev/api/openapiv3.json post /integrations/jira Create a new Jira integration for the organization # Delete Issue Templates Source: https://mintlify.hoop.dev/docs/api-reference/jira/delete-issue-templates https://use.hoop.dev/api/openapiv3.json delete /integrations/jira/issuetemplates/{id} Delete Issue Templates # Get Asset Field Configurations Source: https://mintlify.hoop.dev/docs/api-reference/jira/get-asset-field-configurations https://use.hoop.dev/api/openapiv3.json get /integrations/jira/assets/fieldconfigs Get the AQL configuration of Jira Service Management (JSM) Assets custom fields. These are the object scope and dependent-field (issue scope) filters Jira's own portal applies; they drive the CMDB dropdown cascade. Fields without any configured filter are omitted. # Get Asset Objects Source: https://mintlify.hoop.dev/docs/api-reference/jira/get-asset-objects https://use.hoop.dev/api/openapiv3.json get /integrations/jira/assets/objects Get objects from the Jira Service Management (JSM) Assets API # Get Issue Templates Source: https://mintlify.hoop.dev/docs/api-reference/jira/get-issue-templates https://use.hoop.dev/api/openapiv3.json get /integrations/jira/issuetemplates/{id} Get Issue Templates # Get Jira Integration Source: https://mintlify.hoop.dev/docs/api-reference/jira/get-jira-integration https://use.hoop.dev/api/openapiv3.json get /integrations/jira Get Jira integration for the organization # List Issue Templates Source: https://mintlify.hoop.dev/docs/api-reference/jira/list-issue-templates https://use.hoop.dev/api/openapiv3.json get /integrations/jira/issuetemplates List Issue Templates # Update Issue Templates Source: https://mintlify.hoop.dev/docs/api-reference/jira/update-issue-templates https://use.hoop.dev/api/openapiv3.json put /integrations/jira/issuetemplates/{id} Update Issue Templates # Update Jira Integration Source: https://mintlify.hoop.dev/docs/api-reference/jira/update-jira-integration https://use.hoop.dev/api/openapiv3.json put /integrations/jira Update the Jira integration for the organization # Stream Live Events Source: https://mintlify.hoop.dev/docs/api-reference/live-events/stream-live-events https://use.hoop.dev/api/openapiv3.json get /events/stream Streams change notices of the organization via SSE, one "event: " frame per change, with {"type","id"} as data. A notice names what changed and never its content: read the resource again through its own route. Types: sidecar.checked_in. # Create Machine Identity Source: https://mintlify.hoop.dev/docs/api-reference/machine-identities/create-machine-identity https://use.hoop.dev/api/openapiv3.json post /machineidentities Create a machine identity (non-human identity) with native credentials for each connection # Delete Machine Identity Source: https://mintlify.hoop.dev/docs/api-reference/machine-identities/delete-machine-identity https://use.hoop.dev/api/openapiv3.json delete /machineidentities/{name} Delete a machine identity and revoke all associated credentials # Get Machine Identity Source: https://mintlify.hoop.dev/docs/api-reference/machine-identities/get-machine-identity https://use.hoop.dev/api/openapiv3.json get /machineidentities/{name} Get a machine identity by name # List Machine Identities Source: https://mintlify.hoop.dev/docs/api-reference/machine-identities/list-machine-identities https://use.hoop.dev/api/openapiv3.json get /machineidentities List all machine identities (non-human identities) # List Machine Identity Credentials Source: https://mintlify.hoop.dev/docs/api-reference/machine-identities/list-machine-identity-credentials https://use.hoop.dev/api/openapiv3.json get /machineidentities/{name}/credentials List full credential details for a machine identity including connection strings and secret keys # Rotate Machine Identity Credential Source: https://mintlify.hoop.dev/docs/api-reference/machine-identities/rotate-machine-identity-credential https://use.hoop.dev/api/openapiv3.json post /machineidentities/{name}/credentials/{connectionName}/rotate Rotate (regenerate) a credential for a specific connection. The old credential is revoked and a new one is returned. # Update Machine Identity Source: https://mintlify.hoop.dev/docs/api-reference/machine-identities/update-machine-identity https://use.hoop.dev/api/openapiv3.json put /machineidentities/{name} Update a machine identity. Adding connections provisions new credentials; removing connections revokes them. # Create Org Key Source: https://mintlify.hoop.dev/docs/api-reference/organization-management/create-org-key https://use.hoop.dev/api/openapiv3.json post /orgs/keys Create the organization key to run with `hoop run` command line. # Get Org Key Source: https://mintlify.hoop.dev/docs/api-reference/organization-management/get-org-key https://use.hoop.dev/api/openapiv3.json get /orgs/keys Get the organization key to run with `hoop run` command line # Revoke Org Key Source: https://mintlify.hoop.dev/docs/api-reference/organization-management/revoke-org-key https://use.hoop.dev/api/openapiv3.json delete /orgs/keys Remove organization key # Create Plugin Source: https://mintlify.hoop.dev/docs/api-reference/plugins/create-plugin https://use.hoop.dev/api/openapiv3.json post /plugins Create Plugin resource # Delete Plugin Connection Source: https://mintlify.hoop.dev/docs/api-reference/plugins/delete-plugin-connection https://use.hoop.dev/api/openapiv3.json delete /plugins/{name}/conn/{id} Delete a plugin connection resource. # Get Plugin Source: https://mintlify.hoop.dev/docs/api-reference/plugins/get-plugin https://use.hoop.dev/api/openapiv3.json get /plugins/{name} Get a plugin resource by name # Get Plugin Connection Source: https://mintlify.hoop.dev/docs/api-reference/plugins/get-plugin-connection https://use.hoop.dev/api/openapiv3.json get /plugins/{name}/conn/{id} Get a plugin connection resource # List Plugins Source: https://mintlify.hoop.dev/docs/api-reference/plugins/list-plugins https://use.hoop.dev/api/openapiv3.json get /plugins List all Plugin resources # Update Plugin Source: https://mintlify.hoop.dev/docs/api-reference/plugins/update-plugin https://use.hoop.dev/api/openapiv3.json put /plugins/{name} Update Plugin resource. The `config` and `name` attributes are immutable for this endpoint. # Update Plugin Config Source: https://mintlify.hoop.dev/docs/api-reference/plugins/update-plugin-config https://use.hoop.dev/api/openapiv3.json put /plugins/{name}/config Update the Plugin resource top level configuration. # Upsert Plugin Connection Source: https://mintlify.hoop.dev/docs/api-reference/plugins/upsert-plugin-connection https://use.hoop.dev/api/openapiv3.json put /plugins/{name}/conn/{id} Update or create a plugin connection resource # ProxyManager Connect Source: https://mintlify.hoop.dev/docs/api-reference/proxy-manager/proxymanager-connect https://use.hoop.dev/api/openapiv3.json post /proxymanager/connect Send a connect request to the client. A successful response indicates the client has stablished a connection. If the connection resource has the review enabled, it returns a successful response containing the link of the review in the `Localtion` header. # ProxyManager Disconnect Source: https://mintlify.hoop.dev/docs/api-reference/proxy-manager/proxymanager-disconnect https://use.hoop.dev/api/openapiv3.json post /proxymanager/disconnect Send a disconnect request. The transport layer will disconnect the connected client asynchronously # ProxyManager Status Source: https://mintlify.hoop.dev/docs/api-reference/proxy-manager/proxymanager-status https://use.hoop.dev/api/openapiv3.json get /proxymanager/status Get the current status of the client # Get Compliance Report Source: https://mintlify.hoop.dev/docs/api-reference/reports/get-compliance-report https://use.hoop.dev/api/openapiv3.json get /reports/compliance Computes the compliance report with an overall score, category summaries, actionable items and per-framework control evaluations. # Session Reports Source: https://mintlify.hoop.dev/docs/api-reference/reports/session-reports https://use.hoop.dev/api/openapiv3.json get /reports/sessions The report payload groups sessions by info types and by a custom field (`group_by`) provided by the client. The items returns data containing the sum of redact fields performed by a given info type aggregated by the `group_by` attribute. # Applies a batch of resource plans Source: https://mintlify.hoop.dev/docs/api-reference/resources/applies-a-batch-of-resource-plans https://use.hoop.dev/api/openapiv3.json post /resources/apply Applies a batch of previously created resource plans. Each item references a plan session by SID and the target resource name. All items are processed concurrently and the response is returned once all have completed. Per-item failures are embedded in the results with status "failed" rather than returned as HTTP errors. # Applies a resource plan Source: https://mintlify.hoop.dev/docs/api-reference/resources/applies-a-resource-plan https://use.hoop.dev/api/openapiv3.json post /resources/{name}/apply Applies a previously created provisioning plan to a single resource. The plan session referenced by SID must have been created by the plan endpoint. On success, the resulting role and its credentials are synced as a connection. # Creates a batch of resource plans Source: https://mintlify.hoop.dev/docs/api-reference/resources/creates-a-batch-of-resource-plans https://use.hoop.dev/api/openapiv3.json post /resources/plan Validates provisioning plans for a batch of resources by computing the diff between the desired and current role state for each resource. Each item is session-audited and receives its own plan ID (SID) that can be referenced when applying. All items are processed concurrently and the response is returned once all have completed. Per-item failures are embedded in the results with status "failed" rather than returned as HTTP errors. # Creates a resource Source: https://mintlify.hoop.dev/docs/api-reference/resources/creates-a-resource https://use.hoop.dev/api/openapiv3.json post /resources Creates a resource for the organization. # Creates a resource plan Source: https://mintlify.hoop.dev/docs/api-reference/resources/creates-a-resource-plan https://use.hoop.dev/api/openapiv3.json post /resources/{name}/plan Validates a provisioning plan for a single resource by computing the diff between the desired and current role state. The plan is session-audited and returns a plan ID (SID) that can be referenced when applying. # Deletes a resource Source: https://mintlify.hoop.dev/docs/api-reference/resources/deletes-a-resource https://use.hoop.dev/api/openapiv3.json delete /resources/{name} Deletes a resource by ID for the organization. # Gets a resource Source: https://mintlify.hoop.dev/docs/api-reference/resources/gets-a-resource https://use.hoop.dev/api/openapiv3.json get /resources/{name} Gets a resource by ID for the organization. # Lists resources Source: https://mintlify.hoop.dev/docs/api-reference/resources/lists-resources https://use.hoop.dev/api/openapiv3.json get /resources Lists all resources for the organization. # Tests connectivity for a resource Source: https://mintlify.hoop.dev/docs/api-reference/resources/tests-connectivity-for-a-resource https://use.hoop.dev/api/openapiv3.json get /resources/{name}/health Performs a connectivity test against the resource's master credentials to verify network connectivity. Uses a minimal query (e.g. SELECT 1) to confirm the host is reachable and the master user can authenticate. # Tests connectivity for multiple resources Source: https://mintlify.hoop.dev/docs/api-reference/resources/tests-connectivity-for-multiple-resources https://use.hoop.dev/api/openapiv3.json post /resources/health Performs concurrent connectivity tests for the given resources. Each execution has a 10-second timeout. # Updates a resource Source: https://mintlify.hoop.dev/docs/api-reference/resources/updates-a-resource https://use.hoop.dev/api/openapiv3.json put /resources/{name} Updates a resource by ID for the organization. # Apply Rulepack to Connections Source: https://mintlify.hoop.dev/docs/api-reference/rulepacks/apply-rulepack-to-connections https://use.hoop.dev/api/openapiv3.json post /rulepacks/{id}/apply Replace the set of connections this rulepack is applied to. After the call, the rulepack is attached to exactly the supplied connections (additions and removals as needed). Non-rulepack attributes on each affected connection are preserved. Pass an empty array to remove the rulepack from all connections. Returns 400 with a list of missing names if any connection in the request does not exist. # Get Rulepack Source: https://mintlify.hoop.dev/docs/api-reference/rulepacks/get-rulepack https://use.hoop.dev/api/openapiv3.json get /rulepacks/{id} Get a rulepack by its UUID. # List Rulepacks Source: https://mintlify.hoop.dev/docs/api-reference/rulepacks/list-rulepacks https://use.hoop.dev/api/openapiv3.json get /rulepacks List rulepacks for the organization with optional pagination and search. # Create Runbook Configuration Entry Source: https://mintlify.hoop.dev/docs/api-reference/runbooks/create-runbook-configuration-entry https://use.hoop.dev/api/openapiv3.json post /runbooks/configurations Create Runbook Configuration Entry # Create Runbook File Source: https://mintlify.hoop.dev/docs/api-reference/runbooks/create-runbook-file https://use.hoop.dev/api/openapiv3.json post /runbooks/configurations/{id}/files Commit a new file (or overwrite an existing one) to the git repository associated with the given configuration ID. # Create Runbook Rule Source: https://mintlify.hoop.dev/docs/api-reference/runbooks/create-runbook-rule https://use.hoop.dev/api/openapiv3.json post /runbooks/rules Create a new Runbook Rule # Delete Runbook Configuration Entry Source: https://mintlify.hoop.dev/docs/api-reference/runbooks/delete-runbook-configuration-entry https://use.hoop.dev/api/openapiv3.json delete /runbooks/configurations/{id} Delete a runbook configuration entry. # Delete Runbook Rule Source: https://mintlify.hoop.dev/docs/api-reference/runbooks/delete-runbook-rule https://use.hoop.dev/api/openapiv3.json delete /runbooks/rules/{id} Delete a Runbook Rule by ID # Get Runbook Configuration Source: https://mintlify.hoop.dev/docs/api-reference/runbooks/get-runbook-configuration https://use.hoop.dev/api/openapiv3.json get /runbooks/configurations Get Runbook Configuration # Get Runbook Rule Source: https://mintlify.hoop.dev/docs/api-reference/runbooks/get-runbook-rule https://use.hoop.dev/api/openapiv3.json get /runbooks/rules/{id} Get a single Runbook Rule by ID # List Runbook Rules Source: https://mintlify.hoop.dev/docs/api-reference/runbooks/list-runbook-rules https://use.hoop.dev/api/openapiv3.json get /runbooks/rules List all Runbook Rules # List Runbooks Source: https://mintlify.hoop.dev/docs/api-reference/runbooks/list-runbooks https://use.hoop.dev/api/openapiv3.json get /plugins/runbooks/templates List all Runbooks # List Runbooks Source: https://mintlify.hoop.dev/docs/api-reference/runbooks/list-runbooks-1 https://use.hoop.dev/api/openapiv3.json get /runbooks List all Runbooks # List Runbooks By Connection Source: https://mintlify.hoop.dev/docs/api-reference/runbooks/list-runbooks-by-connection https://use.hoop.dev/api/openapiv3.json get /plugins/runbooks/connections/{name}/templates List Runbooks templates by connection # Runbook Exec Source: https://mintlify.hoop.dev/docs/api-reference/runbooks/runbook-exec https://use.hoop.dev/api/openapiv3.json post /plugins/runbooks/connections/{name}/exec Start a execution using a Runbook as input. If the connection has a JIRA issue template configured, it will create a JIRA issue. # Runbook Exec Source: https://mintlify.hoop.dev/docs/api-reference/runbooks/runbook-exec-1 https://use.hoop.dev/api/openapiv3.json post /runbooks/exec Start a execution using a Runbook as input. If the connection has a JIRA issue template configured, it will create a JIRA issue. # Update Runbook Configuration Source: https://mintlify.hoop.dev/docs/api-reference/runbooks/update-runbook-configuration https://use.hoop.dev/api/openapiv3.json put /runbooks/configurations Update Runbook Configuration # Update Runbook Configuration Entry Source: https://mintlify.hoop.dev/docs/api-reference/runbooks/update-runbook-configuration-entry https://use.hoop.dev/api/openapiv3.json put /runbooks/configurations/{id} Update Runbook Configuration Entry # Update Runbook Rule Source: https://mintlify.hoop.dev/docs/api-reference/runbooks/update-runbook-rule https://use.hoop.dev/api/openapiv3.json put /runbooks/rules/{id} Update an existing Runbook Rule by ID # Search Source: https://mintlify.hoop.dev/docs/api-reference/search/search https://use.hoop.dev/api/openapiv3.json get /search Performs a search for connections and runbooks based on the provided criteria. # List Server Logs Source: https://mintlify.hoop.dev/docs/api-reference/server-logs/list-server-logs https://use.hoop.dev/api/openapiv3.json get /server-logs Tail of recent in-memory runtime logs from the gateway process and connected agents # Stream Server Logs Source: https://mintlify.hoop.dev/docs/api-reference/server-logs/stream-server-logs https://use.hoop.dev/api/openapiv3.json get /server-logs/stream Streams gateway and agent runtime logs in real-time via SSE. Sends a backlog of recent entries on connect, then each new entry as it is captured. # Generate API Key Source: https://mintlify.hoop.dev/docs/api-reference/server-management/generate-api-key https://use.hoop.dev/api/openapiv3.json post /serverconfig/auth/apikey Generate a rollout api key # Get Authentication Configuration Source: https://mintlify.hoop.dev/docs/api-reference/server-management/get-authentication-configuration https://use.hoop.dev/api/openapiv3.json get /serverconfig/auth Get authentication configuration # Get MCP OAuth 2.1 Resource Server Configuration Source: https://mintlify.hoop.dev/docs/api-reference/server-management/get-mcp-oauth-21-resource-server-configuration https://use.hoop.dev/api/openapiv3.json get /serverconfig/mcp-auth Returns the per-org MCP OAuth Resource Server settings. When disabled (default), /mcp accepts Hoop-issued bearer tokens only. # Get MCP OAuth Authorization Server Metadata Source: https://mintlify.hoop.dev/docs/api-reference/server-management/get-mcp-oauth-authorization-server-metadata https://use.hoop.dev/api/openapiv3.json get /.well-known/oauth-authorization-server RFC 8414 authorization-server metadata mirroring the configured IdP, with registration_endpoint pointing at the gateway's RFC 7591 registration shim. Served unauthenticated at the gateway root (outside the /api base path) as /.well-known/oauth-authorization-server and /.well-known/openid-configuration. Returns 404 unless MCP OAuth is enabled with a static client configured; 502 when the IdP discovery document cannot be resolved. # Get Organization Analytics Mode Source: https://mintlify.hoop.dev/docs/api-reference/server-management/get-organization-analytics-mode https://use.hoop.dev/api/openapiv3.json get /orgs/analytics-mode Get the analytics privacy mode of the caller's organization # Get Organization Hide Role Info Source: https://mintlify.hoop.dev/docs/api-reference/server-management/get-organization-hide-role-info https://use.hoop.dev/api/openapiv3.json get /orgs/hide-role-info Get whether the caller's organization blocks reading connection/role secrets (envvars) through the API # Get Organization Onboarding Status Source: https://mintlify.hoop.dev/docs/api-reference/server-management/get-organization-onboarding-status https://use.hoop.dev/api/openapiv3.json get /orgs/onboarding Get the setup checklist state for the caller's organization. Each step latches the first time it is satisfied, so a check never reverts. Once every check passes, `show_setup_checklist` on /userinfo turns false — the signal to stop calling this endpoint. # Get Organization Protection Profile Source: https://mintlify.hoop.dev/docs/api-reference/server-management/get-organization-protection-profile https://use.hoop.dev/api/openapiv3.json get /orgs/protection-profile Get the organization's default protection profile. A null profile means manual configuration. # Get Public Server Info Source: https://mintlify.hoop.dev/docs/api-reference/server-management/get-public-server-info https://use.hoop.dev/api/openapiv3.json get /publicserverinfo Get public server information # Get Server Info Source: https://mintlify.hoop.dev/docs/api-reference/server-management/get-server-info https://use.hoop.dev/api/openapiv3.json get /serverinfo Get server information # Get Server Miscellaneous Configuration Source: https://mintlify.hoop.dev/docs/api-reference/server-management/get-server-miscellaneous-configuration https://use.hoop.dev/api/openapiv3.json get /serverconfig/misc Get server miscellaneous configuration # HealthCheck Source: https://mintlify.hoop.dev/docs/api-reference/server-management/healthcheck https://use.hoop.dev/api/openapiv3.json get /healthz Reports if the service is working properly. The gRPC transport is checked only while experimental.agents is enabled for the organization # Register MCP OAuth Client Source: https://mintlify.hoop.dev/docs/api-reference/server-management/register-mcp-oauth-client https://use.hoop.dev/api/openapiv3.json post /mcp/oauth/register RFC 7591 Dynamic Client Registration shim for IdPs without native DCR support: accepts any registration request and answers with the statically pre-registered OAuth client, echoing the caller's client metadata. Served unauthenticated per RFC 7591. Returns 404 unless MCP OAuth is enabled with a static client configured. # Sign License Source: https://mintlify.hoop.dev/docs/api-reference/server-management/sign-license https://use.hoop.dev/api/openapiv3.json post /orgs/license/sign Sign a new license for a customer. This route is for internal use only # Update Authentication Configuration Source: https://mintlify.hoop.dev/docs/api-reference/server-management/update-authentication-configuration https://use.hoop.dev/api/openapiv3.json put /serverconfig/auth Update authentication configuration # Update MCP OAuth 2.1 Resource Server Configuration Source: https://mintlify.hoop.dev/docs/api-reference/server-management/update-mcp-oauth-21-resource-server-configuration https://use.hoop.dev/api/openapiv3.json put /serverconfig/mcp-auth Enable, disable, or reconfigure the OAuth 2.1 Resource Server profile for the /mcp endpoint. # Update Org License Source: https://mintlify.hoop.dev/docs/api-reference/server-management/update-org-license https://use.hoop.dev/api/openapiv3.json put /orgs/license Upload a new license into the system # Update Organization Analytics Mode Source: https://mintlify.hoop.dev/docs/api-reference/server-management/update-organization-analytics-mode https://use.hoop.dev/api/openapiv3.json put /orgs/analytics-mode Update the analytics privacy mode of the caller's organization # Update Organization Hide Role Info Source: https://mintlify.hoop.dev/docs/api-reference/server-management/update-organization-hide-role-info https://use.hoop.dev/api/openapiv3.json put /orgs/hide-role-info Toggle whether the caller's organization blocks reading connection/role secrets (envvars) through the API # Update Organization Protection Profile Source: https://mintlify.hoop.dev/docs/api-reference/server-management/update-organization-protection-profile https://use.hoop.dev/api/openapiv3.json put /orgs/protection-profile Select the organization's default protection profile. The backend materializes the profile's managed rules and attribute and tags every connection. Passing a null profile switches to manual configuration and deletes all Hoop-managed protection rules. # Update Server Miscellaneous Configuration Source: https://mintlify.hoop.dev/docs/api-reference/server-management/update-server-miscellaneous-configuration https://use.hoop.dev/api/openapiv3.json put /serverconfig/misc Update server miscellaneous configuration # Get Session Metrics Source: https://mintlify.hoop.dev/docs/api-reference/session-metrics/get-session-metrics https://use.hoop.dev/api/openapiv3.json get /metrics/sessions Query session metrics data with advanced filtering. Supports AND/OR logic for combining filters. Filter by resource types (connection_type), resource subtypes (connection_subtype), resources (connection_name), Presidio data types (info_type), masked/unmasked status, date ranges, session dates, and session duration. # Analyze an exec before the run forms Source: https://mintlify.hoop.dev/docs/api-reference/sessions/analyze-an-exec-before-the-run-forms https://use.hoop.dev/api/openapiv3.json post /sessions/analyze Run the AI Session Analyzer on the script of a `POST /sessions` body, before the client asks for the run forms (Jira template, required metadata). A block is final: the gateway records the blocked session as `POST /sessions` does. Any other verdict records nothing, and the next `POST /sessions` of the same user, connection and script reuses it for 15 minutes on the same gateway. Answers 412 while `experimental.analyze_before_run_forms` is off. # Approved Exec Source: https://mintlify.hoop.dev/docs/api-reference/sessions/approved-exec https://use.hoop.dev/api/openapiv3.json post /sessions/{session_id}/exec Run an execution in an approved session # Create a provisioned session using API Key Source: https://mintlify.hoop.dev/docs/api-reference/sessions/create-a-provisioned-session-using-api-key https://use.hoop.dev/api/openapiv3.json post /sessions/provision # Download Session Source: https://mintlify.hoop.dev/docs/api-reference/sessions/download-session https://use.hoop.dev/api/openapiv3.json get /sessions/{session_id}/download Download session by id # Download Session Input Command Source: https://mintlify.hoop.dev/docs/api-reference/sessions/download-session-input-command https://use.hoop.dev/api/openapiv3.json get /sessions/{session_id}/download/input Download session input session by id # Exec Source: https://mintlify.hoop.dev/docs/api-reference/sessions/exec https://use.hoop.dev/api/openapiv3.json post /sessions This endpoint performs ad-hoc executions. It will wait 50 seconds for a sucessful response (200), otherwise return an Accepted status code (202) meaning the execution will be held asynchronously. The outcome could be obtained later on by fetching the resource using the attribute `id`. The payload of this request is used with the Connection resource to construct the command to be executed in the remote agent. - The `script` attribute is passed as stdin to the Connection resource `command` attribute. - The attribute `client_args` is appended to the suffix of the `command`. For example, the following connection: ```json { "name": "bash-connection", "command": ["/bin/bash"], "type": "custom" } ``` With the following payload: ```json { "script": "echo 'hello world'", "client_args": ["-x"], "connection": "bash-connection" } ``` Will perform an ad-hoc shell execution as: ```sh /bin/bash -x </download?token=&extension=csv&newline=1&event-time=0&events=o,e", "expire_at": "2024-07-25T15:56:35.317601Z", } ``` - Fetching the endpoint without any query string returns the payload documented for this endpoint - The attribute `event_stream` will be rendered differently if the request contains the query string `event_stream` with the values `utf8` or `base64`. ```json { (...) "event_stream": ["hello world"] (...) } ``` The attribute `metrics` contains the following structure: ```json { "data_masking": { "err_count": 0, "info_types": { "EMAIL_ADDRESS": 1 }, "total_redact_count": 1, "transformed_bytes": 31 }, "event_size": 356 } ``` # Kill Session Source: https://mintlify.hoop.dev/docs/api-reference/sessions/kill-session https://use.hoop.dev/api/openapiv3.json post /sessions/{session_id}/kill # List Sessions Source: https://mintlify.hoop.dev/docs/api-reference/sessions/list-sessions https://use.hoop.dev/api/openapiv3.json get /sessions List session resources # Retry RDP PII analysis Source: https://mintlify.hoop.dev/docs/api-reference/sessions/retry-rdp-pii-analysis https://use.hoop.dev/api/openapiv3.json post /sessions/{id}/rdp-detections/retry Resets a failed RDP analysis job to pending so the worker pool can re-claim it. # Stream Session Events Source: https://mintlify.hoop.dev/docs/api-reference/sessions/stream-session-events https://use.hoop.dev/api/openapiv3.json get /sessions/{session_id}/stream Streams audit events for an open session in real-time via SSE. Each event is published as it is appended to the WAL. No catch-up is sent for events that occurred before the subscription. # Stream Session Result Source: https://mintlify.hoop.dev/docs/api-reference/sessions/stream-session-result https://use.hoop.dev/api/openapiv3.json get /sessions/{session_id}/result/stream Returns the decoded output of a session as plain text with chunked transfer encoding # Update Session Metadata Source: https://mintlify.hoop.dev/docs/api-reference/sessions/update-session-metadata https://use.hoop.dev/api/openapiv3.json patch /sessions/{session_id}/metadata # Claim Sidecar Approval Request Source: https://mintlify.hoop.dev/docs/api-reference/sidecars/claim-sidecar-approval-request https://use.hoop.dev/api/openapiv3.json post /sidecars/reviews/{id}/claim Answer a sidecar waiting on one approval request it filed. An approved request is consumed once and releases the statement, or is reserved (PROCESSING) when the body asks to reserve it; a request past its deadline is expired and never releases it; any other status is returned as it stands. It never files an approval request. # Clear Sidecar Deleted Name Source: https://mintlify.hoop.dev/docs/api-reference/sidecars/clear-sidecar-deleted-name https://use.hoop.dev/api/openapiv3.json delete /sidecar-deleted-names/{name} Allow a service account identity to create a sidecar with this name again, on its next handshake. # Clear Sidecar Identity Source: https://mintlify.hoop.dev/docs/api-reference/sidecars/clear-sidecar-identity https://use.hoop.dev/api/openapiv3.json delete /sidecars/{nameOrID}/identity Remove the binding of a sidecar to the service account identity that reached it first. The next identity a sidecar service account allows is bound to it on its next handshake; a sidecar created with a token is bound again only through a sidecar service account with adopt_existing_sidecars. A token the sidecar has keeps working. # Create Sidecar Source: https://mintlify.hoop.dev/docs/api-reference/sidecars/create-sidecar https://use.hoop.dev/api/openapiv3.json post /sidecars Register a sidecar. The token is returned only once in this response and cannot be recovered. # Create Sidecar Approval Request Source: https://mintlify.hoop.dev/docs/api-reference/sidecars/create-sidecar-approval-request https://use.hoop.dev/api/openapiv3.json post /sidecars/reviews Register an approval request for a statement a sidecar held. The sidecar is taken from the token, never the body. An approval request for the same bytes past its deadline is expired and a new one is filed. # Create Sidecar Service Account Source: https://mintlify.hoop.dev/docs/api-reference/sidecars/create-sidecar-service-account https://use.hoop.dev/api/openapiv3.json post /sidecar-service-accounts Allow the tokens of a Kubernetes or Google service account to authenticate a sidecar with the hoop-sidecar-identity header. A matching token reaches the sidecar name_template renders, and creates it on its first handshake when no sidecar has that name. The sidecar is bound to the first identity that reaches it; another identity is refused until an admin clears the binding with DELETE /sidecars/{nameOrID}/identity. A sidecar created with a token is reached only with adopt_existing_sidecars. An issuer and audience pair belongs to one organization: 409 when another organization uses it. # Delete Sidecar Source: https://mintlify.hoop.dev/docs/api-reference/sidecars/delete-sidecar https://use.hoop.dev/api/openapiv3.json delete /sidecars/{nameOrID} Delete a sidecar. The token stops working immediately. A sidecar a service account identity reached has its name recorded, so the identity does not create it again; clear it with DELETE /sidecar-deleted-names/{name}. # Delete Sidecar Service Account Source: https://mintlify.hoop.dev/docs/api-reference/sidecars/delete-sidecar-service-account https://use.hoop.dev/api/openapiv3.json delete /sidecar-service-accounts/{id} Remove a sidecar service account. The sidecars it reached stay; their tokens stop authenticating unless another sidecar service account allows them. # Get Sidecar Source: https://mintlify.hoop.dev/docs/api-reference/sidecars/get-sidecar https://use.hoop.dev/api/openapiv3.json get /sidecars/{nameOrID} Get a sidecar by name or ID # Get Sidecar Approval Status Source: https://mintlify.hoop.dev/docs/api-reference/sidecars/get-sidecar-approval-status https://use.hoop.dev/api/openapiv3.json get /sidecars/reviews/{id} Read the status of one approval request the calling sidecar filed. It never changes the request: an approved request stays approved until the sidecar resends the statement or its approval expires. A request past its deadline reads EXPIRED. # Get Sidecar Service Account Source: https://mintlify.hoop.dev/docs/api-reference/sidecars/get-sidecar-service-account https://use.hoop.dev/api/openapiv3.json get /sidecar-service-accounts/{id} Get one sidecar service account by its ID. # Get Sidecar Slack Channels Source: https://mintlify.hoop.dev/docs/api-reference/sidecars/get-sidecar-slack-channels https://use.hoop.dev/api/openapiv3.json get /sidecars/{nameOrID}/slack-channels Where the reviews of each listener of the sidecar are posted in Slack. # Import Sidecar Configuration Source: https://mintlify.hoop.dev/docs/api-reference/sidecars/import-sidecar-configuration https://use.hoop.dev/api/openapiv3.json put /sidecars/configuration Authenticated with the hoop-sidecar-token or the hoop-sidecar-identity header, never both. Stores the config document a sidecar carried locally, once. Only a sidecar too old to send local_configuration on the handshake calls it. Each guardrail and mask rule of the file becomes a rule item, and each listener analyzer block an analyzer rule, bound to the listeners that ran it. The import is refused with 409 when the gateway already holds a configuration with listeners, or when the sidecar loads its configuration from disk. # List Sidecar Approval Requests Source: https://mintlify.hoop.dev/docs/api-reference/sidecars/list-sidecar-approval-requests https://use.hoop.dev/api/openapiv3.json get /sidecars/reviews List the approval requests the calling sidecar filed, newest first. It never changes a request. # List Sidecar Deleted Names Source: https://mintlify.hoop.dev/docs/api-reference/sidecars/list-sidecar-deleted-names https://use.hoop.dev/api/openapiv3.json get /sidecar-deleted-names List the names of deleted sidecars a service account identity had reached. A token that renders one of them is refused and creates nothing. # List Sidecar Service Accounts Source: https://mintlify.hoop.dev/docs/api-reference/sidecars/list-sidecar-service-accounts https://use.hoop.dev/api/openapiv3.json get /sidecar-service-accounts List the service accounts whose tokens may authenticate a sidecar in the organization. # List Sidecars Source: https://mintlify.hoop.dev/docs/api-reference/sidecars/list-sidecars https://use.hoop.dev/api/openapiv3.json get /sidecars List all sidecars for the organization # Patch Sidecar Configuration Source: https://mintlify.hoop.dev/docs/api-reference/sidecars/patch-sidecar-configuration https://use.hoop.dev/api/openapiv3.json patch /sidecars/{nameOrID} Merge a partial configuration into the document a sidecar serves: the keys sent are updated and the rest are left as stored. Unlike PUT it never replaces the whole document, so it cannot overwrite a configuration a sidecar imported meanwhile. load_from_disk true deletes the rules imported from this sidecar that nothing else uses and unbinds the rest; detached_rules lists them. load_from_disk false must be sent alone. It clears the stored document, so the sidecar imports its config file again. # Record Sidecar Session Events Source: https://mintlify.hoop.dev/docs/api-reference/sidecars/record-sidecar-session-events https://use.hoop.dev/api/openapiv3.json post /sidecars/events Record a sidecar's audit events as sessions. The sidecar is taken from the token, never the body, and every session it writes is its own. 2xx means the batch is applied, now or by an earlier request: an event at or below its session's last applied seq is ignored. 4xx means the sidecar must not resend the batch; a 422 names the sessions that can never be recorded, and the other sessions of the batch were applied. 5xx means it may resend it as it is. The organization must have the experimental.sidecar_session_events flag on; the handshake answers the hoop-sidecar-session-events header when it does. # Set Sidecar Slack Channels Source: https://mintlify.hoop.dev/docs/api-reference/sidecars/set-sidecar-slack-channels https://use.hoop.dev/api/openapiv3.json put /sidecars/{nameOrID}/slack-channels Set where the reviews of the listeners in the body are posted in Slack. A listener with no channels uses the fallback channel; a listener left out keeps its channels. # Settle Sidecar Approval Request Source: https://mintlify.hoop.dev/docs/api-reference/sidecars/settle-sidecar-approval-request https://use.hoop.dev/api/openapiv3.json post /sidecars/reviews/{id}/settle Report what the upstream answered to a statement a reserved approval released. Accepted spends the approval (EXECUTED). Refused gives it back (APPROVED), so a resend of the same bytes can take it again. A reservation past its lease is spent and stays spent. Any approval request the calling sidecar did not reserve is returned as it stands. # Sidecar Configuration Source: https://mintlify.hoop.dev/docs/api-reference/sidecars/sidecar-configuration https://use.hoop.dev/api/openapiv3.json get /sidecars/configuration Authenticated with the hoop-sidecar-token or the hoop-sidecar-identity header, never both. Returns the configuration the sidecar must serve, carrying the organization's license in its "license" key, or only the load_from_disk flag and the license when the sidecar loads its configuration from disk. Unlike the handshake it records nothing, so a poll never overwrites what the sidecar last reported about itself. # Sidecar Handshake Source: https://mintlify.hoop.dev/docs/api-reference/sidecars/sidecar-handshake https://use.hoop.dev/api/openapiv3.json post /sidecars/handshake Authenticated with the hoop-sidecar-token or the hoop-sidecar-identity header, never both. Records the reported version and returns the configuration the sidecar must serve. A sidecar whose stored configuration sets load_from_disk receives only that flag and its license, and runs its own config file. A sidecar that sends local_configuration while no configuration is stored gets that answer too: the control plane stores the report and adopts it only when an admin sends load_from_disk false. Otherwise it answers 412 while no configuration with listeners is assigned, recording nothing: a sidecar that cannot run must not show up as recently seen. Answers 422 when the configuration uses a feature the hoop-sidecar-capabilities header does not list. The answer carries the organization's license in its "license" key; the sidecar verifies that signature itself and the license is never stored per sidecar. # Update Sidecar Source: https://mintlify.hoop.dev/docs/api-reference/sidecars/update-sidecar https://use.hoop.dev/api/openapiv3.json put /sidecars/{nameOrID} Replace the configuration a sidecar serves. The sidecar picks it up on its next heartbeat. A change of load_from_disk is refused: use PATCH. # Update Sidecar Service Account Source: https://mintlify.hoop.dev/docs/api-reference/sidecars/update-sidecar-service-account https://use.hoop.dev/api/openapiv3.json put /sidecar-service-accounts/{id} Replace a sidecar service account. The sidecars it reached keep their names; a token it no longer matches stops authenticating. 409 when another organization uses the new issuer and audience. # Create SPIFFE Mapping Source: https://mintlify.hoop.dev/docs/api-reference/spiffe/create-spiffe-mapping https://use.hoop.dev/api/openapiv3.json post /spiffe-mappings Map a SPIFFE identity (exact URI or URI prefix) onto a Hoop agent. # Delete SPIFFE Mapping Source: https://mintlify.hoop.dev/docs/api-reference/spiffe/delete-spiffe-mapping https://use.hoop.dev/api/openapiv3.json delete /spiffe-mappings/{id} Remove a SPIFFE-ID to agent mapping. # List SPIFFE Mappings Source: https://mintlify.hoop.dev/docs/api-reference/spiffe/list-spiffe-mappings https://use.hoop.dev/api/openapiv3.json get /spiffe-mappings List all SPIFFE-ID to agent mappings in the caller's organization. # Update SPIFFE Mapping Source: https://mintlify.hoop.dev/docs/api-reference/spiffe/update-spiffe-mapping https://use.hoop.dev/api/openapiv3.json put /spiffe-mappings/{id} Update an existing SPIFFE-ID to agent mapping. # Answer Signup Origin Survey Source: https://mintlify.hoop.dev/docs/api-reference/user-management/answer-signup-origin-survey https://use.hoop.dev/api/openapiv3.json post /users/self/signup-origin Record how the authenticated user heard about Hoop. Each user may answer only once; a second attempt returns 409. # Create Service Account Source: https://mintlify.hoop.dev/docs/api-reference/user-management/create-service-account https://use.hoop.dev/api/openapiv3.json post /serviceaccounts Create a service account that is associated with a identity provider client # Create User Source: https://mintlify.hoop.dev/docs/api-reference/user-management/create-user https://use.hoop.dev/api/openapiv3.json post /users Creating a user will pre configure user definitions like display name, profile picture, groups and the slack id # Create User Group Source: https://mintlify.hoop.dev/docs/api-reference/user-management/create-user-group https://use.hoop.dev/api/openapiv3.json post /users/groups Create a new user group # Delete User Source: https://mintlify.hoop.dev/docs/api-reference/user-management/delete-user https://use.hoop.dev/api/openapiv3.json delete /users/{emailOrID} Delete a user. # Delete User Group Source: https://mintlify.hoop.dev/docs/api-reference/user-management/delete-user-group https://use.hoop.dev/api/openapiv3.json delete /users/groups/{name} Delete a user group # Get User Source: https://mintlify.hoop.dev/docs/api-reference/user-management/get-user https://use.hoop.dev/api/openapiv3.json get /users/{emailOrID} Get user by email or subject id # Get UserInfo Source: https://mintlify.hoop.dev/docs/api-reference/user-management/get-userinfo https://use.hoop.dev/api/openapiv3.json get /userinfo Get own user's information # Handle Organization Invitation Source: https://mintlify.hoop.dev/docs/api-reference/user-management/handle-organization-invitation https://use.hoop.dev/api/openapiv3.json post /orgs/invitations Accept or decline a pending organization invitation. On accept, the current user is migrated to the invited org and the old auto-created org is removed if empty. On decline, the invitation is dismissed permanently. # List Service Accounts Source: https://mintlify.hoop.dev/docs/api-reference/user-management/list-service-accounts https://use.hoop.dev/api/openapiv3.json get /serviceaccounts List all service accounts # List User Groups Source: https://mintlify.hoop.dev/docs/api-reference/user-management/list-user-groups https://use.hoop.dev/api/openapiv3.json get /users/groups List every group name known to the organization: the ones bound to users, service accounts, API keys and AI agents, plus the ones referenced by the access_control plugin. Sorted alphabetically. # List Users Source: https://mintlify.hoop.dev/docs/api-reference/user-management/list-users https://use.hoop.dev/api/openapiv3.json get /users List the users of the organization. Pass `page` or `page_size` to get a paginated response. Only admins and auditors receive `last_login_at`. # Patch User Slack ID Source: https://mintlify.hoop.dev/docs/api-reference/user-management/patch-user-slack-id https://use.hoop.dev/api/openapiv3.json patch /users/self/slack Patch own user's slack id # Update Service Account Source: https://mintlify.hoop.dev/docs/api-reference/user-management/update-service-account https://use.hoop.dev/api/openapiv3.json put /serviceaccounts/{subject} Update a service account that is associated with a identity provider client # Update User Source: https://mintlify.hoop.dev/docs/api-reference/user-management/update-user https://use.hoop.dev/api/openapiv3.json put /users/{emailOrID} Updates an existing user # Connect a Sidecar Source: https://mintlify.hoop.dev/docs/control-plane/connect-sidecar Issue a token, point a Sidecar at the Control Plane, and let it pull its configuration. A [Sidecar](/docs/core-concepts/sidecar) that knows nothing about a Control Plane reads its config file from disk and runs. Connecting it changes one thing: on boot, it asks the Control Plane what its configuration should be, and from then on the Control Plane owns that configuration. > [!TIP] > > Deploying many Sidecars with automation? Skip the per-Sidecar token: [Service Accounts](/docs/setup/configuration/hoop-sidecar/service-accounts) lets each one authenticate with its Kubernetes or Google service account, and the Control Plane creates it on the first handshake. *** ## The handshake ```mermaid theme={"dark"} sequenceDiagram participant S as Sidecar participant CP as Control Plane S->>S: boot, read local config S->>CP: ping, with token CP->>CP: identify the Sidecar from the token CP-->>S: your configuration S->>S: load into memory, start listeners ``` Four properties fall out of this shape, and they are the reason it looks like this: * **No session to maintain.** The Sidecar loads its configuration into memory and keeps running. A Control Plane that goes down does not take running Sidecars with it. A listener using `require_approval` is the exception: it files each held statement with the Control Plane, and denies that statement while the Control Plane is unreachable. * **The token is the authentication.** There is no second credential and no certificate exchange. A Sidecar can use a [service account](/docs/setup/configuration/hoop-sidecar/service-accounts) instead of a token, never both. * **Ordinary HTTP.** A plain request and a plain response. Nothing is tunnelled and nothing bidirectional stays open. * **Neither side knows the other's physical address.** The Sidecar dials out; the Control Plane never dials in. No inbound firewall rule, no NAT traversal. *** ## Steps **1. Issue a token in the Control Plane** Create a Sidecar registration and copy the token it returns. It is shown once and stored only as a hash, so losing it means registering a new Sidecar. The token identifies this Sidecar and authenticates it — treat it as a credential. **2. Point the Sidecar at the Control Plane** Add the Control Plane's URL to the Sidecar's config file. The token is never written to disk — it goes on the command line or in an environment variable: ```yaml config.yaml theme={"dark"} control_plane_url: https://hoop.your-company.com ``` ```bash theme={"dark"} hoop start sidecar --config config.yaml --token "" ``` Or supply both through the environment, which is the shape a Kubernetes deployment wants — mount the secret, set the variables, pass no arguments: ```bash theme={"dark"} export HOOP_CONTROL_PLANE_URL=https://hoop.your-company.com export HOOP_SIDECAR_TOKEN= ``` **3. Start it** ```bash theme={"dark"} hoop start sidecar --config config.yaml --token "" ``` On the first start the Control Plane holds no configuration for this Sidecar. It answers `412`, the Sidecar imports the document from your local file, and then serves what the Control Plane sends back. That import happens once. **4. Edit the configuration in the Control Plane from now on** The Control Plane owns the whole document after the import — listeners included. The two are never merged. Listeners left in the local file are ignored, and the Sidecar says so at startup: ``` the config file's listeners are ignored: the control plane owns the running config ``` `--config` becomes optional at this point. The URL and the token are enough to start. **5. Confirm what it resolved** The admin API reports the live configuration. It only runs when the configuration names an address for it, so the document the Control Plane serves needs an `admin` block — there is no default port: ```yaml theme={"dark"} admin: listen: 127.0.0.1:19000 ``` ```bash theme={"dark"} curl -s localhost:19000/healthz # ok curl -s localhost:19000/config | python3 -m json.tool ``` The Sidecar should also appear in the Control Plane's list, with a recent check-in. *** ## The license The organization's license lives on the Control Plane, not on each Sidecar. It rides on the handshake response, and the response carries a header saying the Control Plane owns the decision: ``` hoop-sidecar-license-managed: true ``` While that header is present, the Sidecar's own license sources — the `--license` flag, `HOOP_LICENSE` and the config file's `license` key — are ignored, and it warns at startup that it is ignoring them. A Control Plane whose organization holds no license runs the free tier. A `license` key authored on a Sidecar's configuration in the Control Plane is refused. One organization, one license. *** ## Staying in sync A heartbeat repeats the handshake every minute. A change that only touches rules — guardrails, masking, PII, OPA, a listener's analyzer block — is applied in place and logged as `control plane configuration applied`. Connections already open drain under the rules they were accepted with. A change beyond the rules — listeners, audit, admin, log level — logs `restart to apply it` instead. A failed heartbeat changes nothing. The Sidecar keeps serving the configuration and the license it last received. Approval requests do not ride on the heartbeat. A listener using [`require_approval`](/docs/setup/configuration/hoop-sidecar/risk-analysis#holding-a-statement-for-a-person) calls the Control Plane once per held statement, and denies the statement when that call fails. *** ## Upgrading Upgrade the Control Plane first, then the Sidecars. A Sidecar refuses the whole configuration when one key in it is unknown to its version. From 1.210.0 the Control Plane knows what each Sidecar can read: * It sends only the settings an admin set. Upgrading the Control Plane alone changes nothing an older Sidecar receives. * A save that uses a setting, a rule type or a protocol that a connected Sidecar's version lacks is refused with `422`. The error names the Sidecar and the upgrade it needs. A Sidecar that never connected is checked at its first handshake instead. * This covers every Sidecar from 1.162.0. A Sidecar newer than its Control Plane runs, but cannot use a setting the Control Plane does not know. Its first import fails when its config file uses such a setting, and the Sidecar does not start. Do not roll the Control Plane back below a setting a stored configuration uses: the Control Plane then answers `500` to that Sidecar. When a Sidecar refuses a configuration anyway: | When | What happens | | - | - | | At startup | The Sidecar exits with an error that names the key. | | On a heartbeat | The Sidecar keeps running its last rules and reports `refused`. | The Sidecar page in the Control Plane shows the state, the Sidecar's version and the reason until a configuration applies. `Not applied` for longer than a few minutes means the Sidecar is restarting in a loop. **Escape hatch.** An admin can hand the Sidecar back to its own config file: ```bash theme={"dark"} curl -X PATCH https://hoop.your-company.com/api/sidecars/ \ -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \ -d '{"configuration": {"load_from_disk": true}}' ``` The Control Plane then sends only that flag and the license, and the Sidecar runs the config file it was started with. The switch deletes the Control Plane rules imported from this Sidecar that nothing else uses, and unbinds the rest. Send `{"configuration": {"load_from_disk": false}}` alone to hand it back: the stored configuration is cleared, and the Sidecar imports its config file again. *** ## Troubleshooting | Symptom | Check | | - | - | | The Sidecar does not start at all | A first handshake that fails stops startup; there is no fallback to the local file. Check the URL, the token, and outbound HTTPS to the Control Plane host. | | The Sidecar starts but never appears in the Control Plane | Outbound HTTPS to the Control Plane host. The Sidecar dials out; nothing dials in. | | It warns that the config file's listeners are ignored | Expected once the Control Plane holds the configuration. Edit it there; the local file no longer holds it. | | It warns that your license is ignored | Expected while the Control Plane manages licensing. Apply the license to the organization instead. | | The admin API refuses the connection | `admin.listen` is not in the configuration the Control Plane serves. There is no default address. | | Rules changed centrally but the Sidecar did not | Configuration is picked up on the heartbeat, not pushed. Wait up to a minute. A listener change needs a restart. | | Authentication fails | The token is per-Sidecar. Reusing one across two Sidecars is not a supported shape. | | The Sidecar page shows `Refused` or `Not applied` | The Sidecar's version cannot read the configuration. The page shows the reason. Upgrade the Sidecar, or remove the setting. See [Upgrading](#upgrading). | | `more than one control plane credential is set` | Set either `HOOP_SIDECAR_TOKEN` (or `--token`) or `HOOP_SIDECAR_IDENTITY_TYPE`, not both. | | Held statements are denied with `the approval request could not be filed` | Outbound HTTPS to the Control Plane host, and that the listener's `approval_rule` names an access request rule the Control Plane holds. A listener that holds statements fails closed. | *** ## Next > **[Control Plane](/docs/core-concepts/control-plane)** > > What it manages and why the protocol is this simple. > **[Install the Control Plane](/docs/control-plane/install)** > > Docker Compose, Kubernetes and AWS. > **[Config File Reference](/docs/setup/configuration/hoop-sidecar/config-file#control-plane)** > > Every source for `control_plane_url` and the credential, in precedence order. > **[Service Accounts](/docs/setup/configuration/hoop-sidecar/service-accounts)** > > No token per Sidecar: one entry per cluster, Sidecars created on first contact. # Container Images Source: https://mintlify.hoop.dev/docs/control-plane/container-images The images that run the Control Plane, what each one contains, and when to pick which. The Control Plane runs from `hoophq/hoopcontrolplane`, published in two flavours that differ only in the rootfs underneath. It is not the Gateway image with a different command. The Gateway image carries the data plane's dependencies — OCR for session-replay analysis, a set of third-party database clients — and the Control Plane execs none of them. These images are a stock rootfs plus the `hoop` binary, and nothing else. *** ## Choosing a flavour | Tag | Use it when | | - | - | | `hoophq/hoopcontrolplane:` | The default. Ubuntu base, keeps a shell for debugging | | `hoophq/hoopcontrolplane:latest` | An alias of the unsuffixed tag | | `hoophq/hoopcontrolplane:-distroless` | You want the smallest possible surface and no shell | Both are multi-architecture manifests covering `linux/amd64` and `linux/arm64`. Pin an explicit version in production rather than using `latest`. > [!NOTE] > > Every version, its changelog and its release date are published on the [hoophq/hoop releases page](https://github.com/hoophq/hoop/releases). > Image tags, chart versions and binary downloads all use the same version numbers. ```bash theme={"dark"} docker pull hoophq/hoopcontrolplane: ``` ### How they differ | | `` (default) | `-distroless` | | - | - | - | | Base | Ubuntu 24.04 LTS | distroless static | | Shell | yes | **no** | | OS package manager | yes | no | | Size | larger | roughly two thirds of the default | | `kubectl exec -- sh` | works | impossible | | An `exec` probe | works | impossible | | HTTP API, web app, migrations | identical | identical | Both serve the whole API and the web app, run as uid `10001`, and run tini as PID 1. They differ in debuggability and nothing else: distroless has no package manager and no shell, so it reports zero OS-package CVEs and cannot be opened with `kubectl exec`. Pick the default when you want to debug in place, `-distroless` when you want that smaller surface. The Ubuntu flavour carries no suffix and `latest` points at it, so the tag someone reaches for without thinking is the one they can get a shell in. *** ## What is set Neither image needs a command or an argument to start the Control Plane. | | Default | Distroless | | - | - | - | | Entrypoint | `/usr/bin/tini --` | `/app/tini --` | | Command | `hoop start control-plane` | `hoop start control-plane` | | User | `hoop`, uid `10001` | uid `10001` | | Exposed port | `8009` | `8009` | | Binary | `/app/hoop`, with `/app` on `PATH` | same | ```bash theme={"dark"} docker run --rm -p 8009:8009 \ -e POSTGRES_DB_URI='postgres://hoopuser:hooppass@postgres:5432/hoopdb?sslmode=disable' \ -e API_URL='http://127.0.0.1:8009' \ hoophq/hoopcontrolplane: ``` `POSTGRES_DB_URI` and `API_URL` are the only two variables the image needs. See [Environment Variables](/docs/control-plane/environment-variables) for the rest, and [Kubernetes](/docs/control-plane/deployment/kubernetes) for the Helm chart that sets them for you. *** ## Building your own The Dockerfile is `Dockerfile.controlplane` in [hoophq/hoop](https://github.com/hoophq/hoop). It builds from the published release tarball rather than from source, so it needs no Go toolchain and no credentials: ```bash theme={"dark"} # from a checkout, with release tarballs in dist/binaries/ docker build -f Dockerfile.controlplane --target default -t my-registry/hoopcontrolplane:dev . docker build -f Dockerfile.controlplane --target distroless -t my-registry/hoopcontrolplane:dev-distroless . ``` A build with no `--target` produces `default`, the same flavour the unsuffixed tag and `latest` point at — so an accidental default is never the restrictive one. *** ## Next > **[Kubernetes](/docs/control-plane/deployment/kubernetes)** > > The Helm chart, which picks the flavour with `image.tag`. > **[Docker Compose](/docs/control-plane/deployment/docker-compose)** > > Postgres and the Control Plane on a single host. # Docker Compose Source: https://mintlify.hoop.dev/docs/control-plane/deployment/docker-compose Stand up a Control Plane on a single host with docker compose. The fastest way to get a Control Plane running. Good for evaluation, and good enough for a single-host production install. ## Supported operating systems > **Linux** > > Tested on Ubuntu 24.04 and Amazon Linux 2. > **MacOS** > > Intel and Apple Silicon (M1/M2). ## Required tooling ### 1. Docker Install or update to Docker 20.10.0 or greater. > **[Install Docker for Linux](https://docs.docker.com/engine/install/ubuntu/#install-using-the-convenience-script)** > **[Install Docker for MacOS](https://docs.docker.com/desktop/install/mac-install/)** ### 2. Docker Compose Install or update Docker Compose to 2.24.0 or greater. \[!NOTE] Run `docker compose version` to check which version you have installed. > **[Install Docker Compose for Linux](https://docs.docker.com/desktop/install/linux-install/)** > > It ships with the Docker engine, but a standalone installation also works. > **Docker Compose for MacOS** > > Nothing to install — it comes with Docker Desktop. *** ## The compose file ```sh theme={"dark"} curl -sL https://hoop.dev/docker-compose.control-plane.yml > docker-compose.yml ``` The file brings up Postgres and the Hoop image started in control plane mode, plus an optional Sidecar and a database for it to sit in front of. The subcommand picks the mode: the same image runs the gateway when it is started with `hoop start gateway`. The Control Plane publishes one port, `8009`. It opens no gRPC transport and starts no protocol proxies, so there is nothing else to expose. The Sidecar is behind a profile because its token does not exist until the Control Plane issues one, and a Sidecar without a token exits rather than retrying. Profiles are additive, so `docker compose up` brings up Postgres and the Control Plane and nothing else. *** ## Run it on your machine ```sh theme={"dark"} docker compose up ``` Open `http://localhost:8009` in your browser. > [!NOTE] > > Confirm you got the mode you asked for: > > ```sh theme={"dark"} > curl -s localhost:8009/api/publicserverinfo | jq .application_mode > # "control-plane" > ``` To run it on a host your Sidecars can reach, follow the section below instead. *** ## Add a Sidecar **1. Create the first account** At `http://localhost:8009`. Authentication is local by default, so there is nothing to wire up first. **2. Register a Sidecar** Create one named `appdb-sidecar` and copy the `hsc_` token. It is shown once. **3. Put the token in .env** ```sh .env theme={"dark"} HOOP_SIDECAR_TOKEN=hsc_... ``` **4. Bring it up** ```sh theme={"dark"} docker compose --profile sidecar up -d ``` The Control Plane holds no configuration for this Sidecar yet, so the first handshake answers `412` and the Sidecar imports the document the compose file carries. The log says `configuration imported into the control plane`, and the Sidecar appears in the fleet with a recent check-in. **5. Try it** ```sh theme={"dark"} docker run --rm --network hoop-control-plane_hoopcp -e PGPASSWORD=postgres \ postgres:17.6 psql -h sidecar -p 15432 -U postgres -d appdb \ -c "create table t(id int);" -c "drop table t;" ``` `CREATE TABLE` goes through. The `DROP` comes back as `FATAL: destructive statements are not permitted through this lane` — the one guardrail the compose file ships with. From here, edit the configuration in the Control Plane. The local file has done its job; on the next start its listeners are ignored with a warning rather than merged. See [Connect a Sidecar](/docs/control-plane/connect-sidecar). *** ## Run it on a remote machine **1. Download the compose file** ```sh theme={"dark"} curl -sL https://hoop.dev/docker-compose.control-plane.yml > docker-compose.yml ``` **2. Write the .env file** The Control Plane needs to know its own public address, so it can serve the web app assets and tell Sidecars where to come back to. > [!NOTE] > > The `.env` file must sit next to `docker-compose.yml`. ```sh .env theme={"dark"} API_URL=http://:8009 ``` Every other setting is optional — see [Environment Variables](/docs/control-plane/environment-variables) for the full list. > [!NOTE] > > If you cannot reach the web app from outside the VM, check your firewall rules and make sure TCP/8009 is open or bound so it is reachable from your network. **3. Run** The first run pulls the images, so it can take a few minutes. ```sh theme={"dark"} docker compose up ``` **4. Manage the containers** Follow the logs: ```sh theme={"dark"} docker compose logs -f ``` Stop everything: ```sh theme={"dark"} docker compose down ``` **5. Sign in** Visit `http://:8009` and create the first account. Authentication is local by default: the Control Plane manages users and passwords itself and signs its own access tokens, so there is nothing else to wire up before you can log in. *** ## Troubleshooting ### Assets fail to load behind a domain `API_URL` defaults to `127.0.0.1`, which only works from inside the VM. In production it has to carry the full scheme and host: ```sh theme={"dark"} API_URL=https://yourdomain.com ``` Two things go wrong most often: * **Scheme omitted.** `yourdomain.com` is not enough — assets are served with the scheme from this value. * **An IP behind DNS forwarding.** If you set an IP and later put a domain in front of it, the assets still point at the IP. `API_URL` has to be the domain users actually reach. *** ## Next > **[Connect a Sidecar](/docs/control-plane/connect-sidecar)** > > Issue a token, point a Sidecar at the server host, and confirm it picked up its configuration. # Kubernetes Source: https://mintlify.hoop.dev/docs/control-plane/deployment/kubernetes Deploy the Control Plane with the Helm chart, on any cloud provider. This page provides instructions on how to configure the Helm chart to install the Control Plane in any cloud provider. The chart deploys one Control Plane: a Deployment, a Secret holding its environment, a Service for the HTTP API, and — if you ask for them — a ServiceAccount and a pair of Gateway API resources. It depends on no other chart. It needs a PostgreSQL you provide, and nothing else. The Control Plane **carries no traffic**. It serves the HTTP API and the web app and administers a fleet of Sidecars. There is no gRPC listener on 8010, no protocol proxies, and of the six transport plugins only Slack is started. ## Quick Start A Control Plane with local authentication, in three steps. At the end the web app answers on your machine and you can create the first account. **1. Deploy a PostgreSQL** Skip this if you already have a database to point at. This one is a throwaway with a password in plain sight. > **postgres.yaml** > > ```yaml theme={"dark"} > apiVersion: apps/v1 > kind: Deployment > metadata: {name: postgres} > spec: > replicas: 1 > selector: {matchLabels: {app: postgres}} > template: > metadata: {labels: {app: postgres}} > spec: > containers: > - name: postgres > image: postgres:17.6 > env: > - {name: POSTGRES_USER, value: hoopuser} > - {name: POSTGRES_PASSWORD, value: hooppass} > - {name: POSTGRES_DB, value: hoopdb} > ports: [{containerPort: 5432}] > --- > apiVersion: v1 > kind: Service > metadata: {name: postgres} > spec: > selector: {app: postgres} > ports: [{port: 5432}] > ``` ```sh theme={"dark"} kubectl create namespace hoop kubectl -n hoop apply -f postgres.yaml ``` The Control Plane runs its migrations and the organization bootstrap before it listens, so the database has to be reachable at startup. **2. Write the values file** ```yaml values.yaml theme={"dark"} config: POSTGRES_DB_URI: 'postgres://hoopuser:hooppass@postgres:5432/hoopdb?sslmode=disable' API_URL: 'http://127.0.0.1:8009' ``` Two keys are required and the rest have defaults. `API_URL` is the address the web app and every Sidecar reach this on — here it is the port-forward, because that is where you will open it. Change it when you publish the service, and read [API\_URL](#api-url) before you leave it out. **3. Install the chart** ```sh theme={"dark"} VERSION=$(curl -s https://releases.hoop.dev/release/latest.txt) helm upgrade hoopcontrolplane --install \ oci://ghcr.io/hoophq/helm-charts/hoopcontrolplane-chart --version $VERSION \ --namespace hoop \ -f values.yaml ``` ```sh theme={"dark"} kubectl -n hoop rollout status deploy/hoopcontrolplane kubectl -n hoop logs deploy/hoopcontrolplane ``` The last bootstrap line names the mode and the address it will serve: ```json theme={"dark"} {"level":"info","msg":"gateway ready, elapsed=168ms","event":"bootstrap.ready", "urls":{"Control Plane":"http://127.0.0.1:8009"}} ``` Forward the port and open the web app: ```sh theme={"dark"} kubectl -n hoop port-forward svc/hoopcontrolplane 8009:8009 ``` [http://127.0.0.1:8009/login](http://127.0.0.1:8009/login) — authentication is local by default, so the first visit asks you to create the account. Confirm the mode at the same time: ```sh theme={"dark"} curl -s http://127.0.0.1:8009/api/publicserverinfo ``` ```json theme={"dark"} {"auth_method":"local","setup_required":true,"application_mode":"control-plane"} ``` Delete everything this created with `kubectl delete namespace hoop`. ## Helm Install To install the latest version in a new namespace (example: `hoop`): ```bash theme={"dark"} VERSION=$(curl -s https://releases.hoop.dev/release/latest.txt) helm upgrade --install hoopcontrolplane \ oci://ghcr.io/hoophq/helm-charts/hoopcontrolplane-chart --version $VERSION \ -f values.yaml \ --namespace hoop ``` The release name prefixes every resource the chart owns: | Resource | Name | | - | - | | Deployment, Service, ServiceAccount | `-hoopcontrolplane` | | Secret holding the environment | `-hoopcontrolplane-config` | | Secret holding `extraSecret` | `-hoopcontrolplane-extra-env` | | Gateway | `-hoopcontrolplane` | | HTTPRoute | `-hoopcontrolplane-route` | A release named `hoopcontrolplane` collapses to the bare name rather than repeating it. ### Overriding values It is possible to add new attributes or overwrite an attribute from a base `values.yaml` file. In the example below a specific image tag is pinned and the log level is raised. ```bash theme={"dark"} helm upgrade --install hoopcontrolplane \ oci://ghcr.io/hoophq/helm-charts/hoopcontrolplane-chart --version $VERSION \ -f values.yaml \ --set image.tag=1.182.0-distroless \ --set config.LOG_LEVEL=debug ``` ## Control Plane Configuration Everything under `config` becomes an environment variable in a Secret attached with `envFrom`. A change to any of them rolls the pods on `helm upgrade`: the Deployment carries a checksum of the rendered Secret. ```yaml theme={"dark"} config: POSTGRES_DB_URI: 'postgres://:@:5432/' API_URL: 'https://cp.yourdomain.tld' ``` Those two are required. Everything else below has a default or is optional. ### Database The Control Plane stores its state in PostgreSQL, using the `private` schema for its own tables. This creates the database and a user with the privileges it needs: ```sql theme={"dark"} CREATE DATABASE hoopdb; CREATE USER hoopuser WITH ENCRYPTED PASSWORD 'my-secure-password'; -- switch to the created database \c hoopdb CREATE SCHEMA IF NOT EXISTS private; GRANT ALL PRIVILEGES ON DATABASE hoopdb TO hoopuser; GRANT ALL PRIVILEGES ON SCHEMA public to hoopuser; GRANT ALL PRIVILEGES ON SCHEMA private to hoopuser; GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO hoopuser; GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA private TO hoopuser; ``` > [!NOTE] > > If the password contains special characters, URL-encode it in the connection string. Append `?sslmode=disable` if your database does not support TLS. ```yaml theme={"dark"} config: POSTGRES_DB_URI: 'postgres://hoopuser:@:5432/hoopdb' ``` The chart provisions no database and `pglite://` is refused: it is single-node and serves one connection at a time. ### Authentication Authentication is **local by default**. The Control Plane manages users and passwords itself and signs its own tokens, so a database and an address are the whole configuration. Setting any `IDP_*` key selects OIDC instead: ```yaml theme={"dark"} config: IDP_ISSUER: 'https://idp-issuer-url' IDP_CLIENT_ID: 'client-id' IDP_CLIENT_SECRET: 'client-secret' # or, in place of the secret, a token file: idpFederatedToken.enabled sets it IDP_CLIENT_ASSERTION_FILE: '' IDP_CUSTOM_SCOPES: '' IDP_GROUPS_CLAIM: '' IDP_AUDIENCE: '' ``` `IDP_CLIENT_ID` becomes required once `IDP_ISSUER` is set, and so does a client credential: `IDP_CLIENT_SECRET`, or `idpFederatedToken.enabled: true`, which mounts a Kubernetes service account token and sets `IDP_CLIENT_ASSERTION_FILE`. The chart refuses to render without one, or with both. See [Sign in without a client secret](/docs/setup/configuration/idp/azure#sign-in-without-a-client-secret). The provider's callback is `/api/callback` — register that URL with your identity provider. See [Identity Providers](/docs/setup/configuration/idp/get-started) for the per-provider settings. ### API URL `API_URL` is the address the web app and every Sidecar reach this deployment on. It is **required**, and it must carry a scheme. ```yaml theme={"dark"} config: API_URL: 'https://cp.yourdomain.tld' ``` The process itself falls back to `http://127.0.0.1:8009` when the variable is absent, which is why the chart requires it: the fallback boots a pod that looks healthy and is not usable. ### TLS Two keys, and one rule: **set both to serve HTTPS, leave both empty to serve plaintext.** ```yaml theme={"dark"} config: TLS_CERT: 'base64://' TLS_KEY: 'base64://' ``` Nothing is generated, and half a pair serves plaintext rather than failing. Both values go through the environment loader, so three forms work: **Base64 encoded** ```sh theme={"dark"} echo "base64://$(cat server.crt | base64)" echo "base64://$(cat server.key | base64)" ``` **Path based** ```yaml theme={"dark"} config: TLS_CERT: 'file:///etc/hoop/certs/server.crt' TLS_KEY: 'file:///etc/hoop/certs/server.key' ``` Mount the files with [`extraVolumes`](#extra-volumes). > [!NOTE] > > The certificate file may carry the **root** and **intermediate CAs** as well. Order matters: > > ``` > > > > ``` Nothing here reaches the probes, because the chart renders none — an `httpGet` probe you write against a TLS listener must name `scheme: HTTPS` itself. ### Logging ```yaml theme={"dark"} config: GIN_MODE: 'release' # release | debug LOG_ENCODING: 'json' # json | console LOG_LEVEL: 'info' # debug | info | warn | error ``` ## Chart Configuration Everything below is a chart attribute rather than part of the Control Plane's environment: how the pod is built, what it is published as, and where it is scheduled. ### Image Configuration By default the chart pulls `hoophq/hoopcontrolplane:latest`, which is the Ubuntu flavour. ```yaml theme={"dark"} image: repository: hoophq/hoopcontrolplane pullPolicy: Always tag: 1.182.0 ``` | Tag | Base | | - | - | | ``, `latest` | Ubuntu 24.04 LTS, keeps a shell | | `-distroless` | distroless static, no shell, no package manager, about two thirds the size | The web UI is compiled into the binary, so **neither flavour carries webapp files** and both serve the app with no configuration. That is also what makes a distroless flavour possible. [Container Images](/docs/control-plane/container-images) covers what each flavour contains. ### Probes **The chart renders no probe.** `readinessProbe` and `livenessProbe` are both empty by default, and whatever you put under either one is rendered verbatim — any handler the Kubernetes Probe schema accepts, plus timings and thresholds. ```yaml theme={"dark"} readinessProbe: httpGet: path: /api/healthz port: 8009 initialDelaySeconds: 10 periodSeconds: 10 livenessProbe: httpGet: path: /api/healthz port: 8009 initialDelaySeconds: 10 periodSeconds: 10 ``` Health is `GET /api/healthz` on 8009, under `API_URL`'s path if it has one. Ten seconds and not five: the listener opens only after the migrations, the organization bootstrap and the identity provider, so an answer at all means the bootstrap finished. Add `scheme: HTTPS` inside `httpGet` when TLS is configured. A `tcpSocket` check on 8009 serves either listener from one stanza, at the cost of not calling the endpoint: ```yaml theme={"dark"} readinessProbe: tcpSocket: port: 8009 initialDelaySeconds: 10 periodSeconds: 10 ``` > [!WARNING] > > **Why there is no default.** The chart cannot know whether the listener speaks TLS. `TLS_CERT` and `TLS_KEY` decide it, and either can arrive through `extraSecret` or `existingSecret`, which no template can read. The kubelet does not negotiate, so a wrong scheme does not degrade — it stops the pod from ever becoming ready: > > ``` > Readiness probe failed: HTTP probe failed with statuscode: 400 > ``` > > That is Go answering `Client sent an HTTP request to an HTTPS server`. Certificate validity is not the issue in the other direction: kubelet HTTPS probes always skip verification and there is no field to change that. > > With neither probe set, the kubelet treats the container as ready as soon as it starts and never restarts it for health — a pod still running migrations takes Service traffic. Set them. ### Service One Service, one port. ```yaml theme={"dark"} service: enabled: true type: ClusterIP annotations: {} ``` `type: LoadBalancer` with the annotations your cloud provider expects is the whole configuration for a cluster without the Gateway API: ```yaml theme={"dark"} service: type: LoadBalancer annotations: service.beta.kubernetes.io/aws-load-balancer-type: nlb service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing ``` There is deliberately no source-range or traffic-policy plumbing. One HTTP port does not need it. ### Exposing it with the Gateway API The chart renders a Gateway and an HTTPRoute rather than an Ingress. This requires the Gateway API CRDs in your cluster — `istioctl install` for Istio, or the [upstream guides](https://gateway-api.sigs.k8s.io/guides/) for anything else. ```yaml theme={"dark"} gatewayApi: enabled: true createGateway: true gateway: gatewayClassName: istio listeners: - name: http hostname: cp.yourdomain.tld port: 80 protocol: HTTP allowedRoutes: namespaces: {from: Same} httpRoute: hostnames: [cp.yourdomain.tld] ``` Both `parentRefs` and `rules` have working defaults. The default rule is a `PathPrefix` on `API_URL`'s path, backed by this chart's Service on 8009 — which is the whole Control Plane, since it serves one HTTP port and nothing else: ```yaml theme={"dark"} rules: - matches: - path: {type: PathPrefix, value: /} backendRefs: - name: hoopcontrolplane port: 8009 ``` To attach to a Gateway somebody else owns, set `createGateway: false` and name it: ```yaml theme={"dark"} gatewayApi: enabled: true createGateway: false httpRoute: parentRefs: - name: shared-ingress namespace: infra sectionName: http ``` The chart refuses to render `createGateway: false` with no `parentRefs`: a route with no parent attaches to nothing and looks installed. It refuses `service.enabled: false` with no `rules` for the same reason from the other end — the default route's backend *is* that Service, so the route would resolve to nothing and every request would get a 500 from an install that looked fine. `listeners`, `addresses`, `infrastructure` and `backendTLS` pass through to the Gateway untouched, and setting `rules` replaces the default rule entirely. There is no Ingress template and no GRPCRoute. > [!NOTE] > > `backendTLS` is the client certificate the Gateway **presents** to backends, for mTLS, and it lives in the Gateway API **experimental** channel. The standard channel's Gateway CRD has no such field and prunes it silently, so it renders into the manifest and then disappears from the live object — check with `kubectl get gateway -o yaml` before relying on it. > > Validating the backend's own certificate is a different thing: a `BackendTLSPolicy` resource, which this chart does not render. ### Extra Environment Variables Anything this chart does not render goes in `extraSecret`, which becomes a second Secret attached with `envFrom`: ```yaml theme={"dark"} extraSecret: MY_VARIABLE: some-value ``` `existingSecret` references a Secret you manage yourself. The chart never creates or updates it: ```yaml theme={"dark"} existingSecret: hoop-controlplane-credentials ``` Order matters, because later entries win: the chart's own Secret, then `extraSecret`, then `existingSecret`. > [!WARNING] > > A Secret referenced by `existingSecret` is invisible to the chart, so editing it changes no checksum and `helm upgrade` rolls nothing. Run `kubectl rollout restart deploy/-hoopcontrolplane` after you change it, or use a controller that annotates the pods for you. ### Extra Volumes For what the configuration references by path: a TLS certificate under `file:///...`, an identity provider CA bundle. ```yaml theme={"dark"} config: TLS_CERT: 'file:///etc/hoop/certs/server.crt' TLS_KEY: 'file:///etc/hoop/certs/server.key' extraVolumes: - name: api-tls secret: secretName: hoop-controlplane-tls defaultMode: 0400 extraVolumeMounts: - name: api-tls mountPath: /etc/hoop/certs readOnly: true ``` > [!NOTE] > > Mount any Secret holding a private key with `defaultMode: 0400`. Kubernetes writes secret files `0644` by default. ### Service Account With `create: true` the chart makes one named after the release. With `create: false`, `name` points at an account that already exists — the shape workload identity wants. ```yaml theme={"dark"} serviceAccount: create: false name: hoop-controlplane annotations: {} ``` Leaving both unset means the pod uses the namespace default. ### Replicas and Deployment Strategy ```yaml theme={"dark"} replicas: 1 deploymentStrategy: type: Recreate ``` > [!WARNING] > > **Read this before raising `replicas`.** > > Slack's socket mode opens one websocket per process and nothing coordinates them — no lease, no advisory lock, only in-process mutexes. With Slack configured for an organization, two replicas post every review twice and race each other's clicks. Slack documents that a payload may go to any open connection with no pattern to rely on, so a click can be handled by the replica that is not holding the waiting session: the verdict is written and the session is never released. > > Raising `replicas` is safe when **no organization in this deployment has Slack configured**. Everything else in the process is stateless HTTP over a shared database. > > The chart cannot enforce this — whether Slack is configured lives in a database row no chart can read — so it prints a warning above one replica and leaves the decision to you. > > The same constraint applies across deployments: a Gateway and a Control Plane pointed at the same database both read that row and both open a socket. The strategy is `Recreate` for the same reason. At one replica, `RollingUpdate`'s default surge runs two pods through every upgrade, which is two Slack sockets on a timer. The Control Plane holds no sessions, so the short API gap drops nothing. A deployment already running several replicas has accepted that condition — set `RollingUpdate` there. ### Computing Resources The chart is API-only: it carries no sessions and runs no proxies. ```yaml theme={"dark"} resources: limits: cpu: 1024m memory: 1Gi requests: cpu: 256m memory: 512Mi ``` ### Node Selector This configuration describes a pod that has a node selector, `disktype: ssd`. This means that the pod will get scheduled on a node that has a `disktype=ssd` label. See [this documentation](https://kubernetes.io/docs/tasks/configure-pod-container/assign-pods-nodes/) for more information. ```yaml theme={"dark"} # -- Node labels for pod assignment nodeSelector: disktype: ssd ``` ### Tolerations See this article explaining how to configure [tolerations](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/) ```yaml theme={"dark"} # -- Toleration labels for pod assignment tolerations: - effect: NoExecute key: spot value: "true" - effect: NoSchedule key: spot value: "true" ``` ### Node Affinity See [this article](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#affinity-and-anti-affinity) explaining how to configure affinity and anti-affinity rules ```yaml theme={"dark"} # -- Affinity settings for pod assignment affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: topology.kubernetes.io/zone operator: In values: - antarctica-east1 ``` ### Security Context Both are empty by default and pass through untouched. ```yaml theme={"dark"} # -- Pod level podSecurityContext: runAsNonRoot: true seccompProfile: {type: RuntimeDefault} # -- Container level securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true capabilities: {drop: [ALL]} ``` The image already runs as uid 10001. ### Annotations ```yaml theme={"dark"} # -- Applied to the pod template podAnnotations: prometheus.io/scrape: 'true' # -- Applied to the Deployment object deploymentAnnotations: argocd.argoproj.io/sync-wave: '1' ``` ### Naming `nameOverride` changes the base the resource names are built from; `fullnameOverride` replaces the whole name and drops the release prefix. ```yaml theme={"dark"} nameOverride: '' fullnameOverride: '' ``` > [!WARNING] > > Both feed the Deployment's selector, which is **immutable** in Kubernetes. Changing either on a live release makes `helm upgrade` fail. Settle them at install time. ## Generating Manifests If you prefer using manifests over Helm, we recommend this approach. It allows you to track any modifications to the chart whenever a new version appears. You can apply a diff to your versioned files to identify what has been altered. ```bash theme={"dark"} VERSION=$(curl -s https://releases.hoop.dev/release/latest.txt) helm template hoopcontrolplane \ oci://ghcr.io/hoophq/helm-charts/hoopcontrolplane-chart --version $VERSION \ -f values.yaml ``` ## Next > **[Connect a Sidecar](/docs/control-plane/connect-sidecar)** > > Issue a token, point a Sidecar at the Control Plane, and confirm it picked up its configuration. > **[Environment Variables](/docs/control-plane/environment-variables)** > > Every variable the service reads. # Environment Variables Source: https://mintlify.hoop.dev/docs/control-plane/environment-variables Every variable the Control Plane reads, what it does, and what it defaults to. The Control Plane reads its whole configuration from the environment. Fourteen variables, two of them required. ```bash theme={"dark"} POSTGRES_DB_URI='postgres://hoopuser:@db-host:5432/hoopdb' API_URL='https://cp.yourdomain.tld' ``` *** ## At a glance | Variable | Required | Default | | - | - | - | | `POSTGRES_DB_URI` | **yes** | — | | `API_URL` | **yes** | — | | `IDP_ISSUER` | no | unset, meaning local authentication | | `IDP_CLIENT_ID` | with an issuer | — | | `IDP_CLIENT_SECRET` | with an issuer, unless `IDP_CLIENT_ASSERTION_FILE` is set | — | | `IDP_CLIENT_ASSERTION_FILE` | no | unset, meaning the client secret authenticates the client | | `IDP_CUSTOM_SCOPES` | no | `openid`, `profile`, `email` only | | `IDP_GROUPS_CLAIM` | no | `https://app.hoop.dev/groups` | | `IDP_AUDIENCE` | no | empty, no `audience` parameter sent | | `TLS_CERT` | no | empty, serving plaintext | | `TLS_KEY` | no | empty, serving plaintext | | `LOG_LEVEL` | no | `info` | | `LOG_ENCODING` | no | `json` | | `GIN_MODE` | no | `release` | | `MIGRATION_PATH_FILES` | no | empty, using the embedded migrations | *** ## Database `POSTGRES_DB_URI` is where the Control Plane stores its state. It runs migrations and the organization bootstrap against this database before it listens, so it has to be reachable at startup. ```bash theme={"dark"} POSTGRES_DB_URI='postgres://hoopuser:@db-host:5432/hoopdb' ``` URL-encode a password containing special characters. Append `?sslmode=disable` if your database does not support TLS. *** ## Address `API_URL` is the address the web app and every Sidecar reach the deployment on. It must carry a scheme. ```bash theme={"dark"} API_URL='https://cp.yourdomain.tld' ``` *** ## Identity provider Authentication is **local by default**: the Control Plane manages users and passwords itself. Setting `IDP_ISSUER` switches it to OIDC, and a client id and a secret, or a client assertion file, are required with it. ```bash theme={"dark"} IDP_ISSUER='https://login.microsoftonline.com//v2.0' IDP_CLIENT_ID='' IDP_CLIENT_SECRET='' ``` | Variable | Holds | | - | - | | `IDP_ISSUER` | The provider's issuer URL. Discovery runs against `/.well-known/openid-configuration` | | `IDP_CLIENT_ID` | The application's client id | | `IDP_CLIENT_SECRET` | The application's client secret | | `IDP_CLIENT_ASSERTION_FILE` | A JWT file that replaces the client secret (RFC 7523), such as a Kubernetes service account token. Read on each token request | | `IDP_CUSTOM_SCOPES` | Extra scopes, comma-separated, added to `openid`, `profile` and `email` | | `IDP_GROUPS_CLAIM` | The claim to read group membership from | | `IDP_AUDIENCE` | Sent as the `audience` parameter on the authorization request | The redirect the provider must have registered is **`/api/callback`**. It is built from `API_URL`, so the two move together. The startup output names the one it resolved: ``` loaded oidc provider configuration, redirect-url=https://cp.example.tld/api/callback, ... ``` `IDP_GROUPS_CLAIM` defaults to `https://app.hoop.dev/groups`. Set it when your provider puts groups somewhere else — `groups` for Keycloak and Okta, for instance. `IDP_CUSTOM_SCOPES` takes a comma-separated list; each entry is trimmed and one already present is skipped. `IDP_AUDIENCE` is only added to the authorization request when it is non-empty. Auth0 is the common case. `IDP_CLIENT_ASSERTION_FILE` replaces `IDP_CLIENT_SECRET`: set one, not both, or the Control Plane does not start. With Entra ID, the chart's `idpFederatedToken` block mounts a service account token and sets it. See [Sign in without a client secret](/docs/setup/configuration/idp/azure#sign-in-without-a-client-secret). > [!NOTE] > > There is no `AUTH_METHOD`. The method is inferred: any `IDP_*` variable selects OIDC, none leaves local. > > SAML is not configurable by environment at all. It is read from the database, and once that row exists the database supplies the method too — so an `authconfig` row overrides everything above at runtime, and these values are the boot defaults rather than the last word. > > See [Identity Providers](/docs/setup/configuration/idp/get-started) for the per-provider settings. *** ## TLS Two variables, one rule: **set both to serve HTTPS, leave both empty to serve plaintext.** ```bash theme={"dark"} TLS_CERT='base64://' TLS_KEY='base64://' ``` | Variable | Holds | | - | - | | `TLS_CERT` | The server certificate, with its intermediate and root CAs appended if it has them | | `TLS_KEY` | The private key | Nothing is generated and half a pair serves plaintext rather than failing. Three forms work for either value: | Form | Example | | - | - | | Inline PEM | the certificate text itself | | Base64 | `base64://` | | File path | `file:///etc/hoop/certs/server.crt` | *** ## Logging ```bash theme={"dark"} LOG_LEVEL='info' LOG_ENCODING='json' GIN_MODE='release' ``` | Variable | Values | Default | | - | - | - | | `LOG_LEVEL` | `debug`, `info`, `warn`, `error` | `info` | | `LOG_ENCODING` | `json`, `console`, `human`, `verbose` | `json` | | `GIN_MODE` | `release`, `debug` | `release` | `LOG_LEVEL` is matched case-insensitively and anything unrecognised falls back to `info` rather than failing. `LOG_ENCODING` decides the encoder, and anything other than the four values above produces JSON. `json` is the right choice for a log pipeline; `console` and `human` are for reading in a terminal. `GIN_MODE` set to `debug` adds a per-request HTTP access log on top of whatever `LOG_LEVEL` allows. It is the only thing this variable changes here. *** ## Migrations SQL migrations are compiled into the binary and run at every boot, so `MIGRATION_PATH_FILES` is empty by default and nothing is read from disk. Set it only if you manage migration files yourself: ```bash theme={"dark"} MIGRATION_PATH_FILES='/etc/hoop/migrations' ``` *** ## Next > **[Kubernetes](/docs/control-plane/deployment/kubernetes)** > > Deploy it on Kubernetes. > **[Container Images](/docs/control-plane/container-images)** > > What each flavour contains and what it already sets. # Overview Source: https://mintlify.hoop.dev/docs/control-plane/install Deploy the Control Plane in your own infrastructure with Docker Compose, Kubernetes or AWS. The [Control Plane](/docs/core-concepts/control-plane) is the service your Sidecars register with and pull configuration from. You run one per environment. > [!NOTE] > > The Control Plane is an **Enterprise** feature and requires a license. [Talk to us](https://hoop.dev/start) to get one, or use the [managed service](https://use.hoop.dev) and skip this page entirely. *** ## Before you start * A license key. * A hostname your Sidecars can reach over HTTPS. Sidecars only ever make outbound requests, so the Control Plane does not need to reach *them*. * A PostgreSQL database. The compose file below brings one up; point `POSTGRES_DB_URI` at your own instead if you have one. *** ## How to deploy it The mode is chosen by the subcommand: `hoop start control-plane` rather than `hoop start gateway`. One image serves both. > **[Docker Compose](/docs/control-plane/deployment/docker-compose)** > > Postgres and the Control Plane on a single host, with an optional Sidecar > connected to it. Good for evaluation and for single-host production. > **[Kubernetes](/docs/control-plane/deployment/kubernetes)** > > The Helm chart, on any cloud provider. Bring your own PostgreSQL; publish it > with a Service or the Gateway API. *** ## After it is running **1. Create the first account** Authentication is local by default — the Control Plane manages users and passwords itself, so you can sign in as soon as it is up. **2. Apply your license** See [License Management](/docs/setup/license-management). **3. Connect your first Sidecar** Issue a token, point a Sidecar at the Control Plane, and confirm it picked up its configuration. See [Connect a Sidecar](/docs/control-plane/connect-sidecar). *** ## Keeping it current Upgrade the Control Plane first, then the Sidecars. A Control Plane at 1.210.0 or later serves each Sidecar only what its version can read, so Sidecars can lag behind it. See [Upgrading](/docs/control-plane/connect-sidecar#upgrading) for the details. *** ## Next > **[Connect a Sidecar](/docs/control-plane/connect-sidecar)** > > Token, server host, and confirming the handshake. > **[Environment Variables](/docs/control-plane/environment-variables)** > > Every variable the Control Plane reads. # Slack Source: https://mintlify.hoop.dev/docs/control-plane/slack Send held statements to Slack. Approvers approve there without signing in. When a listener holds a statement for a person ([`require_approval`](/docs/setup/configuration/hoop-sidecar/risk-analysis#holding-a-statement-for-a-person)), the Control Plane posts an approval request to Slack. An approver clicks **Approve** or **Reject** in the message. hoop finds the hoop user behind the Slack user by email and checks that user's groups. ![A Hoop Bot message in Slack showing a held DELETE statement on the appdb connection, with Approve and Reject buttons](https://mintcdn.com/hoopdev/FEXd2DY1jsunoAwn/images/integrations/control-plane-slack.webp?fit=max\&auto=format\&n=FEXd2DY1jsunoAwn\&q=85\&s=fa1b1e027bf0110c346e354751e9829b) A held statement in Slack. The approver sees who ran it, on which connection, and the exact statement. > [!NOTE] > > This page is for the Control Plane. For the Gateway, see [Slack](/docs/integrations/slack). *** ## How it works ```mermaid theme={"dark"} sequenceDiagram actor R as Approver participant IdP as Identity provider participant S as Sidecar participant CP as Control Plane participant SL as Slack R->>IdP: log in to the Control Plane IdP->>CP: the user's groups (each login) S->>CP: hold a statement (approval_rule) CP->>SL: post the approval request to the listener's channels, else the fallback channel R->>SL: click Approve or Reject SL->>CP: the click (Socket Mode) CP->>SL: read the Slack user (users.info) CP->>CP: find the hoop user by Slack ID, else email, then check status and group alt allowed CP->>SL: update the message: approved, or rejected with the reason else refused CP-->>SL: tell only the clicker why end S->>CP: poll the approval request, every 5 seconds CP-->>S: approved: run the statement ``` * **Approvers are hoop users.** Their groups come from your identity provider at each login. * **Channels are per listener.** A listener without channels uses the fallback channel. * **Socket Mode.** The Control Plane dials out to Slack. No inbound URL is exposed. *** ## Requirements * Permission to [create a Slack app](https://api.slack.com/apps) and install it in your workspace. * An admin user on the Control Plane. * **One Slack app for this Control Plane only.** Slack sends each click to any open connection of the app. A Gateway or a second Control Plane on the same app token takes clicks that are not theirs. * **One Control Plane replica** with Slack configured. See [Replicas and Deployment Strategy](/docs/control-plane/deployment/kubernetes#replicas-and-deployment-strategy). *** ## 1. Create the Slack app **1. Create the app from a manifest** Open [a new Slack app from an app manifest](https://api.slack.com/apps?new_app=1), choose the workspace and paste this manifest. > **slack-manifest.json** > > ```json theme={"dark"} > { > "display_information": { > "name": "hoop", > "description": "Approve statements held by hoop sidecars", > "background_color": "#7a7879" > }, > "features": { > "bot_user": { > "display_name": "Hoop Bot", > "always_online": true > } > }, > "oauth_config": { > "scopes": { > "bot": [ > "chat:write", > "chat:write.public", > "users:read", > "users:read.email" > ] > } > }, > "settings": { > "interactivity": { > "is_enabled": true > }, > "org_deploy_enabled": false, > "socket_mode_enabled": true, > "token_rotation_enabled": false > } > } > ``` | Scope | Why | | - | - | | `chat:write` | Post and update approval requests, and answer an approver privately | | `chat:write.public` | Post to public channels without inviting the bot | | `users:read` | Read the Slack user who clicked | | `users:read.email` | Match a Slack user to a hoop user by email | **2. Install it** Click **Install to Workspace**. Then open **OAuth & Permissions** and copy the **Bot User OAuth Token** (`xoxb-…`). **3. Create the app-level token** Open **Basic Information** → **App-Level Tokens** → **Generate Token and Scopes**. Name it `hoop`, add the scope `connections:write`, and copy the token (`xapp-…`). **4. Prepare the channels** Choose a fallback channel, and optionally one channel per listener. For a **private** channel, invite the bot: type `/invite @Hoop Bot` in the channel. hoop takes channel **IDs**, not names. Open the channel details and copy the **Channel ID** at the bottom (`C0…`). > [!TIP] > > Already have a Slack app for hoop? Add the `users:read` and `users:read.email` scopes and reinstall it. Slack does not apply new scopes before a reinstall. Do not share it with a Gateway. *** ## 2. Configure the Control Plane **1. Save the tokens** Go to **Settings** → **Slack** → **Configurations**. Paste the **Slack bot token** and the **Slack app token**. Optionally set the **Fallback channel**: it receives the approval requests of listeners with no channel. Click **Save**. The Control Plane log shows `connected to Slack with Socket Mode`. **2. Choose a channel per listener** Open the **Listeners** tab. It lists every listener of every Sidecar. Type the channel IDs in a listener's row and click **Save** on that row. A listener with no channel posts to the fallback channel. With neither, the approval request is filed but nobody is notified in Slack, and the Control Plane logs a warning. *** ## 3. Give approvers their groups An approver is a hoop user in a group the rule names. The groups come from the login: * **With an identity provider (OIDC or SAML):** each login replaces the user's groups with the ones the provider sends. OIDC keeps the admin group; SAML does not. For OIDC, set `IDP_GROUPS_CLAIM` to the claim that holds them. See [Identity provider](/docs/control-plane/environment-variables#identity-provider). * **With local auth**, or a login that sends no groups: set the groups on **Settings** → **Users**. An approver needs a hoop user: they log in once, or an admin adds them on **Settings** → **Users**. With an identity provider, no invitation is needed: the first login creates the user. With local auth, only an admin creates users. A group change in the identity provider reaches hoop at the approver's next login. After login, an admin lands on **Sidecars** and every other user on **Approvals**. > [!WARNING] > > Microsoft Entra ID sends group IDs (GUIDs) by default, not names. Name those IDs on the rule, or configure Entra to send group names. If an approver's Slack email differs from their hoop email, set their **Slack ID** on **Settings** → **Users**. To copy it in Slack: open the person's profile → **⋮** → **Copy member ID** (`U…`). *** ## 4. Name the approvers on the rule Go to **AI Analyzer** and open the rule. Set a risk level to **Hold for approval**, then pick the groups in **Approvers**. The list shows every group of the organization. One approval from any of them releases the statement. **While held for approval** picks how the client waits: for the decision, or denied at once to run the statement again after approval. See [Return mode for agents](/docs/setup/configuration/hoop-sidecar/risk-analysis#return-mode-for-agents). **Time to decide** and **Time to use an approval** limit how long the approval request stays open. Both are optional. See [Time limits](/docs/setup/configuration/hoop-sidecar/risk-analysis#time-limits). With no group, the admin group approves. The Control Plane sets the listener's `approval_rule` to this rule for you. See [Holding a statement for a person](/docs/setup/configuration/hoop-sidecar/risk-analysis#holding-a-statement-for-a-person). *** ## 5. Approve in Slack The **Hoop Approval** message shows the Sidecar, the listener, the statement and one button per group that may approve. **Reject** asks for an optional reason. **More details** opens the approval request on the Control Plane **Approvals** page, which every signed-in user can open. On a click, hoop finds the approver: 1. The hoop user with that Slack ID. 2. Else, exactly one hoop user with the Slack user's email. The user must be active or invited, and in the group of the button. Otherwise only the clicker sees why: see [Messages in Slack](#messages-in-slack). The Sidecar sees the approval on its next poll, within 5 seconds. *** ## Messages in Slack ### On the approval message Everyone in the channel sees these. They replace the buttons as the approval request changes, whether an approver acts in Slack, on the Approvals page or through the API. | Message | Meaning | | - | - | | ` approved this session at