This automations page is moving! We've been working hard at building out our tools documentation at tools.slack.dev — the new home of our Deno Slack SDK and Slack CLI docs! You can start using the new docs today, but we'll keep the content on both sites up to date during the transition.

Slack types

Developing automations requires a paid plan. Don't have one? Join the Developer Program and provision a sandbox with access to all Slack features for free.

When building workflow apps, you can use a handful of Slack types (or even define your own). Slack types are used in two ways: as input and output parameters of functions, and as attributes of datastores.

Common properties

Each Slack type contains the same base set of properties. Each type may also contain additional properties, outlined within each type's definition below. Here are the properties that are common to all:

Property Type Description
default The type that is being described. For example, the default for a boolean would be true or false. An optional parameter default value.
description string An optional parameter description.
examples An array of the type being described. An optional list of examples.
hint string An optional parameter hint.
title string An optional parameter title.
type string String that defines the parameter type.

The examples of declaring a type are shown below in both TypeScript, as they would appear in an app built using the Deno SDK, and in JSON, as they would be defined in a manifest. All manifests can be written in JSON; however, declaring types in an app using the Deno SDK is done differently, requiring a reference to the Schema.slack package for non-primitive types.

Choices

Many of the Slack types allow you to make use of the choices property, which is an array of EnumChoice objects. Here is a closer look at the properties of the EnumChoice object:

Property Type Description
value the type that the EnumChoice object corresponds to — in the example below, it is string The value of the corresponding choice, which must map to the values present in the sibling enum property.
title string The label to display for this EnumChoice.
description string An optional description for this EnumChoice.

In the following example for the string Slack type, defining the choices property allows us to have the label on the input form be capitalized, but the data we're going to save be lowercase.

import { DefineWorkflow, Schema } from "deno-slack-sdk/mod.ts";

// ...

const inputForm = LogFruitWorkflow.addStep(
  Schema.slack.functions.OpenForm,
  {
    title: "Tell us your favorite fruit",
    interactivity: LogFruitWorkflow.inputs.interactivity,
    submit_label: "Submit",
    fields: {
      elements: [{
          name: "Fruit",
          title: "The three best fruits",
          type: Schema.types.string,
          enum: ['mango', 'strawberry', 'plum'],
          choices: [
            {value: 'mango', title: 'Mango!', description: 'Wonderfully tropical'},
            {value: 'strawberry', title: 'Strawberry!', description: 'Absolutely fantastic'},
            {value: 'plum', title: 'Plum!', description: 'Tart, just the way I like em'},
          ]
      }]
      required: ["Fruit"],
    },
  },
);

// ...

Slack types for datastores

When defining a datastore, you can use certain Slack types for its attributes. Attributes accept only a single type property in the definition, instead of all the common properties listed above. The following is a list of the Slack types supported for use with datastores:

Here's a sample datastore definition using Slack types for attributes:

import { DefineDatastore, Schema } from "deno-slack-sdk/mod.ts";

export const MyDatastore = DefineDatastore({
  name: "my_datastore",
  primary_key: "id",
  attributes: {
    id: { type: Schema.types.string },
    channel: { type: Schema.slack.types.channel_id },
    message: { type: Schema.types.string },
    author: { type: Schema.slack.types.user_id },
    isMember: { type: Schema.types.boolean },
  },
});

All Slack types

Name Type Description
array Array An array of items (based on a type that you specify.)
blocks Array of Slack Blocks An array of objects that contain layout and style information about your message.
boolean Boolean A logical value, must be either true or false.
canvas_id String A Slack canvas ID, such as F123456AB.
canvas_template_id String A Slack canvas template ID, such as T5678ABC.
channel_id String A Slack channel ID, such as C123ABC456 or D123ABC456.
date String A string containing a date, format is displayed as YYYY-MM-DD.
expanded_rich_text Object A way to nicely format messages in your app. This type cannot convert other message types, e.g. blocks or strings, and is explicitly for use with canvases.
file_id Object A file ID, such as F123ABC456.
integer Integer A whole number, such as -1, 0, or 31415926535.
interactivity Object An object that contains context about the interactive event that led to opening of the form.
message_context Object An individual instance of a message.
message_ts String A Slack-specific hash/timestamp necessary for referencing events like messages in Slack.
number Number A number that allows decimal points such as 13557523.0005.
oauth2 Object The OAuth2 context created after authenticating with external auth.
object Object A custom Javascript object, like {"site": "slack.com"}.
options Object Used to specify dynamic options for a custom step within Workflow Builder. Must be defined as one of the following types: options_field for rendering the options as a set of fields, or options_select to render the options as a drop-down menu. Refer to custom steps dynamic options in Workflow Builder for more details.
rich_text Object A way to nicely format messages in your app. This type cannot convert other message types e.g. blocks, strings.
string String UTF-8 encoded string, up to 4000 bytes.
team_id String A Slack team ID, such as T1234567890.
timestamp Integer A Unix timestamp in seconds. Not compatible with Slack message timestamps - use string instead.
user_context Object Represents a user who interacted with a workflow at runtime.
user_id String A Slack user ID, such as U123ABC456 or W123ABC456.
usergroup_id String A Slack usergroup ID, such as S123ABC456.

Array

Type: array

In addition to the properties noted above, the array type also has these optional properties available:

Property Type Description
items object The type of items in the array. Can be one of the following types: channel_id, user_id, usergroup_id, timestamp, string, integer, number, boolean, canvas_id, canvas_template_id, channel_canvas_id, team_id, file_id.
minItems integer Minimum number of items allowed.
maxItems integer Maximum number of items allowed.

Declare an array of types:

// ...
{
  name: "departments",
  title: "Your department",
  type: Schema.types.array,
  items: {
    type: Schema.types.string,
    enum: ["marketing", "design", "sales", "engineering"],
  },
  default: ["sales", "engineering"],
}
// ...
// ...
"departments": {
  "title": "Your department",
  "type": "array",
  "items": {
    "type": "string",
    "enum": [
      "marketing", "design", "sales", "engineering"
    ]
  }
}
// ...
Arrays and object types

