---
title: "Subscribe"
method: POST
path: "/slack/enrollments"
tags: ["slack-channel-enrollments"]
---

# Subscribe

`POST /slack/enrollments`

## Request

- Base URL: `https://api.traversal.com` (the document declares no server; this is the origin it was published from)
- URL: `https://api.traversal.com/slack/enrollments`
- Auth: none declared

## Request body

- CreateSlackChannelEnrollmentRequest: Subscribe a Slack channel to Alert Stories. The channel is identified by name; the service resolves it to a ``slack_channel_id`` via the organization's ``slack_channels`` cache. Returns 404 if Traversal has never seen a channel by that name, and 409 if an active enrollment already exists (use PATCH to update settings).
  - `slack_channel_name` string, required: Name of an existing Slack channel Traversal has been added to.
  - `mode` 'MANUAL' | 'AUTO' | 'CUSTOM' | 'READ_ONLY', required: How Traversal is wired into a chat channel. Stored as ``slack_channel_enrollments.mode``. A channel with no enrollment row is implicitly ``MANUAL``, except a Slack mention, which uses the org default so it agrees with the row the join handler is about to write. Storing an explicit ``MANUAL`` row lets the channel carry per-channel state (like ``custom_instruction``) without enabling auto-triggers. Removing a channel from Channel Management entirely is a separate act (archiving the enrollment), not a mode. ``READ_ONLY`` is the one mode that suppresses *outbound* behavior rather than selecting a flavor of it: Traversal keeps ingesting and storing every message, and answers every interactive surface with a fixed notice instead of doing work. It is only offered while its organization's gate is on -- see ``engagement_policy``. Existing ``READ_ONLY`` channels keep the mode when that gate is turned back off, so nothing starts talking again behind a customer's back.
  - `custom_instruction` string, nullable: Free-form per-channel instruction. Omit (null) to leave the existing value unchanged; pass a non-empty string to overwrite it.

## Response `200`

Successful Response

- SlackChannelEnrollmentResponse: Active enrollment row exposed over the API.
  - `id` string, required
  - `organization_id` string, required
  - `slack_channel_id` string, required
  - `slack_channel_name` string, required
  - `mode` 'MANUAL' | 'AUTO' | 'CUSTOM' | 'READ_ONLY', required: How Traversal is wired into a chat channel. Stored as ``slack_channel_enrollments.mode``. A channel with no enrollment row is implicitly ``MANUAL``, except a Slack mention, which uses the org default so it agrees with the row the join handler is about to write. Storing an explicit ``MANUAL`` row lets the channel carry per-channel state (like ``custom_instruction``) without enabling auto-triggers. Removing a channel from Channel Management entirely is a separate act (archiving the enrollment), not a mode. ``READ_ONLY`` is the one mode that suppresses *outbound* behavior rather than selecting a flavor of it: Traversal keeps ingesting and storing every message, and answers every interactive surface with a fixed notice instead of doing work. It is only offered while its organization's gate is on -- see ``engagement_policy``. Existing ``READ_ONLY`` channels keep the mode when that gate is turned back off, so nothing starts talking again behind a customer's back.
  - `custom_instruction` string, nullable, required
  - `created_at` string, date-time, required
  - `updated_at` string, date-time, required
  - `custom_instruction_last_edited_at` string, date-time, nullable
  - `custom_instruction_last_edited_by` string, nullable

## Other responses

- `422`: Validation Error

---

[API](https://skmtc.dev/traversal/apis/traversal-api.md) - [All operations](https://skmtc.dev/traversal/apis/traversal-api/llms.txt) - [OpenAPI document](https://skmtc.dev/traversal/apis/traversal-api/revisions/31e1a8b7cf89?raw)
