> ## Documentation Index
> Fetch the complete documentation index at: https://docs.acornops.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Integrations

> Build bots, workflow adapters, and custom clients on top of AcornOps

Use this path when you want to build around AcornOps rather than only operate the platform. Common examples include Slack, Telegram-style bots, incident workflow automation, custom dashboards, and internal tools that react to AcornOps run events.

## Integration surfaces

| Surface                        | Use it for                                                                                                                     | Notes                                                                                                                                                                                                                                                                                               |
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Control-plane API              | Workspaces, targets, Kubernetes clusters, VMs, Agents, sessions, runs, approvals, MCP registries, and Agent-owned capabilities | Public API under your deployment host, such as `https://api.example.com/api/v1`; most v1 calls require an authenticated AcornOps user session. Installed external clients can use only the explicitly documented linked-user routes. The public demo API is `https://api.demo.acornops.dev/api/v1`. |
| Webhooks                       | Event-driven bots and workflow automation                                                                                      | Verify every delivery signature before processing the payload.                                                                                                                                                                                                                                      |
| Run events and SSE             | Custom run timelines or signed-in user experiences                                                                             | Use replayable run events and `GET /api/v1/runs/{runId}/stream` for live updates.                                                                                                                                                                                                                   |
| Agent capability configuration | Connecting external tool providers                                                                                             | Add remote MCP servers to one Agent through the control-plane API or management console, then review discovered tools.                                                                                                                                                                              |

Execution-engine and LLM-gateway runtime APIs are internal platform surfaces. Do not call them from external bots or customer integrations.

## Auth model for integrations

The public control-plane API is session-based. Browser clients use the same `SameSite=Lax` session cookie as the management console. Mutating requests with a session cookie, plus password login and signup before a session exists, must echo the CSRF token in `x-csrf-token`.

AcornOps v1 does not expose a public PAT or broad bot service-account credential for the control-plane API. Installed external integration clients authenticate with raw bearer tokens whose SHA-256 hashes are configured in `EXTERNAL_INTEGRATION_CLIENTS_JSON`.

For v1 integrations, keep privileged decisions attributable:

* use outgoing webhooks for bot notifications and the authorized Workflow API
  for launches; AcornOps does not currently expose an inbound
  webhook-to-Workflow trigger,
* require an explicit linked-user confirmation before submitting a write approval,
* send users to the management console for approvals outside the integration's own troubleshooting runs or Workflow executions and for management actions,
* never auto-approve because a webhook or run event was received.

Deployments may explicitly add `create_read_write_runs` to a registered external integration client's allowed capabilities and the linked user's workspace grant. That lets the integration request read-write troubleshooting runs and active read-write or approval-gated Workflows when the linked user's workspace role also allows it. Write-capable tools still pause on AcornOps approval gates. The exact integration link and client recorded on the run or Workflow execution may submit the linked user's explicit approval or rejection. It cannot decide approvals for browser-created executions, another link/client, schedules, or system triggers.

Internal service tokens such as `ORCH_SERVICE_TOKEN`, `EXECUTION_ENGINE_DISPATCH_TOKEN`, and `LLM_GATEWAY_ADMIN_TOKEN` are platform credentials. External integration client bearer tokens are narrow adapter credentials, not public PATs. The built-in MCP bridge uses the run-scoped JWT minted for the active execution.

## External integration account-link endpoints

AcornOps exposes a narrow external integration account-link contract for an external integration client. External integration client-side command handling, message copy, event handling, retries, and channel behavior belong outside AcornOps.

The integration client can use:

* `POST /api/v1/auth/external-integrations/link` with `Authorization: Bearer <external-integration-client-token>` and body `{ "externalUserId": "<external-user-id>", "externalDisplayName": "<optional-safe-name>" }` to create a short-lived browser link.
* `POST /api/v1/auth/external-integrations/resolve` with the same bearer token and body `{ "externalUserId": "<external-user-id>" }` to resolve whether the external identity is `linked` or `unlinked`.
* `POST /api/v1/auth/external-integrations/revoke` with the same bearer token and body `{ "externalUserId": "<external-user-id>" }` to revoke the integration client's durable link for that external user.

