# Pins

Pin and unpin messages in channels, and retrieve lists of pinned items. Pinned messages are highlighted items that stay easily accessible at the top of a channel for important information or reference.

## Capabilities

### Add Pin

Pin a message to a channel to highlight it as important.

```typescript { .api }
/**
 * Pin an item to a channel
 * @param options - Message parameters to pin
 * @returns Promise resolving to success confirmation
 */
pins.add(options: PinsAddArguments): Promise<PinsAddResponse>;

interface PinsAddArguments extends MessageArgument, TokenOverridable {}

interface MessageArgument {
  /** Channel containing the message */
  channel: string;
  /** Timestamp of the message to pin */
  timestamp: string;
}

interface PinsAddResponse extends WebAPICallResult {
  /** Whether the pin was successfully added */
  ok: boolean;
}
```

**Usage Examples:**

```typescript
import { WebClient } from "@slack/web-api";

const web = new WebClient(process.env.SLACK_BOT_TOKEN);

// Pin a message to a channel
await web.pins.add({
  channel: "C1234567890",
  timestamp: "1234567890.123456"
});
```

### List Pins

Retrieve all pinned items in a specific channel.

```typescript { .api }
/**
 * List items pinned to a channel
 * @param options - Channel parameters
 * @returns Promise resolving to list of pinned items
 */
pins.list(options: PinsListArguments): Promise<PinsListResponse>;

interface PinsListArguments extends TokenOverridable {
  /** Channel to get pinned items for */
  channel: string;
}

interface PinsListResponse extends WebAPICallResult {
  /** Array of pinned items */
  items?: PinnedItem[];
  /** Total count of pinned items */
  count?: number;
}

interface PinnedItem {
  /** Type of pinned item ('message', 'file', etc.) */
  type?: string;
  /** Channel ID where item is pinned */
  channel?: string;
  /** User who pinned the item */
  created_by?: string;
  /** Timestamp when item was pinned */
  created?: number;
  /** Message object (if type is 'message') */
  message?: Message;
  /** File object (if type is 'file') */
  file?: File;
  /** File comment object (if type is 'file_comment') */
  comment?: FileComment;
}
```

**Usage Examples:**

```typescript
// Get all pinned items in a channel
const pinnedItems = await web.pins.list({
  channel: "C1234567890"
});

console.log(`Found ${pinnedItems.count} pinned items`);

// Process different types of pinned items
pinnedItems.items?.forEach(item => {
  switch (item.type) {
    case 'message':
      console.log(`Pinned message: ${item.message?.text}`);
      break;
    case 'file':
      console.log(`Pinned file: ${item.file?.name}`);
      break;
    case 'file_comment':
      console.log(`Pinned file comment: ${item.comment?.comment}`);
      break;
  }
});
```

### Remove Pin

Remove a pin from a message in a channel.

```typescript { .api }
/**
 * Remove a pin from an item in a channel
 * @param options - Message parameters to unpin
 * @returns Promise resolving to success confirmation
 */
pins.remove(options: PinsRemoveArguments): Promise<PinsRemoveResponse>;

interface PinsRemoveArguments extends MessageArgument, TokenOverridable {}

interface PinsRemoveResponse extends WebAPICallResult {
  /** Whether the pin was successfully removed */
  ok: boolean;
}
```

**Usage Examples:**

```typescript
// Remove a pin from a message
await web.pins.remove({
  channel: "C1234567890",
  timestamp: "1234567890.123456"
});

// Remove all pins from a channel (requires iteration)
const pinnedItems = await web.pins.list({
  channel: "C1234567890"
});

for (const item of pinnedItems.items || []) {
  if (item.type === 'message' && item.message?.ts) {
    await web.pins.remove({
      channel: "C1234567890",
      timestamp: item.message.ts
    });
  }
}
```

## Pin Management Patterns

### Conditional Pinning

Check if a message is already pinned before adding:

```typescript
const checkAndPin = async (channel: string, timestamp: string) => {
  const pinnedItems = await web.pins.list({ channel });
  
  const isAlreadyPinned = pinnedItems.items?.some(
    item => item.type === 'message' && item.message?.ts === timestamp
  );
  
  if (!isAlreadyPinned) {
    await web.pins.add({ channel, timestamp });
    console.log('Message pinned successfully');
  } else {
    console.log('Message is already pinned');
  }
};
```

### Pin Rotation

Maintain a maximum number of pins by removing oldest when adding new:

```typescript
const pinWithRotation = async (channel: string, timestamp: string, maxPins = 5) => {
  const pinnedItems = await web.pins.list({ channel });
  
  // If at max capacity, remove oldest pin
  if (pinnedItems.items && pinnedItems.items.length >= maxPins) {
    const oldestPin = pinnedItems.items
      .filter(item => item.type === 'message')
      .sort((a, b) => (a.created || 0) - (b.created || 0))[0];
    
    if (oldestPin?.message?.ts) {
      await web.pins.remove({
        channel,
        timestamp: oldestPin.message.ts
      });
    }
  }
  
  // Add new pin
  await web.pins.add({ channel, timestamp });
};
```

## Core Types

```typescript { .api }
interface TokenOverridable {
  /** Override the default token for this request */
  token?: string;
}

interface Message {
  /** Message text content */
  text?: string;
  /** Message timestamp */
  ts?: string;
  /** User who sent the message */
  user?: string;
  /** Message type */
  type?: string;
  /** Message subtype */
  subtype?: string;
  /** Message attachments */
  attachments?: MessageAttachment[];
  /** Message blocks */
  blocks?: Block[];
  /** Thread timestamp if message is in a thread */
  thread_ts?: string;
}

interface File {
  /** File ID */
  id?: string;
  /** File name */
  name?: string;
  /** File title */
  title?: string;
  /** File size in bytes */
  size?: number;
  /** File MIME type */
  mimetype?: string;
  /** File URL */
  url_private?: string;
  /** User who uploaded the file */
  user?: string;
}

interface FileComment {
  /** Comment ID */
  id?: string;
  /** Comment text */
  comment?: string;
  /** User who created the comment */
  user?: string;
  /** Comment timestamp */
  timestamp?: number;
}
```