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

# Slack

> Connect an identity to your Slack workspace, search retained history, act on conversations, and route events to your runtime

<Note>Slack is in beta.</Note>

Connect your existing Inkbox identity to Slack. Each identity has its own Slack app, created in a workspace your organization has configured. The connection has its own permissions and disconnect action.

Your agent can read accessible conversations and threads, send and edit messages, use reactions and pins, upload and download files, and receive [Slack webhooks](/docs/api/slack/webhooks). Inkbox also captures [retained message history](/docs/api/slack/archive) for keyword search and controlled backfills. File bytes remain live reads, not archived copies.

The SDK and CLI examples in this guide require version `0.7.11` or later.

## Connect your workspace

1. Open your identity’s **Slack** page in the [Inkbox Console](https://inkbox.ai/console), or go to **Channels → Slack**, choose **Enable Slack**, and select an agent.
2. For your first workspace, follow [Your Slack apps](https://api.slack.com/apps), select the intended workspace, and generate an app-configuration **access token** and **refresh token** under **Your App Configuration Tokens**. Paste both into the Console. For later apps, the **Workspace** dropdown defaults to a saved workspace. Select **Connect another workspace** to enter a new token pair.
3. Choose **Continue**. Inkbox saves any new workspace credentials and starts preparing the agent’s app in one step.
4. After **Preparing your Slack app…** finishes, choose **Add to Slack** and approve access in Slack. The Console detects the connection and returns you to conversations.
5. Add the bot to the channels where it should participate.

**Channels → Slack** lists agents once their Slack apps have been created.

Your organization can reuse saved workspace credentials when setting up other
identity apps, or add a new token pair for a different workspace. Credentials are
write-only; only verified workspace metadata is shown afterward. Each identity app
connects to one workspace in this version and stays bound to the workspace selected during setup. This flow does not use client
invitations or require enabling public distribution.

Set the identity’s display name, description, and avatar before connecting. Apps created through Inkbox use that profile and sync later changes automatically, without reconnecting. Removing the avatar restores the Inkbox icon. Profile updates run in the background, so Slack may take a moment to display them. A workspace approval does not create a separate Inkbox identity.

App preparation runs in the background and retries temporary limits automatically.
Reloading resumes the same preparation. If configuration credentials need
attention, update them before retrying.

Installation is workspace-scoped, including individual workspaces in an Enterprise organization. Organization-wide Enterprise installations are not supported.

Workspace installation and channel membership are separate. Installation does not grant access to every conversation or the workspace's entire history. Private channels require an invitation from someone with the necessary permission. Slack workspace policies, app approval, granted permissions, and rate limits still apply.

The Console and [connection list](/docs/api/slack/connections#list-connections) report app creation, preparation status, and installation availability. Setup creates the app directly for an active identity; there is no separate identity setting to enable first.

Live Slack operations require an active identity and a connected workspace. Pausing the identity stops live operations and agent webhook delivery while preserving connections and history. Eligible incoming messages can still be captured, and received deletions can remove saved content. Capture is independent of [webhook event selection](/docs/api/slack/webhooks).

### Start installation from code

Use an organization admin API key or the identity’s claimed agent key, [save both workspace configuration tokens](/docs/api/slack/connections#save-a-provisioning-workspace), then [prepare the app](/docs/api/slack/connections#prepare-the-app) with that saved workspace UUID. Wait for `setup.status` to be `ready`, then request the installation URL below.

Open the returned URL in a browser; the SDK does not open it for you. Treat it as a secret, use it before `expires_at`, and finish approval in the same browser.

<CodeGroup>
  ```python Python theme={null}
  from inkbox import Inkbox

  inkbox = Inkbox(api_key="YOUR_API_KEY")
  installation = inkbox.slack.start_installation(
      "11111111-1111-4111-8111-111111111111"
  )
  # Open installation.authorization_url in a browser. Do not log it.
  ```

  ```typescript TypeScript theme={null}
  import { Inkbox } from "@inkbox/sdk";

  const inkbox = new Inkbox({ apiKey: "YOUR_API_KEY" });
  const installation = await inkbox.slack.startInstallation(
    "11111111-1111-4111-8111-111111111111",
  );
  // Open installation.authorizationUrl in a browser. Do not log it.
  ```

  ```bash CLI theme={null}
  inkbox slack installation start \
    --identity-id 11111111-1111-4111-8111-111111111111
  ```
</CodeGroup>

The default completion page is in the Inkbox Console. To choose an approved Console completion URL, pass `return_url` in Python, `returnUrl` in the TypeScript options, or `--return-url` in the CLI. Its path must be exactly `/console/slack/complete`; see [installation options](/docs/api/slack/connections#start-browser-installation). Omitting this option keeps the default.

## Contacts from Slack

When the agent encounters a human participant, Inkbox can match a confirmed Slack email to an existing organization contact or create a shared, unreviewed contact. Workspace and user IDs keep the account linked. Missing or unconfirmed email stays a Slack-only contact; a profile phone number is not automatically added as an active contact phone number. This does not import every channel member. See [automatic contacts](/docs/api/slack/webhooks#automatic-contacts) for copied fields and visibility.

## Choose a workspace explicitly

Every live read, connection-specific archive read, file operation, and send uses a `connection_id`. [Identity-level retained search](/docs/api/slack/archive#search-across-workspaces) can search all of the identity’s workspaces without selecting one. Get it from the connection list for your identity. Do not treat a Slack conversation ID as sufficient to select a workspace.

<CodeGroup>
  ```python Python theme={null}
  connections = inkbox.slack.list_connections(
      "11111111-1111-4111-8111-111111111111"
  )
  for connection in connections.connections:
      print(connection.id, connection.workspace_name, connection.status)
  ```

  ```typescript TypeScript theme={null}
  const connections = await inkbox.slack.listConnections(
    "11111111-1111-4111-8111-111111111111",
  );
  for (const connection of connections.connections) {
    console.log(connection.id, connection.workspaceName, connection.status);
  }
  ```

  ```bash CLI theme={null}
  inkbox slack connection list \
    --identity-id 11111111-1111-4111-8111-111111111111
  ```

  ```bash cURL theme={null}
  curl "https://inkbox.ai/api/v1/slack/connections?identity_id=11111111-1111-4111-8111-111111111111" \
    -H "X-API-Key: YOUR_API_KEY"
  ```
</CodeGroup>

Every organization member can set up Slack through the Console. Organization members in the Console, organization admin API keys, and claimed agent keys can save and reuse workspace credentials within their organization. Claimed keys can prepare and install apps, and read and use connections, only for their own identity. Disconnecting a workspace still requires the Console or an organization admin API key. Unclaimed keys cannot set up or use Slack.

## Read and reply

Start with [conversation discovery](/docs/api/slack/conversations), then [read messages or thread replies](/docs/api/slack/messages#list-messages). Pagination is explicit. Request another page only when you need it and honor rate-limit responses.

Send a channel message or supply the root message's `thread_ts` to reply in a thread:

<CodeGroup>
  ```python Python theme={null}
  action = inkbox.slack.send_message(
      "22222222-2222-4222-8222-222222222222",
      conversation_id="C0123456789",
      text="I will check the project notes.",
      idempotency_key="project-reply-01",
      thread_ts="1789552800.000100",
  )
  print(action.id, action.status)
  ```

  ```typescript TypeScript theme={null}
  const action = await inkbox.slack.sendMessage(
    "22222222-2222-4222-8222-222222222222",
    {
      conversationId: "C0123456789",
      text: "I will check the project notes.",
      idempotencyKey: "project-reply-01",
      threadTs: "1789552800.000100",
    },
  );
  console.log(action.id, action.status);
  ```

  ```bash CLI theme={null}
  inkbox slack message send \
    --connection-id 22222222-2222-4222-8222-222222222222 \
    --conversation-id C0123456789 \
    --text "I will check the project notes." \
    --idempotency-key project-reply-01 \
    --thread-ts 1789552800.000100
  ```

  ```bash cURL theme={null}
  curl -X POST "https://inkbox.ai/api/v1/slack/connections/22222222-2222-4222-8222-222222222222/messages" \
    -H "X-API-Key: YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -H "Idempotency-Key: project-reply-01" \
    -d '{
      "conversation_id": "C0123456789",
      "text": "I will check the project notes.",
      "thread_ts": "1789552800.000100"
    }'
  ```
</CodeGroup>

Keep Slack timestamps as strings. Reuse the same idempotency key and request body when retrying the same logical send. A successful HTTP response still requires inspecting the action's `status`: `sending`, `sent`, `failed`, or `unknown`.

`sent` means Slack accepted the message. It is not a delivery or read receipt. Poll the [action status](/docs/api/slack/messages#get-action) while it is `sending`. An `unknown` result does not automatically settle later. Reconcile with the live conversation before deciding what to do. Do not blindly send again with a new key.

## Read conversations in the Console

Open **Channels → Slack** to start setup for an agent or open its existing Slack conversations. Each identity connects to one workspace in this version. The Console does not expose disable or remove actions; lifecycle controls remain available through the management API.

Open your identity's **Slack** section to browse **Channels** and **Direct messages**, including group DMs. Each row opens one conversation. Open replies from the message timeline to read a thread. Member profile images and your identity's avatar identify message authors.

Workspace setup lives on the Slack pages. Reauthorize when a connection needs updated permissions. Retention, retained-message search, history imports, and connection lifecycle controls remain available through the [API](/docs/api/slack), SDKs, and CLI.

## Decide when your agent should act

In the Console, use **Webhooks** to manage notification subscriptions across channels. Subscribe an HTTPS endpoint to the events your runtime needs; one identity-owned subscription can combine Slack with other notification types. Choose DMs, group DMs, mentions, channel messages, and thread replies directly in the [event list](/docs/api/slack/webhooks#event-types). These selections cover all accessible conversations across the identity's connected workspaces, without a separate filter configuration.

Inkbox delivers matching events. Your runtime decides when to wake the agent, what to respond to, which threads to keep watching, and what memory to retain. `slack.thread_reply_received` matches any thread reply; it does not remember whether your agent was mentioned earlier in that thread.

Deduplicate events by the webhook envelope's stable `id`. One post can qualify as both a channel message and a mention, but overlapping matches do not create separate logical events.

Interaction and session-stop events are notifications for your runtime to handle. Receiving one does not automatically execute an action or cancel agent work.

## Capture history without waking on everything

All eligible messages received through the connection are captured automatically, independently of webhook event selection. There is no capture switch or conversation allowlist. Use [archive settings](/docs/api/slack/archive#update-retention-settings) to set a retention period and webhook event selection to choose what wakes your agent.

Search across the identity’s retained messages with [identity-level search](/docs/api/slack/archive#search-across-workspaces). Use an explicit [backfill](/docs/api/slack/archive#import-accessible-history) to import accessible conversation or thread history, then inspect coverage. A completed conversation pass is not proof that every thread or every historical message is present.

<CodeGroup>
  ```python Python theme={null}
  matches = inkbox.slack.search_messages(
      "project notes",
      identity_id="11111111-1111-4111-8111-111111111111",
      limit=20,
  )
  for message in matches.messages:
      print(message.connection_id, message.message_ts, message.text)
  ```

  ```typescript TypeScript theme={null}
  const matches = await inkbox.slack.searchMessages({
    q: "project notes",
    identityId: "11111111-1111-4111-8111-111111111111",
    limit: 20,
  });
  for (const message of matches.messages) {
    console.log(message.connectionId, message.messageTs, message.text);
  }
  ```

  ```bash CLI theme={null}
  inkbox slack search \
    --identity-id 11111111-1111-4111-8111-111111111111 \
    --q "project notes" \
    --limit 20
  ```
</CodeGroup>

Search uses plain keywords and ranks matches by text relevance, with newer messages first for ties. It searches retained message text, not attachment contents; semantic search is not supported.

A claimed agent-scoped key can omit the identity; an organization admin key must specify it. Use `connection_id` in Python, `connectionId` in TypeScript, or `--connection-id` in the CLI to narrow a search to one workspace. Keep all filters unchanged when following `next_cursor` in Python or `nextCursor` in TypeScript and CLI output. Continue even when a page is short or empty if a cursor is present.

Retained history still requires current conversation access. Pausing the identity can retain incoming messages without waking the runtime. Disconnect stops capture through that connection and schedules that connection's archive for deletion.

## Files, pins, and richer actions

* Fetch [file metadata and bytes](/docs/api/slack/files) on demand, or upload a file of up to 10 MiB. Uploads require their own idempotency key. File metadata can be retained; file bytes are not archived.
* A pin marks an existing conversation item for easy reference; it is not a file copy. You can [read, add, and remove pins](/docs/api/slack/operations#read-pins).
* [Edit or delete the bot's messages, manage its reactions, and join or leave supported conversations](/docs/api/slack/operations), subject to Slack permissions.
* [Inspect capabilities](/docs/api/slack/users#inspect-capabilities) before choosing an optional operation. Granted scopes do not guarantee every native feature is available.
* Native processing status is an explicit runtime action for eligible Slack agent sessions. It is not a universal typing indicator and does not run or cancel work automatically.
* Slack webhook delivery diagnostics contain event coordinates and status, not recoverable message bodies. Historical Slack webhook replay remains unsupported even when retained history is enabled.

## Slack Connect and access boundaries

Slack Connect conversations are supported when the selected connection can access them. Use that connection's authority, not a message author's home workspace, for follow-up requests. The same shared conversation can be visible through separate installations; do not merge their permissions or archives.

An incoming event uses the installation identified by Slack's event context. Inkbox does not copy it to every connected workspace that might share the conversation.

Installation does not grant entire-workspace access. Private channels need an authorized invitation. External users and files may expose fewer fields, and access can change after an event arrives. A file reference does not prove the file's original workspace.

Slack does not use the identity's email or phone contact allow/block rules. Slack membership, granted permissions, and workspace restrictions control access. Your runtime still decides which events deserve a response.

## Connection lifecycle

When a workspace requires reauthorization, [start installation again](/docs/api/slack/connections#start-browser-installation) for the same identity and workspace. Reauthorization does not grant access to other workspaces or replay missed webhooks. Request a backfill explicitly when you need accessible history.

The [disconnect API](/docs/api/slack/connections#disconnect-a-workspace) removes Inkbox's access through a connection. It also stops capture and schedules that connection’s retained history for deletion. Reconnection does not restore the deleted archive. This does not uninstall the app from Slack. A workspace administrator can remove the Slack app separately. The Console does not expose a disconnect action.

After reconnecting, capture resumes automatically. Import earlier accessible history explicitly if needed.

## Reference

* [Slack API overview](/docs/api/slack)
* [Connections and installation](/docs/api/slack/connections)
* [Retained history and search](/docs/api/slack/archive)
* [Slack operations](/docs/api/slack/operations)
* [Slack events](/docs/api/slack/webhooks)

## Sender profiles and contacts

Message webhooks include available sender names and profile details under the connection's Slack permissions. Email requires the profile email permission; existing connections can grant newly requested permissions by completing authorization again. Missing profile details do not stop message delivery.

Inkbox links encountered people to organization contacts, including their Slack workspace and user identifiers. The contact card shows those linked accounts. This is not a full workspace directory import. Inkbox contact visibility controls the webhook's linked `contact_id` and contact-card accounts; matching an email does not grant additional contact access.