Be sure to define the array's properties in the items object. Untyped objects are not currently supported. In addition, you can only use an object as the item type of array if it's a custom object. Otherwise, you may recieve the following error:
Unexpected schema encountered for array type: failed to match exactly one allowed schema for items - {"type":"one_of"} (failed_constraint).

Array example

In this example function, we have an array of the custom type ChannelType as both an input_parameter and output_parameter. See this custom type and array in action in the Deno Archive Channel sample app.

const ChannelType = DefineType(...)

export const FilterStaleChannelsDefinition = DefineFunction({
  callback_id: "filter_stale_channels",
  title: "Filter Stale Channels",
  description:
    "Filter out any channels that have received messages within the last 6 months",
  source_file: "functions/filter_stale_channels.ts",
  input_parameters: {
    properties: {
      channels: {
        type: Schema.types.array,
        description: "The list of Channel IDs to filter",
        items: {
          type: ChannelType,
        },
      },
    },
    required: ["channels"],
  },
  output_parameters: {
    properties: {
      filtered_channels: {
        type: Schema.types.array,
        description: "The list of stale Channel IDs",
        items: {
          type: ChannelType,
        },
      },
    },
    required: [],
  },
});

Blocks

Type: slack#/types/blocks

Declare an array of Block Kit JSON objects.

// ...
properties: {
  forecast: {
    type: Schema.slack.types.blocks,
  },
},
// ...
// ... 
"input_parameters": {
  "forecast": {
  "type": "slack#/types/blocks"
  }
}
// ... 

If you use Block Kit builder to build your Block Kit objects, be sure to only grab the blocks array. For example:

[
  {
    "type": "section",
    "text": {
      "type": "plain_text",
      "text": "This is a plain text section block.",
      "emoji": true
    }
  },
  {
    "type": "image",
    "image_url": "example.com/png"
    "alt_text": "inspiration"
  }
]
Blocks example

In this example function, we get the current weather forecast.

import { DefineFunction, Schema } from "deno-slack-sdk/mod.ts";

export const ForecastFunctionDefinition = DefineFunction({
  callback_id: "get_forecast",
  title: "Weather forecast",
  description: "A function to get the weather forecast",
  source_file: "functions/weather_forecast.ts",
  input_parameters: {
    properties: {
      city: {
        type: Schema.types.string,
        description: "City",
      },
      country: {
        type: Schema.types.string,
        description: "Country",
      },
      state: {
        type: Schema.types.string,
        description: "State",
      },
    },
    required: ["city"],
  },
  output_parameters: {
    properties: {
      forecast: {
        type: Schema.slack.types.blocks,
        description: "Weather forecast",
      },
    },
    required: ["forecast"],
  },
});

Boolean

Type: boolean

Declare a boolean type:

// ...
isMember: {
  type: Schema.types.boolean,
}
// ...
// ...
"isMember": {
  "type": "boolean"
}
// ...
Boolean example

In this example datastore definition, we use a boolean type to capture whether the message author holds membership in our club.

import { DefineDatastore, Schema } from "deno-slack-sdk/mod.ts";

export const MyDatastore = DefineDatastore({
  name: "my_datastore",
  primary_key: "id",
  attributes: {
    id: { type: Schema.types.string },
    channel: { type: Schema.slack.types.channel_id },
    message: { type: Schema.types.string },
    author: { type: Schema.slack.types.user_id },
    isMember: { type: Schema.types.boolean },
  },
});

Channel ID

Type: slack#/types/channel_id

The channel_id type also has the following optional property:

Property Type Description
choices EnumChoice[] Defines labels that correspond to the enum values. For more details, refer to choices.

Declare a channel_id type:

// ...
  input_parameters: {
    properties: {
      interactivity: {
        type: Schema.slack.types.interactivity,
      },
      channel: {
        type: Schema.slack.types.channel_id,
      },
    },
  },
// ...
// ...
"input_parameters": {
  "channel": {
    "type": "slack#/types/channel_id"
  }
}
// ...

Canvas ID

Type: slack#/types/canvas_id

The canvas_id type also has the following optional property:

Property Type Description
choices EnumChoice[] Defines labels that correspond to the enum values. For more details, refer to choices.
render_condition Object The render_condition property contains three properties of its own: the operator property is a string logical operator which acts on the conditions; the is_required property is a boolean indicating if the property is required, and the conditions property is an array of object conditions which specify if the field should be rendered.

Declare a canvas_id type:

// ...
{
  name: "project_canvas",
  title: "Project Canvas",
  type: Schema.slack.types.canvas_id
}
// ...
// ...
"project_canvas": {
  "title": "Project Canvas",
  "type": "slack#/types/canvas_id"
}
// ...
Canvas ID example

In this example workflow, we get a canvas ID and information to update it.

import { Schema } from "deno-slack-sdk/mod.ts";
import { CanvasWorkflow } from "../workflows/canvas.ts";

const inputForm = CanvasWorkflow.addStep(
  Schema.slack.functions.OpenForm, 
  {
    title: "Provide info to update a canvas",
    interactivity: CanvasWorkflow.inputs.interactivity,
    submit_label: "Submit",
    fields: {
      elements: [
        {
          name: "canvas",
          title: "Canvas to update",
          type: Schema.slack.types.canvas_id
        },
        {
          name: "content",
          title: "Content",
          type: Schema.slack.types.expanded_rich_text,
        }
      ],
      required: ["canvas", "content"],
    },
  },
);

Canvas Template ID

Type: slack#/types/canvas_template_id

The canvas_template_id type also has the following optional property:

Property Type Description
choices EnumChoice[] Defines labels that correspond to the enum values. For more details, refer to choices.

Declare a canvas_template_id type:

// ...
{
  name: "onboarding_template",
  title: "Onboarding Canvas Template",
  type: Schema.slack.types.canvas_template_id
}
// ...
// ...
"onboarding_template": {
  "title": "Onboarding Canvas Template",
  "type": "slack#/types/canvas_template_id"
}
// ...
Canvas Template ID example