AcornOps returns a management-console `linkUrl` under `/integrations/external/link`. The user opens that URL within the token TTL, and the console shows the normal AcornOps login page when no browser session exists. After password or OIDC sign-in establishes a browser session, the console calls `POST /api/v1/auth/external-integrations/link/preview` to show safe pending-link metadata and grantable workspaces. The console calls `POST /api/v1/auth/external-integrations/link/complete` only after the user explicitly approves the external account and selected workspace grants. Signed-in users can list, edit workspace grants for, and unlink their own active external links through the user-owned external integration endpoints.

Linked bot requests are authorized per workspace. Effective permissions are the linked AcornOps user's workspace role intersected with the registered integration client's capability ceiling and the user's saved workspace grant. A workspace without a grant is hidden or denied to the external integration.

Workflow executions started by an external integration retain the registered client display name for operator-facing provenance in AcornOps. Exact execution responses returned to the integration keep the existing restricted representation and do not expose that browser-only provenance or internal request identity.

External integration clients should not store browser cookies, OIDC tokens, raw link tokens, or an AcornOps user ID as authorization material. Browser login and link completion are AcornOps-owned session flows, not external integration APIs.

## Linked Workflow access

An installed external client can list and run a deliberately narrow set of Workflows for a linked user. Send both the installed client bearer token and the external identity observed from the provider:

```http theme={null}
Authorization: Bearer <external-integration-client-token>
x-acornops-external-user-id: <external-user-id>
```

The linked identity is authorized only when the user has a live workspace role
and saved grants for `read_workspace_data`, `create_sessions`, and the run
capability required by the Workflow, plus every other Workflow permission.
Active ungated read-only definitions require `create_read_only_runs`. Active
read-write or approval-gated definitions require the deployment-owned client
ceiling and user grant to opt into `create_read_write_runs`. AcornOps still
applies Workflow compilation, catalog readiness, Agent tool inheritance,
signed target-tool routing, tool narrowing, and approval gates.

The external client may use:

* `GET /api/v1/workspaces/{workspaceId}/workflows` to list eligible definitions.
* `GET /api/v1/workflows/{workflowId}?workspaceId={workspaceId}` to refresh one eligible definition.
* `POST /api/v1/workflows/{workflowId}/sessions` to create a session owned by the linked AcornOps user.
* `POST /api/v1/workflow-sessions/{sessionId}/messages` with `{ kind: "launch", clientRequestId? }` for the first execution, then `{ kind: "follow_up", content, clientRequestId? }` for replies.

Reuse `clientRequestId` only when retrying the same provider message; use a new
value for a new user message. This makes transport retries idempotent without
making unrelated requests collide. Runtime `inputs`, `targetId`, and
`targetType` body fields are rejected. External credentials cannot list arbitrary Workflow
sessions or use another user's session, and write access remains an explicit
three-layer opt-in.

## Bot adapter pattern

An external integration adapter usually follows this flow:

1. Ask the linked AcornOps user with `manage_webhooks` to create a webhook subscription for the events the bot needs.
2. Verify `AcornOps-Signature` using the subscription secret.
3. Map the event to a channel, thread, incident, or user-visible card.
4. For read-only context, link to the management console, use an authenticated user session, or call an explicitly documented linked-user route with the installed client credential and observed external user ID.
5. For write approvals, render approve and reject controls only when the click can be tied back to a real AcornOps user.
6. Submit approval decisions to `POST /api/v1/runs/{runId}/approvals/{approvalId}/decision`.

Approval decisions are intentionally not just webhook acknowledgements. The first recorded decision wins; conflicting later decisions return the current approval state.

