Built-in types

In order to develop on the next-generation platform, your workspace must be on a paid plan.

When building next generation Slack apps with the Slack SDK, you can use a handful of built-in types (or even define your own). Built-in types are used in two ways with next generation Slack apps: as input and output parameters of Slack functions and as attributes of datastores.

Common properties

Each built-in 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 Data type Description
type string String that defines the parameter type.
title string An optional parameter title.
description string An optional parameter description.
hint string An optional parameter hint.
default The type that is being described; i.e. default for a boolean would be true or false. An optional parameter default value.
examples An array of the type being described. An optional list of examples.

Built-in types in datastores

When defining datastores, you may use built-in types for the datastore's attributes. Attributes accept only a single type property in the definition, instead of all the common properties listed above. 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 built-in types

Built-in type Data type Description
Schema.types.string String UTF-8 encoded string, up to 4000 bytes.
Schema.types.boolean Boolean A logical value, must be either true or false.
Schema.types.array Array An array of items (based on a type that you specify.)
Schema.types.object Object A custom Javascript object, like {"site": "slack.com"}.
Schema.types.integer Integer A whole number, such as -1, 0, or 31415926535.
Schema.types.number Number A number that allows decimal points such as 13557523.0005.
Schema.slack.types.user_id String A Slack user ID, such as U123ABC456 or W123ABC456.
Schema.slack.types.channel_id String A Slack channel ID, such as C123ABC456 or D123ABC456.
Schema.slack.types.usergroup_id String A Slack usergroup ID, such as S123ABC456.
Schema.slack.types.timestamp Integer A Unix timestamp in seconds. Not compatible with Slack message timestamps - use string instead.
Schema.slack.types.blocks Array of Slack Blocks An array of objects that contain layout and style information about your message.
Schema.slack.types.interactivity Object An object that contains context about the interactive event that led to opening of the form.
Schema.slack.types.user_context Object Represents a user who interacted with a workflow at runtime.
Schema.slack.types.date String A string containing a date, format is displayed as YYYY-MM-DD.
Schema.slack.types.rich_text Object A way to nicely format messages in your app. This type cannot convert other message types e.g. blocks, strings.
Schema.slack.types.oauth2 Object The OAuth2 context created after authenticating with external auth.
Schema.slack.types.message_ts String A Slack-specific hash/timestamp necessary for referencing events like messages in Slack.
Schema.slack.types.message_context Object An individual instance of a message.
Schema.slack.types.file_id Object A file ID, such as F123ABC456.

String

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

Property Data 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. See example below.
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,
},
// ...
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"],
    },
  },
);

Let's look at another example - this one using the choices property, which is an array of EnumChoice objects. Defining the choices property in this example allows us to have the label on the input form be capitalized, but the data to be saved be lowercase.

A closer look at the properties of EnumChoice:

Property Data type Description
value type the EnumChoice corresponds to; here it is string Value of the corresponding choice.
title string The label to display for this EnumChoice.
description string An optional description for this EnumChoice.
import { DefineWorkflow, Schema } from "deno-slack-sdk/mod.ts";

// ...

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

// ...

Boolean

Declare a boolean type:

// ...
isMember: {
  type: Schema.types.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 },
  },
});

Array

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"],
}
// ...

Fully defined arrays
Be sure to define the array's properties in the items object. Untyped objects are not currently supported.

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: [],
  },
});

Object

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" },
    },
  }),
},
// ...
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,
  }
},

Integer

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

Property Data 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. See example in the string example.

Declare an integer type:

// ...
  name: "meetings",
  title: "Number of meetings",
  type: Schema.types.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"],
    },
  },
);

Number

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

Property Data 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. See example in the string example.

Declare a number type:

// ...
{
  name: "distance",
  title: "race distance",
  type: Schema.types.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"],
    },
  },
);

User ID

Declare a user_id type:

// ...
{
  name: "runner",
  title: "Runner",
  type: Schema.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"],
    },
  },
);

Channel ID

Declare a channel_id type:

// ...
  input_parameters: {
    properties: {
      interactivity: {
        type: Schema.slack.types.interactivity,
      },
      channel: {
        type: Schema.slack.types.channel_id,
      },
    },
  },
// ...
Channel ID example

In this example workflow definition, we enable users to send a greeting to a specific channel.

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

export 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"],
  },
});

Usergroup ID

Declare a usergroup_id type:

// ...
attributes: {
  usergroup_id: {
    type: Schema.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.string },
    channel: { type: Schema.slack.types.channel_id },
    usergroup_id: { type: Schema.slack.types.usergroup_id },
    shiftRotation: { type: Schema.types.string },
  },
});

Timestamp

Declare a timestamp type:

// ...
inputs: {
  currentTime: {
    value: "{{data.trigger_ts}}",
    type: Schema.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}}" },
  },
};

Blocks

Declare an array of Block Kit JSON objects.

// ...
properties: {
  forecast: {
    type: Schema.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"],
  },
});

Interactivity

Declare the interactivity type:

// ...
properties: {
  interactivity: {
    type: Schema.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"],
  },
});

User context

Declare the user_context type:

// ...
input_parameters: {
  properties: {
    person_reporting_bug: {
      type: Schema.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,
  },
);

Date

Declare a date type:

// ...
fields: {
  elements: [
    {
      name: "date",
      title: "Date Posted",
      type: Schema.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,
});

Rich text

Declare a rich_text type:

// ...
elements: [
  {
    name: "formattedStringInput",
    title: "String input",
    type: Schema.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,
});

OAuth2

Declare an oauth2 type:

// ...
  githubAccessTokenId: {
    type: Schema.slack.types.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"],
  },
});

Message Timestamp

Declare a message_ts type:

//...
input_parameters: {
  properties: {
    message_ts : {
      type: Schema.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;


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.",
});

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",
});

//...

File ID

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"
    },
  ],
},
// ...

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"],
    }
  },
);

Have 2 minutes to provide some feedback?

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