In this example workflow, we receive a canvas_template_id for creating a new canvas.

import { Schema } from "deno-slack-sdk/mod.ts";
import { CanvasWorkflow } from "../workflows/canvas.ts";

const inputForm = CanvasWorkflow.addStep(
  Schema.slack.functions.OpenForm, 
  {
    title: "Provide a template your canvas from",
    interactivity: CanvasWorkflow.inputs.interactivity,
    submit_label: "Submit",
    fields: {
      elements: [
        {
          name: "template",
          title: "Canvas template",
          type: Schema.slack.types.canvas_template_id
        },
        {
          name: "title",
          title: "Canvas title",
          type: Schema.types.string,
        },
        {
          name: "owner_id",
          title: "Owner ID",
          type: Schema.slack.types.user_id
        }
      ],
      required: ["template", "title", "owner_id"],
    },
  },
);

Date

Type: slack#/types/date

The date type also has the following optional property:

Property Type Description
choices EnumChoice[] Defines labels that correspond to the enum values. For more details, refer to choices.

Declare a date type:

// ...
fields: {
  elements: [
    {
      name: "date",
      title: "Date Posted",
      type: Schema.slack.types.date,
    },
  ],
},
// ...
// ...
"fields": {
  "elements": [
    {
      "date_posted": {
      "type": "slack#/types/date"
      }
    }
  ]
}
// ...
Date example

In this example workflow, a form requires a date as input, which is printed along with the message after the form is submitted.

import { DefineWorkflow, Schema } from "deno-slack-sdk/mod.ts";

const TestReverseWorkflow = DefineWorkflow({
  callback_id: "test_reverse",
  title: "Test reverse",
  input_parameters: {
    properties: {
      channel: { type: Schema.slack.types.channel_id },
      interactivity: { type: Schema.slack.types.interactivity },
    },
    required: ["interactivity"],
  },
});

const formData = TestReverseWorkflow.addStep(Schema.slack.functions.OpenForm, {
  title: "Reverse string form",
  submit_label: "Submit form",
  description: "Submit a string to reverse",
  interactivity: TestReverseWorkflow.inputs.interactivity,
  fields: {
    required: ["channel", "stringInput", "date"],
    elements: [
      {
        name: "stringInput",
        title: "String input",
        type: Schema.types.string,
      },
      {
        name: "date",
        title: "Date Posted",
        type: Schema.slack.types.date,
      },
      {
        name: "channel",
        title: "Post in",
        type: Schema.slack.types.channel_id,
        default: TestReverseWorkflow.inputs.channel,
      },
    ],
  },
});

import { ReverseFunction } from "../functions/reverse.ts";
const reverseStep = TestReverseWorkflow.addStep(ReverseFunction, {
  input: formData.outputs.fields.stringInput,
});

// Add the date parameter as a step in your workflow. The message and date will be printed side by side.
TestReverseWorkflow.addStep(Schema.slack.functions.SendMessage, {
  channel_id: formData.outputs.fields.channel,
  message: reverseStep.outputs.reverseString + " " +
    formData.outputs.fields.date,
});

Expanded Rich Text

Type: slack#/types/expanded_rich_text

The expanded_rich_text type is a superset of the rich_text type, and is explicitly for use with canvases. It accepts all elements that rich_text provides and behaves in the same way as rich_text, except that it also accepts the following additional sub-elements:

Property Type Description
rich_text_header object The text for the header, in the form of a plain_text text object.
rich_text_divider object Creates a divider to place between text.
rich_text_list object This is an expanded version of the rich_text_list element used in rich_text blocks. It behaves the same, except that it accepts two new style fields: checked and unchecked. This allows for the creation of checklists.

Declare an expanded_rich_text type:

// ...
{
  name: "canvas_content",
  title: "Canvas Content",
  type: Schema.slack.types.expanded_rich_text
}
// ...
// ...
"canvas_content": {
  "title": "Canvas Content",
  "type": "slack#/types/expanded_rich_text"
}
// ...
Expanded rich text example

Here is an example payload that shows the expanded_rich_text type and all of its sub-elements:

[
    {
        "type": "expanded_rich_text",
        "elements": [
            {
                "type": "rich_text_header",
                "elements": [
                    {
                        "type": "text",
                        "text": "Hello world"
                    }
                ],
                "level": 1
            },
            {
                "type": "rich_text_list",
                "style": "unchecked",
                "indent": 0,
                "elements": [
                    {
                        "type": "rich_text_section",
                        "elements": [
                            {
                                "type": "text",
                                "text": "one"
                            }
                        ]
                    }
                ],
                "border": 0
            },
            {
                "type": "rich_text_list",
                "style": "checked",
                "indent": 1,
                "elements": [
                    {
                        "type": "rich_text_section",
                        "elements": [
                            {
                                "type": "text",
                                "text": "two"
                            }
                        ]
                    }
                ],
                "border": 0
            },
            {
                "type": "rich_text_divider"
            }
        ]
    }
]

File ID

Type: slack#/types/file_id

In addition to the properties noted above, a string type also has these optional properties available:

Property Type Description
allowed_filetypes_group string If provided, a predefined subset of filetypes will be restricted for file upload when this type is used in an OpenForm function. Can either be ALL or IMAGES_ONLY.
allowed_filetypes string[] If provided, only these filetypes are allowed for file upload in an OpenForm function. Empty arrays are not allowed. A list of filetypes supported by Slack can be found here. Filetypes defined here will override any restrictions set in allowed_filetypes_group.

Declare a file_id type:

// ...
fields: {
  elements: [
    {
      title: "Enter a file",
      name: "image-123",
      type: Schema.types.array,
      maxItems: 1,
      description: "",
      items: {
        type: Schema.slack.types.file_id,
        allowed_filetypes_group: "ALL"
      }
    },
  ],
},
// ...
// ...
"file": {
  "type": "slack#/types/file_id",
  "allowed_filetypes_group": "ALL"
}
// ...

OpenForm parameters

When using the file_id type in an OpenForm function, there are two additional parameters that can be utilized.