For a Workflow, keep the returned `workflowSessionId` as the external thread
mapping. Each external message requires a new `clientRequestId` and creates a
new execution in that session. A reply after completion retains the conversation
history and stored Workflow snapshot, but it creates new run IDs and fresh
approvals. The current Workflow must remain active, and AcornOps recompiles the
session's access from current effective permissions for every message.

Use `GET /api/v1/workflow-executions/{executionId}` for sanitized state and
`GET /api/v1/workflow-executions/{executionId}/stream` for aggregate,
replayable SSE. The execution stream discovers each next-step run and approval,
so adapters do not need to poll an unknown sequence of individual run streams.
Resume with `Last-Event-ID` or `after`. Any linked integration with effective
workspace read access may inspect safe execution metadata and events, including
executions started elsewhere. Session replies, approval decisions, and report
metadata/downloads remain restricted to the exact originating link and client.

Direct run reads follow the same disclosure boundary. Linked integrations see
a bounded run projection, and only the exact originating link/client receives
the final assistant output needed by its adapter. External run event lists,
per-run SSE, and nested aggregate run events keep lifecycle and safe approval
metadata while removing prompts, reasoning, token deltas, raw tool arguments,
and tool results.

Run approval lists and decision responses use the same boundary. Linked
integrations receive only bounded control metadata such as approval identity,
safe summary, state, target, and expiry. Executable arguments, tool references
and digests, actor identifiers, continuation state, and tool results remain
browser/internal-only.

## Webhook events

Webhook events and delivery jobs are stored durably in Postgres and signed with
HMAC-SHA256. Delivery is at least once: consumers must handle duplicate and
out-of-order events. One stable event ID and immutable body are reused across
all recipients and retry attempts.

Delivery URLs must use HTTPS. AcornOps rejects embedded credentials, IP-literal URLs, redirects, localhost, metadata endpoints, and reserved destinations. A deployment can opt an exact DNS hostname or leading-wildcard hostname into private-address delivery, but this does not weaken the remaining URL and DNS checks.

Workspace users with `permissions.manage_webhooks` can create, edit, disable, delete, and inspect delivery history for outgoing webhooks from Workspace Settings. The create response returns the signing secret once. Store that secret in your integration and do not put it in a delivery URL.

Webhook subscriptions store concrete event types. The management console may offer event group shortcuts, but it expands those groups before saving the subscription.

Each delivery includes:

* `AcornOps-Event-Id`
* `AcornOps-Event-Type`
* `AcornOps-Timestamp`
* `AcornOps-Signature`

Target-scoped events include `targetId` and `targetType`. Kubernetes events also include `clusterId`, which matches the Kubernetes target ID.

The signature input is `timestamp + "." + raw_json_body`, encoded as `v1=<hex>`.

### Issue lifecycle events

Subscribe to these events for issue alerts:

* `issue.created.v1` when a new fingerprint becomes active
* `issue.reopened.v1` when a resolved issue becomes active again
* `issue.resolved.v1` after the resolution grace period

Each issue event has `subject.type: "issue"` and includes a bounded issue
snapshot in `data`. Use `lifecycleVersion` to reject older state and `stateAsOf`
to distinguish the authoritative snapshot time from the later delivery time.
The payload excludes raw findings, observations, logs, search text, and latest
evidence.

Issue webhooks are current-action notifications, not a complete audit log.
When an issue enters recovery, AcornOps pauses pending created or reopened
notifications without consuming delivery attempts. Resolution or reopening
supersedes older pending lifecycle notifications. A receiver can therefore see
`issue.resolved.v1` without first receiving `issue.created.v1`. Query the issue
API for authoritative current state.

### Retry and subscription behavior

AcornOps retries transient network and DNS failures, timeouts, HTTP `408`,
`425`, `429`, and `5xx` responses. It honors a bounded `Retry-After` value or
uses jittered exponential backoff, and stops after 10 attempts or 24 hours.
Redirects, blocked destinations, configuration failures, and other
nonretryable `4xx` responses are terminal.

