Send and receive metadata events

This tutorial will walk you through the creation of a Slack app that can send and receive metadata events using Slack triggers, workflows, and functions.

Features you’ll use

Scopes you'll request

1Set up the Slack CLI

Use the new Slack CLI to create and deploy Slack apps. With the Slack CLI, developers can create an app and generate some boilerplate code in seconds.

This section walks through setting up your environment for next gen platform development.

  • Install the Slack CLI

    We've built a command line interface to make the process of creating new apps, running them, and deploying them easier. Binaries are available for macOS and Windows.

    Deno is currently a pre-requisite for using the CLI — if you do not have Deno installed, please do so first.

    Additionally, the experience of writing an app will be greatly enhanced if your IDE includes support for Deno. Here's a plugin to add Deno capabilities to VS Code.

    To install the Slack CLI:

    1. Download the latest binary for your platform
    2. Decompress the downloaded file. On macOS, copy the slack binary to a destination in your path (we recommend /usr/local/bin). For Windows, copy the .exe file into any location accessible in your path.
    3. Test the app is properly installed by running slack version and verifying the version matches the one you downloaded.

    Now you can now use the Slack CLI to authenticate and create a new app.

  • Authenticate the Slack CLI

    Before you can create an app, you must authenticate.

    1. Run slack login — this will display some instruction text and a string to copy and paste in any channel in the test workspace.

          /hermesauthticket ABC123DEF...XYZ
      
    2. Copy the entire string, including the leading /, and paste it into any channel in your Slack workspace. (You are essentially calling a special slash command that will authenticate your app with Slack).

    3. Run slack auth info for details on your active workspace authorization.

    Now that you've authenticated, you can create a new app.

2Create a Slack app

This section walks you through the structure of your app and how the different pieces tie together.

We will then define a function invoked by a Slack trigger that creates a new incident channel, and sends a message with important incident data.

  • Create a new app

    Now you can create an app! cd to a directory where you have write access and want your app to live, most likely in your home. Then, run

    $ slack create [optional-project-name]
    

    This will create a new project called with a random name like priceless-lemur-123.

    If you want to name your project something specific, include an additional parameter

    $ slack create my-new-project
    

    Once the app has finished running, you'll have a new directory that contains a skeleton app.

    $ cd my-new-project
    

    The structure of these next-generation apps aims to favor convention over configuration. Directories are named logically and the files within those directories map to specific functionality with an app. For example, the functions directory contains a list of an app's functions, with a single file for each function an app defines.

  • Understand how the app is structured

    Your new project has a directory structure that should resemble the following:

    .slack/
      - apps.json
      - cli.json
    assets/
      - icon.png
    functions/
     - myfunction.ts
    tables/
     - mytable.ts
    triggers/
     - mytrigger.ts
    workflows/
     - myworkflow.ts
    import_map.json
    project.ts
    README.md
    

    Functions: Modular, reusable, atomic blocks of functionality that can be grouped together as workflows. A function defines inputs, performs some useful bit of work using those inputs, and responds with pre-defined outputs. You'll be able to quickly write custom functions, deploy them via the CLI, and building workflows using these functions. Check out our functions documentation to learn more.

    Workflows: A workflow is a group of functions, including built-in functions provided by Slack. Check out our workflows documentation to learn more.

    Triggers: Define how workflows are called, such as a message action, shortcut, or event, where it is able to be executed, and who can execute it. Check out our triggers documentation to learn more.

    Tables: Define tables and store data to power your application. Check out our tables documentation to learn more.

    Project.ts: Contains all of the metadata about a project, such as the name of project, description, and requested OAuth scopes. It also contains a list of defined functions, tables, triggers and workflows.

3Send a metadata event

Let's use a Slack Trigger, Workflow, and Function to learn how to send message events that include metadata.