Parameter Type Description
allowed_filetypes_group string Can be either ALL or IMAGES_ONLY. If provided, specifies allowed predefined subset of filetypes for file in an OpenForm function.
allowed_filetypes array of strings If provided, specifies allowed filetypes for file upload in an OpenForm function. Overrides any restrictions set in allowed_filetypes_group.
File ID example

In this example workflow, we collect a file from the user.

import { Schema } from "deno-slack-sdk/mod.ts";
import { ImageWorkflow } from "../workflows/ImageWorkflow.ts";

const getImageStep = ImageWorkflow.addStep(
  Schema.slack.functions.OpenForm,
  {
    title: "Submit this form",
    interactivity: ImageWorkflow.inputs.interactivity,
    fields:{
      elements: [
        {
        title: "Enter a file",
        name: "image-123",
        type: Schema.types.array,
        maxItems: 1,
        description: "",
        items: {
          type: Schema.slack.types.file_id,
          allowed_filetypes_group: "ALL"
        },
      }
      ],
      required: ["image-123"],
    }
  },
);

Integer

Type: integer

In addition to the properties noted above, an integer type also has these optional properties available:

Property Type Description
minimum number Absolute minimum acceptable value for the integer.
maximum number Absolute maximum acceptable value for the integer.
enum number[] Constrain the available integer options to just the list of integers denoted in the enum property. Usage of enum also instructs any UI that collects a value for this parameter to render a dropdown select input rather than a free-form text input.
choices EnumChoice[] Defines labels that correspond to the enum values. For more details, refer to choices.

Declare an integer type:

// ...
  name: "meetings",
  title: "Number of meetings",
  type: Schema.types.integer,
// ...
// ...
"meetings": {
  "title": "Number of meetings",
  "type": "integer"
}
// ...
Integer example

In this example workflow, we check the number of meetings we have scheduled for the day.

import { Schema } from "deno-slack-sdk/mod.ts";
import { MeetingsWorkflow } from "../workflows/meetings.ts";

const inputForm = MeetingsWorkflow.addStep(
  Schema.slack.functions.OpenForm,
  {
    title: "Number of meetings",
    interactivity: MeetingsWorkflow.inputs.interactivity,
    submit_label: "Check meetings",
    fields: {
      elements: [
        {
          name: "channel",
          title: "Channel to send results to",
          type: Schema.slack.types.channel_id,
          default: MeetingsWorkflow.inputs.channel,
        },
        {
          name: "meetings",
          title: "Number of meetings",
          description: "meetings",
          type: Schema.types.integer,
          minimum: -1,
          maximum: 5,
        },
        {
          name: "meetingdate",
          title: "Meeting date",
          type: Schema.slack.types.date,
        },
      ],
      required: ["channel", "meetings", "meetingdate"],
    },
  },
);

Interactivity

Type: slack#/types/interactivity

Using interactivity in Workflow Builder

In Workflow Builder, this input type will not have a visibile input field and cannot be set manually by a builder.

Instead, the way the value is set is dependent on the situation:

  • If the workflow starts from an explicit user action (with a link trigger, for example), then the interactivity will be passed from the trigger to the following function input.

  • If the workflow starts from something other than an explicit user action (from a scheduled trigger, for example), then the builder of the workflow must place a step that creates an interactivity value (like a message with a button). This value can then be passed to the following function input.

  • A step with an interactivity input type must immediately follow a "user action", like a link trigger or a message with a button. Workflow Builder enforces this behavior.

If a workflow step requires interactivity and there is no way to ascertain the value within Workflow Builder, the workflow cannot be published.


In addition to the properties noted above, the interactivity type also has these properties available:

Property Type Description
interactivity_pointer string A pointer used to confirm user-initiated interactivity in a function.
interactor user_context Context information of the user who initiated the interactivity.

Declare the interactivity type:

// ...
properties: {
  interactivity: {
    type: Schema.slack.types.interactivity,
  },
},
// ...
// ...
"input_parameters": {
  "interactivity": {
  "type": "slack#/types/interactivity"
  }
}
// ...
Interactivity example

In this example workflow, we specify that it is an interactive workflow.

import { DefineWorkflow, Schema } from "deno-slack-sdk/mod.ts";

const GreetingWorkflow = DefineWorkflow({
  callback_id: "greeting_workflow",
  title: "Send a greeting",
  description: "Send a greeting to channel",
  input_parameters: {
    properties: {
      interactivity: { type: Schema.slack.types.interactivity },
      channel: { type: Schema.slack.types.channel_id },
    },
    required: ["interactivity"],
  },
});

Message Context

Type: slack#/types/message_context

The message_context type is used in the ReplyInThread Slack function as the target message you want to reply to.

For example, let's say you have a workflow step that uses the SendMessage function. If you want to send a reply to that message in a follow-on step that calls the ReplyInThread function, pass the return value from the first step into the message_context parameter of ReplyInThread.

Here's a brief example:

// Send a message to channel with ID C123456
const msgStep = GreetingWorkflow.addStep(Schema.slack.functions.SendMessage, {
  channel_id: "C123456",
  message: "This is a message to the channel.",
});

// Send a message as an in-thread reply to the above message by passing
// the outputs' message_context property
GreetingWorkflow.addStep(Schema.slack.functions.ReplyInThread, {
  message_context: msgStep.outputs.message_context,
  message: "This is a threaded reply to the above message.",
});
// ...
"message_context": {
  "type": "slack#/types/message_context"
}
// ...

You can also construct and deconstruct the message_context as you see fit in your app. Here is what comprises message_context:

Property Type Description Required
message_ts Schema.slack.types.message_ts A Slack-specific hash/timestamp necessary for referencing events like messages in Slack. Yes
channel_id Schema.slack.types.channel_id The ID of the channel where the message is posted. No

Any individual property on message_context could be referenced too. See the below example where we pass message_context.message_ts to the trigger_ts property:

//...

