---
layout: page
title: Web API client
permalink: /web_api
redirect_from: /basic_usage
order: 2
headings:
    - title: Posting a message
    - title: Passing optional arguments to a method
    - title: Uploading a file
    - title: Getting a list of channels
    - title: Using a callback instead of a Promise
    - title: Changing the retry configuration
    - title: Changing the request concurrency
    - title: Customizing the logger
    - title: Proxy settings
    - title: OAuth token exchange
---

This package includes a web client that makes it simple to use the
[Slack Web API methods](https://api.slack.com/methods). Here are some of the goodies you get right
out of the box:

* Request queuing and rate-limit management
* Request body serialization and response body parsing
* Keeps track of your token
* Proxy support
* File upload handling
* Error handling
* Logging
* Configurability

Here are some of the common recipies for using the `WebClient` class.

---

### Posting a message

Your app will interact with the Web API through the `WebClient` object, which a top level export
from this package. At a minimum, you need to instantiate it with a token. The example below shows
how to post a message into a channel, DM, MPDM, or group. This will require either the
`chat:user:write` or `chat:bot:write` scopes.

```javascript
const { WebClient } = require('@slack/client');

// An access token (from your Slack app or custom integration - xoxp, xoxb, or xoxa)
const token = process.env.SLACK_TOKEN;

const web = new WebClient(token);

// The first argument can be a channel ID, a DM ID, a MPDM ID, or a group ID
const channelId = 'C1232456';

// See: https://api.slack.com/methods/chat.postMessage
web.chat.postMessage(channelId, 'Hello there')
  .then((res) => {
    // `res` contains information about the posted message
    console.log('Message sent: ', res.ts);
  })
  .catch(console.error);
```

**NOTE**: While most Web API methods have a function signature that puts all required arguments
in order as see on the method's documentation table on <https://api.slack.com/methods>, a few
methods do not follow this convention:
-  `chat.delete`
-  `chat.update`
-  `chat.unfurl`

See the `___Facet` reference documentation or the source code for the correct parameter ordering.

---

### Passing optional arguments to a method

Each method can also take optional arguments in an object after its required arguments.
Let's post a message like above, but with attachments for a more rich UI.

```javascript
web.chat.postMessage(channelId, 'Hello there', {
  attachments: [
    {
      "fallback": "Required plain-text summary of the attachment.",
      "color": "#36a64f",
      "author_name": "Bobby Tables",
      "author_link": "http://flickr.com/bobby/",
      "author_icon": "http://flickr.com/icons/bobby.jpg",
      "title": "Slack API Documentation",
      "title_link": "https://api.slack.com/",
      "text": "Optional text that appears within the attachment",
      "fields": [
        {
          "title": "Priority",
          "value": "High",
          "short": false
        }
      ],
      "image_url": "http://my-website.com/path/to/image.jpg",
      "thumb_url": "http://example.com/path/to/thumb.png",
      "footer": "Slack API",
      "footer_icon": "https://platform.slack-edge.com/img/default_application_icon.png",
      "ts": 123456789
    }
  ]
})
  .then((res) => {
    // `res` contains information about the posted message
    console.log('Message sent: ', res.ts);
  })
  .catch(console.error);
```

**NOTE**: See the [Message Builder](https://api.slack.com/docs/messages/builder) for a playground
where you can prototype your message's look.

---

### Uploading a file

The `files.upload` method can be used to upload a file, cool! This will require `files:write:user`
scope.

```javascript
const fs = require('fs');
const { WebClient } = require('@slack/client');

// An access token (from your Slack app or custom integration - xoxp, xoxb, or xoxa)
const token = process.env.SLACK_TOKEN;

const web = new WebClient(token);

// Slack needs a file name for the upload
// This file is located in the current directory (`process.pwd()`)
var fileName = 'test_file.csv';

// See: https://api.slack.com/methods/chat.postMessage
web.files.upload(fileName, {
  // You can use a ReadableStream or a Buffer for the file option
  file: fs.createReadStream(`./${fileName}`),
  // Or you can use the content property (but not both)
  // content: 'plain string content that will be editable in Slack'
})
  .then((res) => {
    // `res` contains information about the uploaded file
    console.log('File uploaded: ', res.file.id);
  })
  .catch(console.error);
```

---

### Getting a list of channels

The `channels.list` method can be used to get a list of all the public channels (and private
channels from the user who authorized) when using a user token with scope `channels:read`. Or, it
would the public channels are all private channels a bot user is a member of when using a bot token.

```javascript
const { WebClient } = require('@slack/client');

// An access token (from your Slack app or custom integration - xoxp, xoxb, or xoxa)
const token = process.env.SLACK_TOKEN;

const web = new WebClient(token);

// See: https://api.slack.com/methods/channels.list
web.channels.list()
  .then((res) => {
    // `res` contains information about the channels
    res.channels.forEach(c => console.log(c.name));
  })
  .catch(console.error);
});
```

---

### Using a callback instead of a Promise

Every web API method can also be called with a callback function that takes `cb(error, response)`.
If you prefer callbacks over promises, here is the example above translated for callbacks:

```javascript
web.channels.list((err, res) => {
  if (err) {
    return console.error(err);
  }

  // `res` contains information about the channels
  res.channels.forEach(c => console.log(c.name));
});

```

---

### Changing the retry configuration

The `WebClient` will retry any request that fails for a recoverable error. The policy is
configurable, but the default is retrying forever with an exponential backoff, capped at thirty
minutes but with some randomization. You can use the `retryConfig` option to customize that policy.
The value is an `options` object as described in the following library:
<https://github.com/tim-kos/node-retry>.

```javascript
const { WebClient } = require('@slack/client');
const token = process.env.SLACK_TOKEN;
const web = new WebClient(token, {
  retryConfig: {
    // This would turn the retrying feature off
    retries: 0,
  },
});
```

---

### Changing the request concurrency

The `WebClient` maintains a queue of requests to make sure a limited number of requests are in
flight at a time. It also helps with rate limit management. The default concurrency is set to three
but you can configure this with the `maxRequestConcurrency` option.

```javascript
const { WebClient } = require('@slack/client');
const token = process.env.SLACK_TOKEN;
const web = new WebClient(token, {
  retryConfig: {
    // Allow up to 10 requests to be in-flight at a time
    maxRequestConcurrency: 10,
  },
});
```

---

### Customizing the logger

The `WebClient` also logs interesting events as it operates. By default, the log level is set to
`INFO` and it should not log anything as long as nothing goes wrong. You can adjust the log level
using the `logLevel` option and use any of the
[npm log levels](https://github.com/winstonjs/winston/tree/2.4.0#logging-levels).

You can also capture the logs without writing them to stdout by setting the `logger` option. It
should be set to a function that takes `fn(level: string, message: string)`.

```javascript
const fs = require('fs');
const { WebClient } = require('@slack/client');

// open a file to write logs
// TODO: make sure to call `logStream.end()` when the app is shutting down
const logStream = fs.createWriteStream('/tmp/app.log');

const token = process.env.SLACK_TOKEN;
logStream.on('open', () => {
  const web = new WebClient(token, {
    // increased logging, great for debugging
    logLevel: 'debug',
    logger: (level, message) => {
      // write to disk
      logStream.write(`[${level}]: ${message}`);
    }
  });
});
```

---

### Proxy settings

If you need to send all your HTTP requests through a proxy, the `WebClient` class allows for you
to do this with the `transport` option.

```javascript
const { WebClient } = require('@slack/client');
const { proxiedRequestTransport } = require('@slack/client/lib/clients/transports/request');

const web = new WebClient(token, {
  transport: proxiedRequestTransport('your proxy url')
});
```

---

### OAuth token exchange

There's one method that doesn't require a `token`, and that's because it generates the `token` for
you: `oauth.access`. You'll be using this method at the end of the OAuth flow for a distributed
Slack app. To do this, just initialize without a token.

Or, if you are using the Passport authentication framework, this step is handled for you using the
[`@aoberoi/passport-slack` Strategy](https://github.com/aoberoi/passport-slack).

```javascript
const { WebClient } = require('@slack/client');

const client = new WebClient();
const clientId = process.env.SLACK_CLIENT_ID;
const clientSecret = process.env.SLACK_CLIENT_SECRET;

// Not shown: did some OAuth to recieve `code` grant
client.oauth.access(clientId, clientSecret, code)
  .then((res) => {
    // Good idea to save the access token to your database
    console.log(res.access_token);
  })
  .catch(console.error);
```