The trigger will start a workflow that displays a modal. The modal will allow a user to enter a message and a secret that's stored as metadata. When the workflow is run, it will execute a function that sends the message with the secret metadata into a Slack channel.

  • Adding a new function to send metadata events

    Let's begin by defining a function that will send a message with metadata to the Slack channel. The metadata object has an event payload that contains our secret message and the user who created the original message.

    Create a new file called functions/send_metadata_event.ts with the following content:

    import { DefineFunction, Schema } from "slack-cloud-sdk/mod.ts";
    
    export const SEND_METADATA_EVENT_TYPE = "secret_message_event_type";
    
    export const SendMetadataEventFunction = DefineFunction(
      "send_metadata_event_function",
      {
        title: "Send a message with metadata",
        description: "Sends a message with a event metadata into a channel",
        input_parameters: {
          message: {
            type: Schema.types.string,
            description: "Message to send",
          },
          secret: {
            type: Schema.types.string,
            description: "Secret message included as metadata",
          },
          channel_id: {
            type: Schema.slack.types.channel_id,
            description: "Channel to send the message",
          },
          user_id: {
            type: Schema.slack.types.user_id,
            description: "User included as metadata",
          },
        },
        output_parameters: {
          ok: {
            type: Schema.types.boolean,
            description: "Returns true if the message was send successfully",
          },
        },
      },
      async ({ inputs, client }) => {
        console.log(`SendMetadataEventFunction inputs: ${JSON.stringify(inputs)}`);
    
        const resp = await client.call("chat.postMessage", {
          text: `:speech_balloon: ${inputs.message}`,
          channel: inputs.channel_id,
          metadata: {
            event_type: SEND_METADATA_EVENT_TYPE,
            event_payload: {
              message: inputs.message,
              secret: inputs.secret,
              user_id: inputs.user_id,
            },
          },
        });
    
        if (!resp.ok) {
          console.log(`Error sending message: ${resp.error}`);
        } else {
          console.log(`Successfully sent message: ${JSON.stringify(resp)}`);
        }
    
        return {
          outputs: {
            ok: resp.ok,
          },
        };
      },
    );
    

    Now that we've created the function, we need to import and reference it in the Project definition.

    Open the file project.ts and add the SendMetadataEventFunction import to the functions property:

    import { Project } from "slack-cloud-sdk/mod.ts";
    import { SendMetadataEventFunction } from "./functions/send_metadata_event.ts";
    // ...
    
    Project({
      //...
      functions: [SendMetadataEventFunction],
      //...
    });
    
  • Adding a new workflow to execute the function

    Now let's define the workflow that will invoke the function we just defined. The workflow will open a modal to get a message and secret metadata from the user. It will then execute our function that sends a message with the metadata.

    Create a new file called workflows/send_metadata_event.ts with the following content:

    import { DefineWorkflow, Schema } from "slack-cloud-sdk/mod.ts";
    import { SendMetadataEventFunction } from "../functions/send_metadata_event.ts";
    
    export const SendMetadataEventWorkflow = DefineWorkflow(
      "send_metadata_event_workflow",
      {
        title: "Send a message with metadata",
        description: "Send a message with custom metadata",
        input_parameters: {
          message: {
            type: Schema.types.string,
            description: "Message to send",
          },
          secret: {
            type: Schema.types.string,
            description: "Secret message included as metadata",
          },
          channel_id: {
            type: Schema.slack.types.channel_id,
            description: "Channel to send the message",
          },
          user_id: {
            type: Schema.slack.types.user_id,
            description: "User who created the message",
          },
        },
      },
    );
    
    SendMetadataEventWorkflow.addStep(SendMetadataEventFunction, {
      message: SendMetadataEventWorkflow.inputs.message,
      secret: SendMetadataEventWorkflow.inputs.secret,
      channel_id: SendMetadataEventWorkflow.inputs.channel_id,
      user_id: SendMetadataEventWorkflow.inputs.user_id,
    });
    

    Now that we've created the workflow, we need to import and reference it in the Project definition.

    Open the file project.ts and add the SendMetadataEventWorkflow import to the workflows property:

    import { Project } from "slack-cloud-sdk/mod.ts";
    import { SendMetadataEventWorkflow } from "./workflows/send_metadata_event.ts";
    // ...
    
    Project({
      // ...
      workflows: [SendMetadataEventWorkflow],
      // ...
    });
    
  • Adding a new trigger to start the workflow

    At this point we have a function that sends metadata and a workflow that invokes the function. Now we can now create a Shortcut trigger that will run the workflow, causing a modal to open so we can provide the input parameters to the workflow.

    Create a file called triggers/send_metadata_event_shortcut.ts with the following content:

    import { DefineTrigger, TriggerTypes } from "slack-cloud-sdk/mod.ts";
    import { SendMetadataEventWorkflow } from "../workflows/send_metadata_event.ts";
    
    export const SendMetadataEventShortcut = DefineTrigger(
      "send_metadata_event_shortcut",
      {
        type: TriggerTypes.Shortcut,
        name: "Send a secret message",
        description: "Send a message to a channel with event metadata",
      },
    )
      .runs(SendMetadataEventWorkflow)
      .withInputs((ctx) => ({
        message: "This message includes a secret",
        channel_id: ctx.data.channel_id,
        user_id: ctx.data.user_id,
      }));
    

    Now that we've created the trigger, we need to import and reference it in the Project definition.

    Open the file project.ts and add the SendMetadataEventShortcut import to the triggers property:

    import { Project } from "slack-cloud-sdk/mod.ts";
    import { SendMetadataEventShortcut } from "./triggers/send_metadata_event_shortcut.ts";
    // ...
    
    Project({
      // ...
      triggers: [SendMetadataEventShortcut],
      // ...
    });
    
  • Try it out

    It's time to try sending a message with metadata into Slack:

    1. Deploy your app to Slack with slack deploy
      • Or, run the app locally using slack run
    2. Launch the Shortcut trigger called "Send a secret message"
      • To find the Shortcut, select the ⚡️ lightning bolt in your message composer
    3. Submit the modal dialog
      • Message: "This message includes a secret"
      • Secret: "Shhh..."
    4. Confirm that you received a message
      • Message: "This message includes a secret"

    Did you notice that you can't see the secret message "Shhh..."? This is because it's part of the metadata event. Next, we'll learn how to receive the metadata event and payload.

