# Create Slack Feed

## User Intent

"I want to sync Slack channels into Graphlit for search and AI interactions"

## Operation

* **SDK Method**: `graphlit.createFeed()` with Slack configuration
* **GraphQL**: `createFeed` mutation
* **Entity Type**: Feed
* **Common Use Cases**: Slack channel sync, team communication search, chat history RAG

## TypeScript (Canonical)

```typescript
import { Graphlit } from 'graphlit-client';
import {
  ContentTypes,
  FeedInput,
  FeedListingTypes,
  FeedTypes,
  SearchTypes,
} from 'graphlit-client/dist/generated/graphql-types';

const graphlit = new Graphlit();

// Optional: Query available Slack channels (requires token/OAuth)
const channelsResponse = await graphlit.querySlackChannels({
  token: process.env.SLACK_TOKEN!,
});

console.log('Available channels:', channelsResponse.slackChannels?.results);

// Step 1: Create a Slack feed for ONE channel (one feed per channel)
const feedInput: FeedInput = {
  name: 'Engineering Slack',
  type: FeedTypes.Slack,
  slack: {
    type: FeedListingTypes.Past,
    channel: 'engineering',
    token: process.env.SLACK_TOKEN!,
    readLimit: 100,
    includeAttachments: true,
  },
};

const response = await graphlit.createFeed(feedInput);
const feedId = response.createFeed.id;

console.log(`Slack feed created: ${feedId}`);

// Step 3: Poll for feed completion
while (true) {
  const status = await graphlit.isFeedDone(feedId);
  if (status.isFeedDone.result) {
    break;
  }
  console.log('Still syncing Slack messages...');
  await new Promise((resolve) => setTimeout(resolve, 10_000));
}

console.log('Slack feed sync complete!');
```

## Parameters

### FeedInput (Required)

* **`name`** (string): Display name for the feed
* **`type`** (FeedTypes): Must be `SLACK`
* **`slack`** (SlackFeedPropertiesInput): Slack-specific configuration

### SlackFeedPropertiesInput (Required)

* **`type`** (FeedListingTypes): `Past` (backfill then continue) or `New` (new items only)
* **`channel`** (string): Slack channel name (one channel per feed)
* **`token`** (string): Slack token (Token auth) or use `connector` (Connector auth)
* **`includeAttachments`** (boolean, optional): include file attachments
* **`readLimit`** (int, optional): items per poll/run

### Optional

* **`correlationId`** (string): For tracking in production
* **`collections`** (EntityReferenceInput\[]): Auto-add synced messages to collections
* **`workflow`** (EntityReferenceInput): Apply workflow to messages

## Response

```typescript
{
  createFeed: {
    id: string;              // Feed ID
    name: string;            // Feed name
    state: EntityState;      // ENABLED
    type: FeedTypes.Slack;   // SLACK
    slack: {
      channel: string;
      includeAttachments?: boolean;
      type?: FeedListingTypes;
    }
  }
}
```

## Developer Hints

### OAuth Token Requirements

**Slack OAuth Scopes Needed**:

* `channels:read` - List public channels
* `channels:history` - Read public channel messages
* `groups:read` - List private channels (if needed)
* `groups:history` - Read private channel messages (if needed)
* `users:read` - Get user information

**Getting a Slack Token**:

1. Create Slack App at <https://api.slack.com/apps>
2. Add OAuth scopes under "OAuth & Permissions"
3. Install app to workspace
4. Copy Bot User OAuth Token (starts with `xoxb-`)

### Feed is Continuous Sync

```typescript
// Feed continuously monitors for new messages
const feed = await graphlit.createFeed(feedInput);

// New messages appear automatically as content
// No need to manually trigger sync
```

**Important**: Feeds run continuously. To stop syncing, disable or delete the feed.

### Polling for Initial Sync

```typescript
// After creating feed, wait for initial sync
const feedId = response.createFeed.id;

let isDone = false;
while (!isDone) {
  const status = await graphlit.isFeedDone(feedId);
  isDone = status.isFeedDone.result || false;
  
  if (!isDone) {
    await new Promise(resolve => setTimeout(resolve, 10000));
  }
}

// Now query synced messages
const messages = await graphlit.queryContents({
  feeds: [{ id: feedId }],
  types: [ContentTypes.Message]
});

console.log(`Synced ${messages.contents.results.length} messages`);
```