const message = CreateSurveyWorkflow.addStep(
  Schema.slack.functions.ReplyInThread,
  {
    message_context: {
      channel_id: CreateSurveyWorkflow.inputs.channel_id,
      message_ts: CreateSurveyWorkflow.inputs.parent_ts,
    },
    message:
      `Your feedback is requested – <${trigger.outputs.trigger_url}|survey now>!`,
  },
);

CreateSurveyWorkflow.addStep(SaveSurveyFunctionDefinition, {
  channel_id: CreateSurveyWorkflow.inputs.channel_id,
  parent_ts: CreateSurveyWorkflow.inputs.parent_ts,
  reactor_id: CreateSurveyWorkflow.inputs.reactor_id,
  trigger_ts: message.outputs.message_context.message_ts, //Here we reference message_ts from message_context
  trigger_id: trigger.outputs.trigger_id,
  survey_stage: "SURVEY",
});

//...

Message Timestamp

Type: slack#/types/message_ts

Declare a message_ts type:

//...
input_parameters: {
  properties: {
    message_ts : {
      type: Schema.slack.types.message_ts,
      description: "The ts value of a message"
    },
  },
},
//...
// ...
"input_parameters": {
  "message_ts": {
  "type": "slack#/types/message_ts",
  "description": "The ts value of a message"
  }
}
// ...
Message Timestamp example

In this example workflow from the Simple Survey sample app, a message_ts is used as an input parameter in two functions.

import { DefineWorkflow, Schema } from "deno-slack-sdk/mod.ts";

import { CreateGoogleSheetFunctionDefinition } from "../functions/create_google_sheet.ts";
import { CreateTriggerFunctionDefinition } from "../functions/create_survey_trigger.ts";
import { SaveSurveyFunctionDefinition } from "../functions/save_survey.ts";
import { RemoveThreadTriggerFunctionDefintion } from "../functions/remove_thread_trigger.ts";

/**
 * Workflows can also interweave the outputs from one step to
 * the inputs of another, compounding custom and Slack functions
 * to create connected processes.
 * https://api.slack.com/automation/workflows#workflow-custom-functions
 */
const CreateSurveyWorkflow = DefineWorkflow({
  callback_id: "create_survey",
  title: "Create a survey",
  description: "Add a request for feedback to a message",
  input_parameters: {
    properties: {
      channel_id: {
        type: Schema.slack.types.channel_id,
        description: "The channel containing the reacted message",
      },
      parent_ts: {
        type: Schema.types.string,
        description: "Message timestamp of the reacted message",
      },
      parent_url: {
        type: Schema.types.string,
        description: "Permalink to the reacted message",
      },
      reactor_id: {
        type: Schema.slack.types.user_id,
        description: "User that added the reacji",
      },
    },
    required: ["channel_id", "parent_ts", "parent_url", "reactor_id"],
  },
});

// Step 1: Create a new Google spreadsheet
const sheet = CreateSurveyWorkflow.addStep(
  CreateGoogleSheetFunctionDefinition,
  {
    google_access_token_id: {},
    title: CreateSurveyWorkflow.inputs.parent_ts,
  },
);

// Step 2: Create a link trigger for the survey
const trigger = CreateSurveyWorkflow.addStep(CreateTriggerFunctionDefinition, {
  google_spreadsheet_id: sheet.outputs.google_spreadsheet_id,
  reactor_access_token_id: sheet.outputs.reactor_access_token_id,
});

// Step 3: Delete the prompt message and metadata
CreateSurveyWorkflow.addStep(RemoveThreadTriggerFunctionDefintion, {
  channel_id: CreateSurveyWorkflow.inputs.channel_id,
  parent_ts: CreateSurveyWorkflow.inputs.parent_ts,
  reactor_id: CreateSurveyWorkflow.inputs.reactor_id,
});

// Step 4: Notify the reactor of the survey spreadsheet
CreateSurveyWorkflow.addStep(Schema.slack.functions.SendDm, {
  user_id: CreateSurveyWorkflow.inputs.reactor_id,
  message:
    `Feedback for <${CreateSurveyWorkflow.inputs.parent_url}|this message> is being <${sheet.outputs.google_spreadsheet_url}|collected here>!`,
});

// Step 5: Send the survey into the reacted thread
const message = CreateSurveyWorkflow.addStep(
  Schema.slack.functions.ReplyInThread,
  {
    message_context: {
      channel_id: CreateSurveyWorkflow.inputs.channel_id,
      message_ts: CreateSurveyWorkflow.inputs.parent_ts, //used here as part of the message_context object
    },
    message:
      `Your feedback is requested – <${trigger.outputs.trigger_url}|survey now>!`,
  },
);

// Step 6: Store new survey metadata
CreateSurveyWorkflow.addStep(SaveSurveyFunctionDefinition, {
  channel_id: CreateSurveyWorkflow.inputs.channel_id,
  parent_ts: CreateSurveyWorkflow.inputs.parent_ts,
  reactor_id: CreateSurveyWorkflow.inputs.reactor_id,
  trigger_ts: message.outputs.message_context.message_ts, //Referenced here individually
  trigger_id: trigger.outputs.trigger_id,
  survey_stage: "SURVEY",
});

export default CreateSurveyWorkflow;


Number

Type: number

In addition to the properties noted above, a number type also has these optional properties available:

Property Type Description
minimum number Absolute minimum acceptable value for the number.
maximum number Absolute maximum acceptable value for the number.
enum number[] Constrain the available number options to just the list of numbers denoted in the enum property. Usage of enum also instructs any UI that collects a value for this parameter to render a dropdown select input rather than a free-form text input.
choices EnumChoice[] Defines labels that correspond to the enum values. For more details, refer to choices.

Declare a number type:

// ...
{
  name: "distance",
  title: "race distance",
  type: Schema.types.number,
}
// ...
// ...
"distance": {
  "title": "race distance",
  "type": "number"
}
// ...
Number example

In this example workflow, we collect a runner's distance and date of their last run.

import { Schema } from "deno-slack-sdk/mod.ts";
import { LogRunWorkflow } from "../workflows/log_run.ts";

