# Core API Methods

Essential WebClient methods for making API calls, handling pagination, and uploading files.

## Capabilities

### Generic API Call

Make calls to any Slack Web API method with automatic error handling and retry logic.

```typescript { .api }
/**
 * Make a generic API call to any Slack Web API method
 * @param method - The API method name (e.g., 'chat.postMessage')
 * @param options - Parameters for the API call
 * @returns Promise resolving to the API response
 */
apiCall(method: string, options?: Record<string, unknown>): Promise<WebAPICallResult>;
```

**Usage Examples:**

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

const web = new WebClient(token);

// Direct API call
const result = await web.apiCall('chat.postMessage', {
  channel: '#general',
  text: 'Hello world!'
});

// Call with complex parameters
const result = await web.apiCall('conversations.create', {
  name: 'new-channel',
  is_private: false
});

// Override token per call
const result = await web.apiCall('auth.test', {
  token: 'xoxp-different-token'
});
```

### Pagination Support

Automatically handle cursor-based pagination for methods that return large datasets.

```typescript { .api }
/**
 * Paginate through all results of an API method
 * @param method - The API method name that supports pagination
 * @param options - Parameters for the API call
 * @returns AsyncIterable for iterating through all pages
 */
paginate(
  method: string, 
  options?: Record<string, unknown>
): AsyncIterable<WebAPICallResult>;
```

**Usage Examples:**

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

const web = new WebClient(token);

// Iterate through all conversation members
const members = [];
for await (const page of web.paginate('conversations.members', {
  channel: 'C1234567890',
  limit: 100
})) {
  members.push(...page.members);
}

// Get all channels
const channels = [];
for await (const page of web.paginate('conversations.list', {
  types: 'public_channel,private_channel'
})) {
  channels.push(...page.channels);
}

// Use with custom accumulator function
async function getAllUsers() {
  const users = [];
  for await (const page of web.paginate('users.list')) {
    users.push(...page.members);
    
    // Optional: break early based on condition
    if (users.length > 1000) break;
  }
  return users;
}
```

### Advanced Pagination with Custom Logic

Use pagination with custom page reduction and stopping criteria.

```typescript { .api }
/**
 * Custom page reducer function for accumulating results
 * @param accumulator - Current accumulated value
 * @param page - Current page result
 * @returns Updated accumulator value
 */
type PageReducer<A = any> = (
  accumulator: A | undefined, 
  page: WebAPICallResult
) => A;

/**
 * Predicate function to determine when to stop pagination
 * @param page - Current page result
 * @returns True to continue, false to stop
 */
type PaginatePredicate = (page: WebAPICallResult) => boolean;
```

**Usage Examples:**

```typescript
// Custom accumulator pattern
const userCount = await web.paginate('users.list')
  .reduce((count = 0, page) => count + page.members.length, 0);

// Stop pagination based on condition
for await (const page of web.paginate('conversations.history', {
  channel: 'C1234567890'
})) {
  const oldestMessage = page.messages[page.messages.length - 1];
  
  // Stop if we've reached messages older than 30 days
  if (Date.now() - (oldestMessage.ts * 1000) > 30 * 24 * 60 * 60 * 1000) {
    break;
  }
  
  // Process messages...
}
```

### File Upload V2

Modern file upload implementation using Slack's external upload flow.

```typescript { .api }
/**
 * Upload files using the v2 external upload method
 * @param options - File upload configuration
 * @returns Promise resolving to upload results
 */
filesUploadV2(options: FilesUploadV2Arguments): Promise<WebAPICallResult & {
  files: FilesCompleteUploadExternalResponse[];
}>;

interface FilesUploadV2Arguments {
  /** Channels or conversations where the file will be shared */
  channel_id?: string;
  /** Alternative to channel_id - channel names */
  channels?: string;
  /** Title of the file */
  title?: string;
  /** File content as Buffer, Stream, or string */
  file?: Buffer | NodeJS.ReadableStream | string;
  /** Filename if file content is provided */
  filename?: string;
  /** File type/extension */
  filetype?: string;
  /** Alternative file content (deprecated) */
  content?: string;
  /** Initial comment about the file */
  initial_comment?: string;
  /** Thread timestamp to upload file to a thread */
  thread_ts?: string;
  /** Alt text for screen readers */
  alt_text?: string;
  /** Snippet type for text files */
  snippet_type?: string;
}
```

**Usage Examples:**

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

const web = new WebClient(token);

// Upload file from filesystem
const result = await web.filesUploadV2({
  channels: '#general',
  file: createReadStream('./report.pdf'),
  filename: 'monthly-report.pdf',
  title: 'Monthly Report',
  initial_comment: 'Here is this month\'s report'
});

// Upload text content as file
await web.filesUploadV2({
  channels: 'D1234567890', // DM channel
  content: 'console.log("Hello, world!");',
  filename: 'hello.js',
  filetype: 'javascript',
  title: 'Hello World Script'
});

// Upload to specific thread
await web.filesUploadV2({
  channel_id: 'C1234567890',
  file: Buffer.from('Log data here...'),
  filename: 'debug.log',
  thread_ts: '1234567890.123456',
  alt_text: 'Debug log file'
});
```

### Response Handling

All API methods return a standardized response format with consistent error handling.

```typescript { .api }
interface WebAPICallResult {
  /** Indicates if the API call was successful */
  ok: boolean;
  /** Error message if the call failed */
  error?: string;
  /** Additional response metadata */
  response_metadata?: {
    /** Warning messages from Slack */
    warnings?: string[];
    /** Cursor for pagination */
    next_cursor?: string;  
    /** OAuth scopes associated with the token */
    scopes?: string[];
    /** Messages array for bulk operations */
    messages?: string[];
  };
  /** Method-specific response data */
  [key: string]: any;
}
```

**Usage Examples:**

```typescript
const result = await web.chat.postMessage({
  channel: '#general',
  text: 'Hello!'
});

if (result.ok) {
  console.log('Message posted:', result.ts); // Message timestamp
  console.log('Channel:', result.channel); // Channel ID
  
  // Check for warnings
  if (result.response_metadata?.warnings) {
    console.warn('Warnings:', result.response_metadata.warnings);
  }
} else {
  console.error('Error:', result.error);
}

// Handle pagination cursors
const listResult = await web.conversations.list({ limit: 100 });
if (listResult.response_metadata?.next_cursor) {
  // More results available
  const nextPage = await web.conversations.list({
    limit: 100,
    cursor: listResult.response_metadata.next_cursor
  });
}
```

## Types

```typescript { .api }
interface FilesCompleteUploadExternalResponse {
  id: string;
  title: string;
  name: string;
  mimetype: string;
  filetype: string;
  pretty_type: string;
  user: string;
  created: number;
  size: number;
  permalink: string;
  permalink_public?: string;
}
```