Posting messages using curl


If you just want to be able to post messages to public channels using a token that's only allowed to do that one thing, this tutorial is for you!

To get started, you'll need to create a Slack app. It's not a big deal, it's just a container for your credentials and where to put all the vital information about what your app is or does. You can't get a token without one.

We set up an app manifest with just the permissions you'll need to post messages to any public channel—without even having your app be a member. In this first step, you'll create an app following the prompts after the button below. When you're all done creating and installing your app, follow the banner back to this tutorial.

Features you’ll use

Scopes you'll request

Tokens created by this manifest sure are potent! If you've been using Slack for a long time, this is more or less the equivalent of a classic legacy tester token, but operating as a bot instead of a user.

Create a pre-configured app

Quickly create an app with the correct configuration of scopes and features for this tutorial by clicking below.

Step 1Basic activities using your token with curl

Now that you have your token, let's start using it.

  • Make sure your token works with curl

    Now that you've created your app and have your token, we'll use it in the next steps with the command line tool curl.

    If you're in a MacOS or modern UNIX environment, it's likely you already have curl available when you open up a terminal.

    If you don't have curl or aren't already familiar with it, visit the venerable tool online at

    Do you see your token below? If it's not a placeholder, that means you've arrived at this track after creating your app using the button above. Thank you!


    Anywhere you see xoxb-not-a-real-token-this-will-not-work in this tutorial, that's where your real bot token should be.

    First, let's make sure our token works. It's wise to do a sanity check when you first use a token in a new environment. Since you'll be copying and pasting your token around, it's possible for you to even lose it!

    We're going to use our token to call the auth.test Web API method. In the Slack Web API, the RPC (not REST) methods are served from over HTTPS and all methods are part of the /api/ path.

    Here's a verbose but best practice way to issue your first curl request.

    curl -H "Authorization: Bearer xoxb-not-a-real-token-this-will-not-work"

    That looks so formal though! When you pass a token the preferred way, you must pass it as an Authorization HTTP header with a special keyword that tells us exactly what kind of authorization you're presenting.

    If you prefer to keep things tidier, you can do this too:

    curl -d "token=xoxb-not-a-real-token-this-will-not-work"

    If the request works, you'll see curl print a JSON response in the command line indicating at the very least that "ok" is true. It'll also return some other info that's useful to identify just who or what the token you're using belongs to.

    If you want to see even more about the request, try adding the --verbose flag to the end of your curl request. It'll print out all the HTTP headers and you'll really see how the whole request sequence plays out.

    If your token works—great! Let's proceed. And if it doesn't—make sure you've created an app, installed it, and copied your app's bot token before trying again.

  • We must say hello to the world

    With a working token, let's throw all caution to the wind and post a message to declare a bold "hello!" to the world. As is our custom.

    You're going to need a public channel ID. Or your own user ID. The token we're using doesn't have permissions to list channels or users, so you're going to need to find one another way. This other tutorial introduces more privledged tokens that can retrieve data like this.

    From here on out, I assume you have a public channel or user ID. For our example, we'll use C123456 a public channel I like to call #test.

    To start our message, we'll want to use some text. It'll become the text parameter of our request to chat.postMessage, the primary way to send messages into Slack.

    We all say hello our own little way, today I'll use: "Hi I am a bot that can post messages to any public channel."

    Preparing my request, I'll set that hello as my text argument and C123456 as my channel argument.

    curl -d "text=Hi I am a bot that can post messages to any public channel." -d "channel=C123456" -H "Authorization: Bearer xoxb-not-a-real-token-this-will-not-work" -X POST

    Executing this with your own token and channel ID, you should see a "ok": true like before in the response (and more!) and also, your app's message posted to the target channel.

    We did something a little different here. We used -d to pass each argument separately. Curl will helpfully URL-encode strings you pass it, so we didn't have to manually modify each of our space characters to + or %20 like curl ultimately will do for you. We added -X POST to instruct curl to use the HTTP method POST. It might even have done it anyway, but with a write method I like to be explicit.

    Making your messages more fantastic

    Block kit is the way to build UIs and vibrant messages on the Slack platform. If you want to go beyond a "hello world" you'll want to learn Block Kit next. With these app permissions, you can even extend your app to being fully interactive with Block Kit interactivity.

    Block Kit Builder is a design tool that'll show you the possibilities and the JSON code to go with them.

    When you have blocks you want to include with your message, it's best to change up how you send your arguments to curl to send application/json instead, meaning the whole packet of info you send over to Slack will be in JSON.

    First we'll make our hello world a little fancier and plan out its JSON.

    	"blocks": [
    			"type": "section",
    			"text": {
    				"type": "mrkdwn",
    				"text": "Hi I am a bot that can post *_fancy_* messages to any public channel."

    Then we'll attach the other argument we need to send a message to the API—channel. Since we'll send blocks we won't need to send text this time.

    	"channel": "C123456",
    	"blocks": [
    			"type": "section",
    			"text": {
    				"type": "mrkdwn",
    				"text": "Hi I am a bot that can post *_fancy_* messages to any public channel."

    And now we'll package it up into a curl request. Here's one way to do that. We're going to remove newlines from our JSON and just stuff it into a single-quoted string. If your blocks themselves had single-quoted strings, this wouldn't work out so well. Since this is a lot of stuff, we're breaking lines up by trailing each component with a \ character.

    curl -H "Content-type: application/json" \
    --data '{"channel":"C123456","blocks":[{"type":"section","text":{"type":"mrkdwn","text":"Hi I am a bot that can post *_fancy_* messages to any public channel."}}]}' \
    -H "Authorization: Bearer xoxb-not-a-real-token-this-will-not-work" \
    -X POST

    If you can't get this one to work, try loading the blocks into Block Kit Builder and making sure everything transcribed right.

    With a token with limited permissions like this—the ability to post to any public channel—you can go far. Sending notifications into Slack from the command line, scripts, or even complex applications or integrations is one of the primary use cases for our platform. I hope you can take what you've learned here today and apply it to your own workspace projects.

Step complete!