4Receive a metadata event

Let's learn how to receive a metadata event using a Slack Trigger, Workflow, and Function.

We'll start by creating a trigger that listens for our metadata event. When we receive an event, then we'll run a workflow that sends a message into Slack to reveal the event's metadata.

  • Adding a new workflow to execute the function

    Let's begin by creating a workflow for receiving metadata events. This workflow will use a built-in Slack function to send a message that reveals the event's metadata.

    Create a new file called workflows/receive_metadata_event.ts with the following content:

    import { DefineWorkflow, Schema } from "slack-cloud-sdk/mod.ts";
    
    export const ReceiveMetadataEventWorkflow = DefineWorkflow(
      "receive_metadata_event_workflow",
      {
        title: "Receives and responds to a metadata event",
        description: "Receives a metadata event and sends a message in response",
        input_parameters: {
          metadata: {
            type: Schema.types.object,
            description: "Custom message metadata",
          },
          channel_id: {
            type: Schema.slack.types.channel_id,
            description: "Channel to send the message",
          },
        },
      },
    );
    
    ReceiveMetadataEventWorkflow.addStep(Schema.slack.functions.SendMessage, {
      channel_id: ReceiveMetadataEventWorkflow.inputs.channel_id,
      message:
        `:magic_wand: Revealing the secret message:\n> ${ReceiveMetadataEventWorkflow
          .inputs.metadata.event_payload?.secret} - <@${ReceiveMetadataEventWorkflow
          .inputs.metadata.event_payload?.user_id}>`,
    });
    

    Now that we've created the workflow, we need to import and reference it in the Project definition.

    Open the file project.ts and add the ReceiveMetadataEventWorkflow import to the workflows property:

    import { Project } from "slack-cloud-sdk/mod.ts";
    import { ReceiveMetadataEventWorkflow } from "./workflows/receive_metadata_event.ts";
    import { SendMetadataEventWorkflow } from "./workflows/send_metadata_event.ts";
    // ...
    
    Project({
      // ...
      workflows: [ReceiveMetadataEventWorkflow, SendMetadataEventWorkflow],
      // ...
    });
    
  • Adding a new trigger to receive the metadata events

    Next, let's define an Event trigger that listens for our custom MessageMetadataPosted event and runs the new workflow we just created in the previous step.

    Create a file called triggers/receive_metadata_event.ts with the following content:

    import { DefineTrigger, Schema, TriggerTypes } from "slack-cloud-sdk/mod.ts";
    import { ReceiveMetadataEventWorkflow } from "../workflows/receive_metadata_event.ts";
    import { SEND_METADATA_EVENT_TYPE } from "../functions/send_metadata_event.ts";
    
    // TODO - Update to be your Slack channel ID (e.g. "C02AL6F9NU9")
    const CHANNEL_ID = "C0XXXXXX";
    
    export const ReceiveMetadataEvent = DefineTrigger(
      "receive_metadata_event",
      {
        type: TriggerTypes.Event,
        event_type: Schema.slack.events.MessageMetadataPosted,
        metadata_event_type: SEND_METADATA_EVENT_TYPE,
      },
    )
      .runs(ReceiveMetadataEventWorkflow)
      .withInputs((ctx) => ({
        channel_id: ctx.data.channel_id,
        metadata: ctx.data.metadata,
      }))
      .availableToChannel(CHANNEL_ID);
    

    Next, update the CHANNEL_ID to the channel where your app is run:

    1. Right-click on the Slack channel name
    2. Select "Copy link"
    3. Paste the link and copy the end of the URL path (e.g. "C02AL6F9NU9")

    Now that we've created the trigger, we need to import and reference it in the Project definition.

    Open the file project.ts and add the ReceiveMetadataEvent import to the triggers property:

    import { Project } from "slack-cloud-sdk/mod.ts";
    import { ReceiveMetadataEvent } from "./triggers/receive_metadata_event.ts";
    import { SendMetadataEventShortcut } from "./triggers/send_metadata_event_shortcut.ts";
    // ...
    
    Project({
      // ...
      triggers: [ReceiveMetadataEvent, SendMetadataEventShortcut],
      // ...
    });
    
  • Try it out

    To try it all out, we'll use the Shortcut trigger that we created earlier to send a metadata event. Then our new Event trigger will listen for the same metadata event and respond with a message that reveals the metadata.

    1. Deploy your app to Slack with slack deploy
      • Or, run the app locally using slack run
    2. Launch the Shortcut trigger called "Send a secret message"
      • To find the Shortcut, select the ⚡️ lightning bolt in your message composer
    3. Submit the modal dialog
      • Message: "This message includes a secret"
      • Secret: "Shhh..."
    4. Confirm that you received a message
      • Message: "This message includes a secret"
    5. Confirm that you received a second message
      • Message: "Revealing the secret message: Shhh..."

5Going further

This is a simple example that shows how to send and receive metadata events.

We do it all within one app, but your app can also listen for metadata events from other apps. This can open a whole new world of possibility, because it allows apps to communicate with other apps.

The robots are taking over! 🤖

    Was this page helpful?