### Channel Discovery

```typescript
// List all channels user has access to
const channels = await graphlit.querySlackChannels({ token: slackToken });
const channelNames = channels.slackChannels?.results ?? [];

// One feed per channel (recommended if you want multiple channels)
for (const channel of channelNames.filter((c) => c.startsWith('eng-') || c.startsWith('dev-'))) {
  await graphlit.createFeed({
    name: `Slack #${channel}`,
    type: FeedTypes.Slack,
    slack: {
      type: FeedListingTypes.Past,
      channel,
      token: slackToken,
    },
  });
}
```

## Variations

### 1. Sync Specific Channels Only

Create multiple feeds (one per channel):

```typescript
await graphlit.createFeed({
  name: 'Slack #customer-support',
  type: FeedTypes.Slack,
  slack: {
    type: FeedListingTypes.Past,
    channel: 'customer-support',
    token: slackToken,
  },
});
```

### 2. Sync with Auto-Collection

Automatically add messages to a collection:

```typescript
// Create collection first
const collectionResponse = await graphlit.createCollection({
  name: 'Slack Messages'
});

// Create feed with collection
const feedInput: FeedInput = {
  name: 'Team Slack',
  type: FeedTypes.Slack,
  slack: {
    type: FeedListingTypes.Past,
    token: slackToken
  },
  collections: [{ id: collectionResponse.createCollection.id }]
};
```

### 3. Sync with Entity Extraction

Extract people and topics from messages:

```typescript
// Create workflow for entity extraction
const workflowResponse = await graphlit.createWorkflow({
  name: 'Extract Slack Entities',
  extraction: {
    jobs: [{
      connector: {
        type: EntityExtractionServiceTypes.ModelText,
        modelText: {
          extractedTypes: [
            ObservableTypes.Person,
            ObservableTypes.Organization,
            ObservableTypes.Label
          ]
        }
      }
    }]
  }
});

// Create feed with workflow
const feedInput: FeedInput = {
  name: 'Slack with Extraction',
  type: FeedTypes.Slack,
  slack: {
    type: FeedListingTypes.Past,
    token: slackToken
  },
  workflow: { id: workflowResponse.createWorkflow.id }
};
```

### 4. Query Synced Messages

Search through synced Slack messages:

```typescript
// After feed sync completes
const results = await graphlit.queryContents({
  feeds: [{ id: feedId }],
  types: [ContentTypes.Message],
  search: 'deployment issues',
  searchType: SearchTypes.Hybrid
});

results.contents.results.forEach(msg => {
  console.log(`${msg.name}: ${msg.summary}`);
});
```

### 5. Multi-Channel Pattern with Filtering

Sync multiple channels and filter by date:

```typescript
const feedInput: FeedInput = {
  name: 'Recent Engineering Discussions',
  type: FeedTypes.Slack,
  slack: {
    type: FeedListingTypes.Past,
    channel: 'engineering',
    token: slackToken
  }
};

const response = await graphlit.createFeed(feedInput);

// Wait for sync
await waitForFeedCompletion(response.createFeed.id);

// Query only recent messages
const lastWeek = new Date();
lastWeek.setDate(lastWeek.getDate() - 7);

const recentMessages = await graphlit.queryContents({
  feeds: [{ id: response.createFeed.id }],
  creationDateRange: {
    from: lastWeek,
    to: new Date()
  }
});
```

## Common Issues

**Issue**: `Invalid token` error\
**Solution**: Ensure Slack token has required OAuth scopes. Regenerate token with correct scopes.

**Issue**: `Channel not found`\
**Solution**: Use `querySlackChannels()` to confirm the exact channel name. The app/user must have access to the channel.

**Issue**: Feed created but no messages syncing\
**Solution**: Verify token has `channels:history` scope and the app/user has access to the channel.

**Issue**: Feed sync taking too long\
**Solution**: This is normal for channels with many messages. Use `isFeedDone()` to poll. Initial sync can take minutes for large channels.

## Production Example


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.graphlit.dev/api-guides/use-cases/feeds/messaging/feed-create-slack.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
