The new Slack platform is in beta. Your feedback is most welcome.

Custom functions

On the next-generation platform, you can build custom Run On Slack functions, which are reusable building blocks of automation that are deployed to our infrastructure and accept inputs, perform some calculations, and provide outputs. Functions can be used as steps in Workflowsβ€”and Workflows are invoked by Triggers.

To create a Run On Slack function, we need to do three things:

Define a function

Functions are defined via the DefineFunction method, which is part of the SDK that gets included with every newly created project. Both the definition and implementation for your functions should live in the same file, so to keep your app organized, put all your function files in a functions folder in your app's root folder.

Let's take a look at the "Send a greeting" function that comes with the Hello World sample app:

// /slack-samples/deno-hello-world/functions/greeting_function.ts
import { DefineFunction, Schema, SlackFunction } from "deno-slack-sdk/mod.ts";

export const GreetingFunctionDefinition = DefineFunction({
  callback_id: "greeting_function",
  title: "Send a greeting",
  description: "Send greeting to channel",
  source_file: "functions/greeting_function.ts",
  input_parameters: {
    properties: {
      recipient: {
        type: Schema.slack.types.user_id,
        description: "Greeting recipient",
      },
      message: {
        type: Schema.types.string,
        description: "Message to the recipient",
      },
    },
    required: ["message"],
  },
  output_parameters: {
    properties: {
      greeting: {
        type: Schema.types.string,
        description: "Greeting for the recipient",
      },
    },
    required: ["greeting"],
  },
});

Note that we import DefineFunction, which is used for defining our function, and also SlackFunction, which we'll use to implement our function in the next section.

Just like Workflows, Custom functions have a unique callback_id and also require a title. A third required field is source_file, which points to where the function is implemented. Additionally, you can set inputs and outputs just like you can with Workflows.

Here's all the fields you can use when defining a Custom function:

Field Expected value
callback_id A required unique string identifier representing the function ("nothing" in the above example). It must be unique in your application; no other functions may share the same callback ID. Changing a function's callback ID is not recommended as it means that the function will be removed from the app and created under the new callback ID, which will break any workflows referencing the old function.
title A required string to nicely identify the function.
description An optional succinct summary of what your function does.
source_file The relative path from the project root to the function handler file (i.e., the source file). Remember to update this if you start nesting your functions in folders.
input_parameters An object which describes one or more input parameters that will be available to your function. Each top-level property of this object defines the name of one input parameter which will become available to your function.
output_parameters An object which describes one or more output parameters that will be returned by your function. This object follows the exact same pattern as input_parameters: top-level properties of the object define output parameter names, with the property values further describe the type and description of each individual output parameter.

The value for properties in input_parameters and output_parameters needs to be an object with further sub-properties:

  • type: The type of the input parameter. This can be a Built-in type or a Custom type that you define.
  • description: A string description of the parameter.

If you want to set a property as required, list its name in its respective input or output properties required property.

For example, if you have an input parameter named customer_id that you want to be required, you can do so like this:

input_parameters: {
  properties: {
    customer_id: {
      type: Schema.types.string,
      description: "The customer's ID"
    }
  },
  required: ["customer_id"]
}

Functions can (and generally should) declare inputs and outputs.

Inputs are declared in the input_parameters property, and outputs are declared in the output_parameters property. Each can contain either Built-in types or Custom types that you define.

While, strictly speaking, input and output parameters are optional, they are a common and standard way to pass data between functions and nearly any function you write will expect at least one input and pass along an output.

Functions are similar in philosophy to Unix system commands: they should be minimalist, modular, and reusable. Expect the output of one function to eventually become the input of another, with no other frame of reference.

Once your function is defined in your app's manifest file, the next step is to implement the function in its respective source file.

Have 2 minutes to provide some feedback?

We'd love to hear about your experience with the new Slack platform. Please complete our short survey so we can use your feedback to improve.

Implement a function

To keep your project tidy, implement your functions in the same source file you defined them in.

Implementation involves creating a SlackFunction default export:

// /slack-samples/deno-hello-world/functions/greeting_function.ts

}); // end of DefineFunction

