Twitch notifications (part three): How to create and notify a list of subscribers using Courier
Tags: node, twitch, notifications, discord
Published: 2021-02-09 13:30:03

In this series, I explain how to use [Twitch EventSub](https://dev.twitch.tv/docs/eventsub) and [Courier](https://www.courier.com) to automatically send notifications to multiple destinations – Slack, Discord, and more – when your Twitch stream goes live. 

In part one, [we built a Node.js app](https://www.courier.com/blog/how-to-handle-real-time-twitch-events) using Express.js to accept events from Twitch EventSub. In part two, we listened for our event and triggered a notification using Courier. Now, in part three, we're going to use Courier’s [List API](https://www.courier.com/blog/introducing-the-lists-api) to send multiple notifications when our event is triggered.

Follow along with the series: 
* Part one: [How to handle real-time events from Twitch](https://www.courier.com/blog/how-to-handle-real-time-twitch-events)
* Part two: [How to send notifications when your stream goes Twitch live](https://www.courier.com/blog/how-to-send-notifications-about-twitch-stream)
* Part three (this post): How to create and notify a list of subscribers using Courier

Need help getting started with sending notifications about your Twitch stream? [Join our community on Discord](https://discord.gg/courier) – we’re happy to chat!

# How to create and notify a list of subscribers using Courier

In this tutorial, I'll show you how to extend the [Node.js and Express app](https://www.courier.com/blog/how-to-send-notifications-about-twitch-stream) that we updated in part two to send notifications to more than one destination using Courier’s [Lists API](https://help.courier.com/en/articles/4340268-lists-api-list-id-pattern-guidelines). We'll update the sendOnline function to use a List send. I'll also demo sending to a [Discord](https://discord.com/) channel.

## Prerequisites

To complete this tutorial, you'll need a few things:

1. [Node.js and Express.js app from part two](https://www.courier.com/blog/how-to-send-notifications-about-twitch-stream)
1. [Courier account](https://app.courier.com/register/) – it’s free to sign up and includes 10,000 notifications per month
1. [Discord Bot](https://discord.com/developers/applications)
1. [Twitch CLI](https://github.com/twitchdev/twitch-cli) (v0.5.0+)

If you’re using the Node.js and Express.js app we created in part one, it should either be deployed somewhere publicly accessible that supports HTTPS and port 443, or be running locally [using ngrok](https://ngrok.com/docs#getting-started-expose). 

We'll need an existing Discord Bot that Courier can use to send your notifications. If you don't have one, check out our [Discord Integration Guide](https://docs.courier.com/docs/discord) to get started.

You'll also need your Courier Auth Token for the following steps. You can find your Courier Auth Token in [Settings > API Keys](https://app.courier.com/settings/api-keys) in your Courier account. Use the Published Production Key.

# Step one: Update your code to send to a list

To send to multiple recipients, we'll need to refactor the sendOnline function to use a list send instead of the regular send. We'll also need to create a list of recipients. To continue sending the SMS notification we created in part two, we'll create a stored profile for the recipient and subscribe them to our list.

## Create a List in Courier

To create our list, we'll use the [Courier Lists API](https://docs.courier.com/reference/lists-api). Our list will need a list id and a name. For this tutorial, we'll create a list with an id of "twitch.stream.online" and a name of "Twitch Stream Online." You can learn more about [using list id patterns](https://help.courier.com/en/articles/4340268-lists-api-list-id-pattern-guidelines) in our Help Center.

Let's create our list by executing the following cURL command in your terminal, replacing COURIER_AUTH_TOKEN with your auth token:

```shell
curl --request PUT \
  --url https://api.courier.com/lists/twitch.stream.online \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer COURIER_AUTH_TOKEN' \
  --header 'Content-Type: application/json' \
  --data '{"name":"Twitch Stream Online"}'
```

Your new list should now be visible in the data tab in your Courier Account.

## Add a new subscriber to the List

Now that we have a list, let's subscribe the recipient we used in part two to it. To do this, we'll first need to use the [Profiles API](https://docs.courier.com/reference/profiles-api) to store the recipient's profile information in Courier. Then, we'll make a call to the [List API](https://docs.courier.com/reference/lists-api#putlistsubscription) to subscribe them to the list.

We'll use the recipient id and profile information from the existing send command. Execute the following cURL command in your terminal using your values:

```shell
curl --request POST \
  --url https://api.courier.com/profiles/AYDRIAN10036 \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer COURIER_AUTH_TOKEN' \
  --header 'Content-Type: application/json' \
  --data '{"profile":{"phone_number":"+12025550140"}}'
```

Now that we have the profile stored, we can use the recipient id and subscribe it to our list. Execute the following cURl command in your terminal replacing AYDRIAN10036 with your recipient id:

```
curl --request PUT \
  --url https://api.courier.com/lists/twitch.stream.online/subscriptions/AYDRIAN10036 \
  --header 'Authorization: Bearer COURIER_AUTH_TOKEN'
```

Repeat this process to add more subscribers to the list. When you’re ready, let's update the code to send to our new list.

## Swap out the Courier Send

Previously, we told Courier to send to a single recipient. In order to send to the list we just created, we’ll need to use a List send instead.

In your index.js file, replace the following in the sendOnline function:

```javascript
const { messageId } = await courier.send({
  eventId: "TWITCH_ONLINE",
  recipient: "AYDRIAN10036",
  profile: {
    phone_number: "+12025550140"
  },
  data: { stream, game }
});
```

With the following:

```javascript
const { messageId } = await courier.send({
  event: "TWITCH_ONLINE",
  list: "twitch.stream.online",
  data: { stream, game }
});
```

Now if you were to run this code, it would still deliver the notification via SMS.

# Step two: Add Discord to your notification in Courier

Now that we can send notifications to multiple recipients with Lists, let's expand the available destinations. Recently, [Discord committed to fully supporting online communities](https://blog.discord.com/discord-is-for-your-communities-3d14464d4c7b), making it a top choice for notifying people about our Twitch stream. Let's add the ability to have Courier post to a channel using a Discord Bot.

## Configure the Discord integration in Courier

Let's start by configuring the [Discord integration](https://app.courier.com/integrations/discord). This will require you to enter the bot token for the bot that Courier will send as.

![Courier Discord Integration](https://dev-to-uploads.s3.amazonaws.com/i/09e5odevprx0hi406xhb.png)

## Design the Discord notification

Now we can update our existing Twitch Online Alert notification. We'll add Discord by clicking “Add Channel” and selecting Discord from the list of configured integrations.

![Add Discord notification channel](https://dev-to-uploads.s3.amazonaws.com/i/96zkurj2vb6uhs8eqvk6.png)

We can now select Discord under Channels to the left and start designing our notification. Because we have already created our SMS notification, we can reuse those content blocks for Discord. Simply drag the blocks in the Library section to our Discord notification.

![Discord notification](https://dev-to-uploads.s3.amazonaws.com/i/sgbu3jvxhd759kfb6kmc.png)

We now have a message that matches our SMS. Feel free to add more content blocks to your  Discord notifications. When you’re finished, click “Publish Changes” in the upper righthand corner.

If you'd like, you can preview the generated Discord markdown using the Preview tab. You can use the test event we created in part two.

![Discord notification preview](https://dev-to-uploads.s3.amazonaws.com/i/crjatuggml72t2wgf9yi.png)

# Step three: Subscribe a Discord channel to the List

Your notification is now ready to start sending to Discord. The last step is to identify the Discord channel that you want to post your notification in and add it as a recipient to our list. Similar to how we added a recipient for our SMS notification, we'll first create a profile in Courier and then subscribe it to the list.

We'll need the channel id of the channel we want to send to. An easy way to retrieve that is to turn on Developer Mode in Discord. You can go to User Settings > Appearance and scroll to Advanced at the bottom and toggle Developer Mode to on. This will allow you to right click on a channel and copy the id. 

![Discord User Settings](https://dev-to-uploads.s3.amazonaws.com/i/7edaj2va1pamckiagk1r.png)

I'm going to use the `#show-and-tell` channel in  [Courier’s Discord server](https://discord.gg/courier), which you’re welcome to join. For the recipient id, I'm going to use DISCORD_COURIER_SHOW_AND_TELL. It's a little long but descriptive.

Execute the following cURL command to create a profile for the channel in Courier:

```shell
curl --request POST \
  --url https://api.courier.com/profiles/DISCORD_COURIER_SHOW_AND_TELL \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer COURIER_AUTH_TOKEN' \
  --header 'Content-Type: application/json' \
  --data '{"profile":{"discord":{"channel_id":"801886566419136592"}}}'
```

Now we can execute the following cURL command to subscribe it to our list:

```shell
curl --request PUT \
  --url https://api.courier.com/lists/twitch.stream.online/subscriptions/DISCORD_COURIER_SHOW_AND_TELL \
  --header 'Authorization: Bearer COURIER_AUTH_TOKEN'
```

We can test our application using the Twitch CLI. Run the following command with the needed substitutions:

```shell
twitch event trigger streamup --to-user YOUR_BROADCASTER_ID -F https://EXTERNAL_URL/webhook/callback -s YOUR_SECRET
```

This command will trigger an example `stream.online` event using your broadcaster id. You should see the event in the [Courier Logs](https://app.courier.com/data/messages). You should receive an SMS message and that your Discord Bot has posted the following:

![Discord example notification](https://dev-to-uploads.s3.amazonaws.com/i/c393s54y1k8a81y4nbk7.png)

# Putting it all together: Full application code
With the update to the sendOnline function, your finished application should look like the following.

```javascript
require("dotenv").config();
const express = require("express");
const crypto = require("crypto");
const { CourierClient } = require("@trycourier/courier");
const app = express();
const port = process.env.PORT || 3000;
const twitchSigningSecret = process.env.TWITCH_SIGNING_SECRET;
const courier = CourierClient();
const { ApiClient } = require("twitch");
const { ClientCredentialsAuthProvider } = require("twitch-auth");
const authProvider = new ClientCredentialsAuthProvider(
  process.env.TWITCH_CLIENT_ID,
  process.env.TWITCH_CLIENT_SECRET
);
const twitch = new ApiClient({ authProvider });

app.get("/", (req, res) => {
  res.send("Hello World!");
});

const verifyTwitchSignature = (req, res, buf, encoding) => {
  const messageId = req.header("Twitch-Eventsub-Message-Id");
  const timestamp = req.header("Twitch-Eventsub-Message-Timestamp");
  const messageSignature = req.header("Twitch-Eventsub-Message-Signature");
  const time = Math.floor(new Date().getTime() / 1000);
  console.log(`Message ${messageId} Signature: `, messageSignature);

  if (Math.abs(time - timestamp) > 600) {
    // needs to be < 10 minutes
    console.log(
      `Verification Failed: timestamp > 10 minutes. Message Id: ${messageId}.`
    );
    throw new Error("Ignore this request.");
  }

  if (!twitchSigningSecret) {
    console.log(`Twitch signing secret is empty.`);
    throw new Error("Twitch signing secret is empty.");
  }

  const computedSignature =
    "sha256=" +
    crypto
      .createHmac("sha256", twitchSigningSecret)
      .update(messageId + timestamp + buf)
      .digest("hex");
  console.log(`Message ${messageId} Computed Signature: `, computedSignature);

  if (messageSignature !== computedSignature) {
    throw new Error("Invalid signature.");
  } else {
    console.log("Verification successful");
  }
};

const sendOnline = async (event) => {
  const stream = await twitch.helix.streams.getStreamByUserId(
    event.broadcaster_user_id
  );
  const game = await stream.getGame();

  const { messageId } = await courier.send({
    event: "TWITCH_ONLINE",
    list: "twitch.stream.online",
    data: { stream, game }
  });
  console.log(
    `Online notification for ${event.broadcaster_user_name} sent. Message ID: ${messageId}.`
  );
};

app.use(express.json({ verify: verifyTwitchSignature }));

app.post("/webhooks/callback", async (req, res) => {
  const messageType = req.header("Twitch-Eventsub-Message-Type");
  if (messageType === "webhook_callback_verification") {
    console.log("Verifying Webhook");
    return res.status(200).send(req.body.challenge);
  }

  const { type } = req.body.subscription;
  const { event } = req.body;

  console.log(
    `Receiving ${type} request for ${event.broadcaster_user_name}: `,
    event
  );

  if (type === "stream.online") {
    try {
      sendOnline(event);
    } catch (ex) {
      console.log(
        `An error occurred sending the Online notification for ${event.broadcaster_user_name}: `,
        ex
      );
    }
  }

  res.status(200).end();
});

const listener = app.listen(port, () => {
  console.log("Your app is listening on port " + listener.address().port);
});
```

Our application will process `stream.online` events and pass them to Courier along with additional stream data. Courier will then create SMS or Discord notifications based on the profiles in your list of subscribers.

# So, what's next?

You now have an application that will send notifications to a list of subscribers, via SMS and Discord, when you start your Twitch stream. I encourage you to explore adding more subscribers to your list and adding even more destinations like Slack and Facebook Messenger. [Join our Discord community](https://discord.gg/courier) and let me know where you go from here!

-Aydrian