const inputForm = LogRunWorkflow.addStep(
  Schema.slack.functions.OpenForm,
  {
    title: "Log a run",
    interactivity: LogRunWorkflow.inputs.interactivity,
    submit_label: "Log run",
    fields: {
      elements: [
        {
          name: "channel",
          title: "Channel to send logged run to",
          type: Schema.slack.types.channel_id,
          default: LogRunWorkflow.inputs.channel,
        },
        {
          name: "distance",
          title: "Distance (in miles)",
          type: Schema.types.number,
          description: "race distance (in miles)",
          minimum: 0,
          maximum: 26.2,
        },
        {
          name: "rundate",
          title: "Run date",
          type: Schema.slack.types.date,
        },
      ],
      required: ["channel", "distance", "rundate"],
    },
  },
);

OAuth2

Type: slack#/types/credential/oauth2

Declare an oauth2 type:

// ...
  githubAccessTokenId: {
    type: Schema.slack.types.oauth2,
    oauth2_provider_key: "github",
  },
// ...
// ...
"github_access_token_id": {
  "type": "slack#/types/credential/oauth2",
  "oauth2_provider_key": "github"
}
// ...
OAuth2 example

In this example, we use the oauth2 type for an input parameter in a custom function. To read more about a full implementation of oauth2, check out External authentication.