The recipient set is captured when an event occurs. New subscriptions do not
receive historical events. Before each attempt, AcornOps rechecks whether the
subscription is enabled and still selects the event and target, then uses its
current canonical URL and signing secret. Delivery ordering is not global.

## External webhook route connect/status

Some bot adapters create one delivery route per external user or destination, then ask the AcornOps user to subscribe workspace events to that route URL. After the user links the external account and creates the webhook subscriptions, the bot can claim live subscription metadata for that route.

For the Mattermost bot, run `!webhook create` to obtain the user-level delivery URL. The same linked AcornOps user must add that exact URL to one or more subscriptions in Workspace Settings and then run `!webhook connect`. The connect call is the secret handoff for this route: it rotates each matching subscription secret and returns the new value once over authenticated TLS. Do not paste a signing secret into Mattermost or put it in the delivery URL.

Connect a route:

```http theme={null}
POST /api/v1/external-integrations/webhook-routes/connect
Authorization: Bearer <external-integration-client-token>
x-acornops-external-user-id: <external-user-id>
Content-Type: application/json
```

```json theme={null}
{
  "deliveryUrl": "https://bot.example.com/acornops/webhooks/routes/route-token"
}
```

AcornOps compares the canonical delivery URL exactly and returns only subscriptions created by the linked AcornOps user while that user still has `permissions.manage_webhooks`. Each successful connect rotates the matching signing secrets and returns the fresh `signingSecret` values in that response. Treat reconnect as the documented secret recovery and rotation flow.

Check route status:

```http theme={null}
GET /api/v1/external-integrations/webhook-routes/status?deliveryUrl=<url-encoded-delivery-url>
Authorization: Bearer <external-integration-client-token>
x-acornops-external-user-id: <external-user-id>
```

Status responses return `unconfigured`, `configured`, or `connected` plus current workspace/event/enabled state. Status always reloads live AcornOps authorization and subscription state and never includes signing secrets. The Mattermost bot's `!webhook status` command uses this route without exposing its locally retained secrets.

Write approval integrations should handle:

* `run.tool_approval_requested.v1`
* `run.tool_approval_decided.v1`

When a run or aggregate Workflow execution stream reports a pending write
approval, the originating linked integration may collect an explicit user
confirmation. For approvals outside that narrow scope, send the user to:

```text theme={null}
{MANAGEMENT_CONSOLE_BASE_URL}/workspaces/{workspaceId}/approvals?runId={runId}&approvalId={approvalId}
```

MCP server integrations may also care about:

* `mcp.server.created.v1`
* `mcp.server.updated.v1`
* `mcp.server.deleted.v1`
* `mcp.server.tested.v1`

Use the API reference sidebar for webhook endpoint schemas and examples.

## Tool and MCP integrations

There are two different integration directions:

| Goal                                    | Recommended path                                                                                                                                    |
| --------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| Let AcornOps call your external tools   | Expose an MCP server, install it on one Agent, test discovery, then review exact server/tool pairs.                                                 |
| Let your app react to AcornOps activity | Subscribe to webhooks and use an authenticated user session or an explicitly documented linked-user endpoint when additional API context is needed. |

Remote MCP servers can receive non-secret `publicHeaders`. Credentials must use the secret-backed auth fields. Platform scope headers such as `x-workspace-id`, `x-target-id`, `x-target-type`, and `x-run-id` are reserved and added by the gateway.

See [MCP and tools](/use/tools-and-mcp) for MCP setup and header policy.

## Start here

Use this sequence for a new integration:

1. Confirm the platform is deployed and reachable from your integration host.
2. Decide whether the integration is webhook-driven, user-session driven, linked-external-user driven, or a combination.
3. Create a workspace webhook subscription for the required event types.
4. Verify signatures before acting on payloads.
5. Use [API overview](/developer/api-overview) to confirm API boundaries, then use the API reference sidebar for endpoint schemas.
6. Use [MCP and tools](/use/tools-and-mcp) only when AcornOps should call tools exposed by another system.