export default SlackFunction(
  // Pass along the function definition from earlier in the source file
  GreetingFunctionDefinition,
  ({ inputs }) => { // Provide any context properties, like `inputs`, `env`, or `token`
    
    // Implement your function
    const { recipient, message } = inputs;
    const salutations = ["Hello", "Hi", "Howdy", "Hola", "Salut"];
    const salutation =
      salutations[Math.floor(Math.random() * salutations.length)];
    const greeting =
      `${salutation}, <@${recipient}>! :wave: Someone sent the following greeting: \n\n>${message}`;

    // Don't forget any required output parameters  
    return { outputs: { greeting } };
  },
);

See greeting_function.ts in the "Hello World" sample app for a complete example.

When using a local development server, you can use console.log to emit information to the console. When your app is deployed to production, any console.log commands are available via slack activity. Check out our Logging page for more.

When composing your functions, some things you can do include:

You can also encapsulate your business logic separately from the function handler, then import what you need and build your functions that way.

Function context properties

Your function handler's context supports several properties that you can use by declaring them.

Here are all the context properties available:

Property Kind Description
env String Represents environment variables available to your function's execution context. These are added via the CLI's env add command
inputs Object Contains the input parameters you defined as part of your Function definition.
token String Your application's access token. Useful for calling Slack API methods
event Object Contains the full incoming event details
team_id String The ID of your Slack workspace, i.e. T112345ABCD

The object returned by your function supports the following properties:

Property Kind Description
error String Indicates the error that was encountered. If present, the function will return an error regardless of what is passed to outputs
outputs Object Exactly matches the structure of your function definition's output_parameters. This is required unless an error is returned
completed Boolean Indicates whether or not the function is completed. This defaults to true

Don't forget to add your function to a workflow! When you're finished defining and implementing your functions, the next step is to add them to Workflows. Once added as a step in a Workflow, your Function will run when that Workflow is invoked by a Trigger.

Distribute a function

A newly created Run On Slack Function will only be accessible to it's creator until it is distributed to others.

To distribute a Function so that another user (or many users) can build workflows that reference that function, you'll use the distribute command. At this time, Functions can be distributed to everyone in a workspace, your app's collaborators, or specific users.

In order to enable the distribute command, your app must have been deployed at least once before attempting to distribute your function to others.

Re-deploy your app after using the distribute function
Anytime you make permission changes to your function using the distribute command, your app must be redeployed, each time after, in order for the new access changes to be available in your app's workspace.

Grant access to one person

Given:

  • a function with a callback ID of get_next_song
  • a user with ID U1234567

You can distribute the Function get_next_song to the user U1234567 like this:

$ slack function distribute --name get_next_song --users U1234567 --grant

To revoke access, replace --grant with --revoke.

Grant access to multiple people

Given:

  • a function with a callback ID of calculate_royalties
  • users with the following IDs: U1111111, U2222222, and U3333333

You can distribute the Function calculate_royalties to the above users like this:

$ slack function distribute --name calculate_royalties --users U1111111,U2222222,U3333333 --grant

To revoke access, replace --grant with --revoke.

Grant access to all collaborators

Given:

You can distribute the Function notify_escal_team to all of your app's collaborators like this:

$ slack function distribute --name motify_escal_team --app_collaborators --grant

Grant access to all workspace members

Given:

  • a function with a callback ID of get_customer_profile

You can distribute the Function get_customer_profile to everyone in your workspace like this:

$ slack function distribute --name get_customer_profile --everyone --grant

Grant access using the prompt based approach

The prompt-based approach allows you to distribute your function to one user, to multiple people, to collaborators, or to everyone in an interactive prompt.

To activate the flow, use the following command in your terminal:

$ slack function distribute

Given:

You will answer the first prompt in the following manner:

Choose the name of the function you'd like to distribute
> reverse (Reverse)
Choose who you'd like to to have access to your function

If going from everyone or app_collaborators to specific users, you should be offered the option of adding collaborators to specific users.

> specific users (current)
  app collaborators only
  everyone
Choose an action
> granting a user access
  revoking a user's access
Provide ID(s) of one or more user in your workspace

Given:

  • a user's ID in your workspace: U0123456789

You will answer the following prompt below:

: U0123456789

You can add multiple users at the same time. To do this, separate the user ID's with a comma (eg. U0123456789, UA987654321).

After you've finished this flow, you'll receive a message indicating the type of distribution you chose.

More distribution options

For more distributions options, including how to revoke access, head to the distribute command reference.

Have 2 minutes to provide some feedback?

We'd love to hear about your experience with the new Slack platform. Please complete our short survey so we can use your feedback to improve.