export const CreateIssueDefinition = DefineFunction({
  callback_id: "create_issue",
  title: "Create GitHub issue",
  description: "Create a new GitHub issue in a repository",
  source_file: "functions/create_issue.ts",
  input_parameters: {
    properties: {
      githubAccessTokenId: {
        type: Schema.slack.types.oauth2,
        oauth2_provider_key: "github",
      },
      url: {
        type: Schema.types.string,
        description: "Repository URL",
      },

// ...

  },
  output_parameters: {
    properties: {
      GitHubIssueNumber: {
        type: Schema.types.number,
        description: "Issue number",
      },
      GitHubIssueLink: {
        type: Schema.types.string,
        description: "Issue link",
      },
    },
    required: ["GitHubIssueNumber", "GitHubIssueLink"],
  },
});

Object

Type: object

The object type also has the following optional property:

Property Type Description
choices EnumChoice[] Defines labels that correspond to the enum values. For more details, refer to choices.
Object types are not supported within Workflow Builder at this time
If your function will be used within Workflow Builder, we suggest not using the Object types at this time.

Objects can be typed or untyped. Here we have examples of both.

Typed Object

Refer to custom types for more information about typed objects, including properties and how to use DefineProperty to enforce required properties.

Declare a custom object type:

// ...
properties: {
  reviewer: DefineProperty({
    type: Schema.types.object,
    properties: {
      login: { type: "string" },
    },
  }),
},
// ...
// ...
"input_parameters": {
  "reviewer": {
    "type": "object",
    "properties": {
      "login": { "type": "string" }
    }
  } 
}

//...
Object example

In this example workflow, we notify authors about updates to their file review status.

import { DefineWorkflow, Schema } from "deno-slack-sdk/mod.ts";

export const ReviewStatusWorkflow = DefineWorkflow({
  callback_id: "review_status_workflow",
  title: "Review status",
  description: "Review status",
  input_parameters: {
    properties: {
      action: {
        type: Schema.types.string,
      },
      review_request: {
        type: Schema.types.object,
        properties: {
          number: { type: "integer" },
          title: { type: "string" },
          body: { type: "string" },
          changed_files: { type: "integer" },
        },
      },
      author: {
        type: Schema.types.object,
        properties: {
          login: { type: "string" },
        },
      },
      reviewer: {
        type: Schema.types.object,
        properties: {
          login: { type: "string" },
        },
      },
    },
    required: ["action", "review_request", "author", "reviewer"],
  },
});

Untyped Object

Untyped objects do not have properties defined on them. They are malleable; you can assign any kind of properties to them. In TypeScript lingo, these objects are typed as any.

Declare an untyped object type:

properties: {
  flexibleObject: {
    type: Schema.types.object,
  }
},

Options

Custom steps used as dynamic options within Workflow Builder must include an options output parameter of type slack#/types/options_select or slack#/types/options_field. More context in custom steps dynamic option.

Options field

Type: slack#/types/options_field

The slack#/types/options_field type defines the interface that a dynamic option step must return to render a set of fields in a dynamic options context. The slack#/types/options_field type is an array of items with the following parameters:

Name Type Required Description
text text object Yes Defines the text shown as the field name (same text type as the options Block Kit item).
key string Yes Represents a unique identifier to the field, used as the field key in the object representing the input parameter.
type string Yes The type of the field; which can be most valid input parameter types (string, array, user_id, and so on).
options options_select No When provided, it renders the field as a drop-down menu. This parameter is currently only compatible when the type is string or array. If the type is string, a single-select drop-down menu is rendered. If the type is array, a multi-select drop-down menu is rendered.
is_required boolean No When provided, indicates whether a given dynamic field should be required or not. Default value is false.
items object, { type: string } No Required when the type field is array; it defines the items of the array. The type: string dictates the type of the values in the options array. string is currently the only supported value.

Declare an options_field type:

{
  "title": "Test dynamic field options",
  "description": "",
  "input_parameters": {
    "dynamic_fields": {
      "type": "object",
      "title": "Dynamic custom field options",
      "description": "A dynamically-populated section of input fields",
      "dynamic_options": {
        "function": "#/functions/get-field-options",
        "inputs": {},
        "selection_type": "key-value"
      }
    }
  },
  "output_parameters": {}
}
Options field example

Below is an example of the slack#/types/options_field type that renders the following field types: primitives, Slack types, single-select drop-down menu, and multi-select drop-down menu:

"options": [
    {
        "text": {
            "type": "plain_text",
            "text": "Nickname",
        },
        "type": "string",
        "key": "nickname",
    },
    {
        "text": {
            "type": "plain_text",
            "text": "User",
        },
        "type": "slack#/types/user_id",
        "key": "user",
    },
    {
        "text": {
            "type": "plain_text",
            "text": "Vehicle",
        },
        "type": "string",
        "options": [
            {
                "text": {
                    "type": "plain_text",
                    "text": "Toyota",
                },
                "value": "value-0",
            },
            {
                "text": {
                    "type": "plain_text",
                    "text": "Subaru",
                },
                "value": "value-1",
            },
            {
                "text": {
                    "type": "plain_text",
                    "text": "Jeep",
                },
                "value": "value-2",
            },
        ],
        "key": "cars",
    },
    {
        "text": {
            "type": "plain_text",
            "text": "Pets",
        },
        "type": "array",
        "options": [
            {
                "text": {
                    "type": "plain_text",
                    "text": "Cat",
                },
                "value": "value-0",
            },
            {
                "text": {
                    "type": "plain_text",
                    "text": "Dog",
                },
                "value": "value-1",
            },
            {
                "text": {
                    "type": "plain_text",
                    "text": "Dragon",
                },
                "value": "value-2",
            },
        ],
        "key": "pets",
        "items": {
            "type": "string"
        },
    },
]

Options select

Type: slack#/types/options_select

The slack#/types/options_select type defines the interface that a dynamic options step must return to render a drop-down menu in a dynamic options context. The slack#/types/options_select type is an array of options Block Kit items, where only the text and value fields are required.

Declare an options_select type:

{
  "title": "Step that uses a dynamic input",
  "description": "This step uses a dynamic input rendered as a single-select menu",
  "input_parameters": {
    "dynamic_single_select": {
      "type": "string",
      "title": "dynamic single select drop-down menu",
      "description": "A dynamically-populated single-select drop-down menu",
      "is_required": true,
      "dynamic_options": {
        "function": "#/functions/get-options",
        "inputs": {}
      }
    }
  },
  "output_parameters": {}
}
Options select example
"options": [
    {
        "text": {
            "type": "plain_text",
            "text": "Cat",
        },
        "value": "value-0",
    },
    {
        "text": {
            "type": "plain_text",
            "text": "Dog",
        },
        "value": "value-1",
    },
    {
        "text": {
            "type": "plain_text",
            "text": "Dragon",
        },
        "value": "value-2",
    },
]

Rich text

Type: slack#/types/rich_text

Declare a rich_text type:

// ...
elements: [
  {
    name: "formattedStringInput",
    title: "String input",
    type: Schema.slack.types.rich_text,
  },
],
// ...
// ...
"elements": {
  "formattedStringInput": {
    "title": "String input",
    "type": "slack#/types/rich_text"
}
}
// ...
Rich text example

In this example workflow, we collect a formatted message from the user using the rich_text type.

import { DefineWorkflow, Schema } from "deno-slack-sdk/mod.ts";

const TestWorkflow = DefineWorkflow({
  callback_id: "test",
  title: "Test",
  input_parameters: {
    properties: {
      channel: { type: Schema.slack.types.channel_id },
      interactivity: { type: Schema.slack.types.interactivity },
    },
    required: ["interactivity"],
  },
});

const formData = TestWorkflow.addStep(Schema.slack.functions.OpenForm, {
  title: "Send Message Form",
  submit_label: "Send Message form",
  interactivity: TestWorkflow.inputs.interactivity,
  fields: {
    required: ["channel", "formattedStringInput"],
    elements: [
      {
        name: "formattedStringInput",
        title: "String input",
        type: Schema.slack.types.rich_text,
      },
      {
        name: "channel",
        title: "Post in",
        type: Schema.slack.types.channel_id,
        default: TestWorkflow.inputs.channel,
      },
    ],
  },
});

// To share this message object with other users, embed it into a Slack function such as SendMessage.
TestWorkflow.addStep(Schema.slack.functions.SendMessage, {
  channel_id: formData.outputs.fields.channel,
  message: formData.outputs.fields.formattedStringInput,
});

String

Type: string

In addition to the properties noted above, a string type also has these optional properties available:

Property Type Description
minLength number Minimum number of characters comprising the string.
maxLength number Maximum number of characters comprising the string.
enum string[] Constrain the available string options to just the list of strings denoted in the enum property. Usage of enum also instructs any UI that collects a value for this parameter to render a dropdown select input rather than a free-form text input.
choices EnumChoice[] Defines labels that correspond to the enum values. For more details, refer to choices.
format string Define accepted format of the string. Valid options include url or email.

Declare a string type:

// ...
{
  name: "notes",
  title: "Notes",
  type: Schema.types.string,
},
// ...
// ...
"notes": {
  "type": "string",
  "title": "notes"
}
// ...
String example

In this example workflow, we use a string type to allow a user to add notes about their time off request.

import { Schema } from "deno-slack-sdk/mod.ts";
import { CreateFTOWorkflow } from "../workflows/create_fto_workflow.ts";

const ftoRequestData = CreateFTOWorkflow.addStep(
  Schema.slack.functions.OpenForm,
  {
    title: "Request dates off",
    description: "Hooray for vacay!",
    interactivity: CreateFTOWorkflow.inputs.interactivity,
    submit_label: "Submit request",
    fields: {
      elements: [
        {
          name: "start_date",
          title: "Start date",
          type: Schema.slack.types.date,
        },
        {
          name: "end_date",
          title: "End date",
          type: Schema.slack.types.date,
        },
        {
          name: "notes",
          title: "Notes",
          description: "Anything to note?",
          type: Schema.types.string,
          long: true, // renders the input box as a multi-line text box on the form
        },
      ],
      required: ["start_date", "end_date"],
    },
  },
);

Team ID

Type: slack#/types/team_id

The team_id type also has the following optional property:

Property Type Description
choices EnumChoice[] Defines labels that correspond to the enum values. For more details, refer to choices.

Currently, this type is not supported for use in the OpenForm Slack function.

Declare a team_id type:

// ...
attributes: {
  team_id: {
    type: Schema.slack.types.team_id,
  },
},
// ...
// ...
"team_id": {
  "type": "slack#/types/team_id"
}
// ...

Timestamp

Type: slack#/types/timestamp

The timestamp type also has the following optional property:

Property Type Description
choices EnumChoice[] Defines labels that correspond to the enum values. For more details, refer to choices.

Declare a timestamp type:

// ...
inputs: {
  currentTime: {
    value: "{{data.trigger_ts}}",
    type: Schema.slack.types.timestamp,
  },
},
// ...
// ...
"input_parameters": {
  "current_time": {
  "type": "slack#/types/timestamp"
  }
}

// ...
Timestamp example

In this example trigger, we call a workflow that logs an incident and the time it occurred.

import { DefineWorkflow, Schema } from "deno-slack-sdk/mod.ts";
import { Trigger } from "deno-slack-api/types.ts";

export const MyWorkflow = DefineWorkflow({
  callback_id: "my_workflow",
  title: "My workflow",
  input_parameters: {
    properties: {
      currentTime: { type: Schema.slack.types.timestamp },
      interactivity: { type: Schema.slack.types.interactivity },
    },
    required: [],
  },
});

export const incidentTrigger: Trigger<typeof MyWorkflow.definition> = {
  type: "shortcut",
  name: "Log an incident",
  workflow: `#/workflows/${MyWorkflow.definition.callback_id}`,
  inputs: {
    currentTime: { value: "{{data.trigger_ts}}" },
    interactivity: { value: "{{data.interactivity}}" },
  },
};

User context

Type: slack#/types/user_context

Using user_context in Workflow Builder

In Workflow Builder, this input type will not have a visibile input field and cannot be set manually by a builder.

Instead, the way the value is set is dependent on the situation:

  • If the workflow starts from an explicit user action (with a link trigger, for example), then the user_context will be passed from the trigger to the function input. If the workflow contains a step that alters the user_context value (like a message with a button), then the altered user_context value is passed to the function input.

  • If the workflow starts from something other than an explicit user action (from a scheduled trigger, for example), then the builder of the workflow must place a step that sets the user_context value (like a message with a button). This value will then be passed to the input of the function.

If a workflow step requires user_context and there is no way to ascertain the value within Workflow Builder, the workflow cannot be published.


In addition to the properties noted above, the user_context type also has these properties available:

Property Type Description
id string The user_id of the person to which the user_context belongs.
secret string A hash used internally by Slack to validate the authenticity of the id in the user_context. This can be safely ignored, since it's only used by us at Slack to avert malicious actors!

Declare the user_context type:

// ...
input_parameters: {
  properties: {
    person_reporting_bug: {
      type: Schema.slack.types.user_context,
      description: "Which user?",
    },
  },
},
// ...
// ...
"input_parameters": {
  "person_reporting_bug": {
  "type": "slack#/types/user_context",
  "description": "Which user?"
  }
}
// ...
User context example

In this example workflow, we use the Schema.slack.types.user_context type to report a bug in a system and to collect the reporter's information.

import { DefineWorkflow, Schema } from "deno-slack-sdk/mod.ts";

const ReportBugWorkflow = DefineWorkflow({
  callback_id: "report_bug",
  title: "Report a Bug",
  description: "Report a bug",
  input_parameters: {
    properties: {
      channel_id: {
        type: Schema.slack.types.channel_id,
        description: "Which channel?",
      },
      person_reporting_bug: {
        type: Schema.slack.types.user_context,
        description: "Which user?",
      },
    },
    required: ["person_reporting_bug"],
  },
});

import { CreateBugFunction } from "../functions/create_bug.ts";

ReportBugWorkflow.addStep(
  CreateBugFunction,
  {
    title: "title",
    summary: "summary",
    urgency: "S0",
    channel_id: ReportBugWorkflow.inputs.channel_id,
    creator: ReportBugWorkflow.inputs.person_reporting_bug,
  },
);

User ID

Type: slack#/types/user_id

The user_id type also has the following optional property:

Property Type Description
choices EnumChoice[] Defines labels that correspond to the enum values. For more details, refer to choices.

Declare a user_id type:

// ...
{
  name: "runner",
  title: "Runner",
  type: Schema.slack.types.user_id,
}
// ...
// ...
"runner": {
  "title": "Runner",
  "type": "slack#/types/user_id"
}
// ...
User ID example

In this example workflow, we get a runner's ID and the distance of their logged run.

import { Schema } from "deno-slack-sdk/mod.ts";
import { RunWorkflow } from "../workflows/run.ts";

const inputForm = RunWorkflow.addStep(
  Schema.slack.functions.OpenForm,
  {
    title: "Log your run",
    interactivity: RunWorkflow.inputs.interactivity,
    submit_label: "Submit",
    fields: {
      elements: [
        {
          name: "channel",
          title: "Channel to send entry to",
          type: Schema.slack.types.channel_id,
          default: RunWorkflow.inputs.channel,
        },
        {
          name: "runner",
          title: "Runner",
          type: Schema.slack.types.user_id,
        },
        {
          name: "distance",
          title: "Distance (in miles)",
          type: Schema.types.number,
        },
      ],
      required: ["channel", "runner", "distance"],
    },
  },
);

Usergroup ID

Type: slack#/types/usergroup_id

The usergroup_id type also has the following optional property:

Property Type Description
choices EnumChoice[] Defines labels that correspond to the enum values. For more details, refer to choices.

Declare a usergroup_id type:

// ...
attributes: {
  usergroup_id: {
    type: Schema.slack.types.usergroup_id,
  },
},
// ...
// ...
"usergroup_id": {
  "type": "slack#/types/usergroup_id"
}
// ...
Usergroup ID example

In this example datastore definition, we store work shift details for a team.

import { DefineDatastore, Schema } from "deno-slack-sdk/mod.ts";

export const MyShifts = DefineDatastore({
  name: "shifts",
  primary_key: "id",
  attributes: {
    id: { type: Schema.types.string },
    team_id: { type: Schema.types.team_id },
    channel: { type: Schema.slack.types.channel_id },
    usergroup_id: { type: Schema.slack.types.usergroup_id },
    shiftRotation: { type: Schema.types.string },
  },
});

Have 2 minutes to provide some feedback?

We'd love to hear about your experience building Slack automations. Please complete our short survey so we can use your feedback to improve.