How To Setup Twitch EventSub API Subscriptions

April - 2021
TODO: Figure out why this isn't working in MDX


### [x] TL;DR

Jump down to the Details section for a step-by-step walk-thru of how to setup to receive EventSub notifications from Twitch. 


### [x] Overview 


This is how to create a webhooks subscription with Twitch's new [EventSub API](https://dev.twitch.tv/docs/eventsub). The example uses follower notifications. You can find the list of the other [available subscription types here](https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types).

Twitch's EventSub docs indicate it will eventually be the sole API service and that it will provide both websockets and webhooks. An initial set of webhooks has been implement but as far as I can tell, websockets have not. (If you know better, [please let me know](https://twitter.com/TheIdOfAlan).) 

Setting up an EventSub webhook subscription works like this:

- 1. You create a JSON object/file with all the credentials, parameters, and callback URL necessary to define the subscription you want

- 2. You send a POST request with the JSON to Twitch

- 3. Twitch sends a separate "challenge" POST request with a JSON body to the callback URL you defined in your JSON

- 4. Your server responds to Twitch's challenge with a confirmation code from the JSON they sent 

After that, your subscription will be active and Twitch will send messages to your callback URL every time the requested even occurs. 

Two import points about your callback URL:

1. In order for Twitch to be able to send messages to your callback URL it has to be public
2. Twitch only sends messages to via HTTPS on port 443

I run my server locally and without a public address. In order to let twitch get to it, I use [localtunnel](https://github.com/localtunnel/localtunnel) to create a public address that connects with my local private server. It's worth pointing out that this setup means that localtunnel can see the traffic, but I'm not worried about that for these notifications. 



### [x] Details


#### [x] Step 1 - Create a Twitch Account with MFA

You'll need a Twitch account to create an app. I went with the option of making a new one that I also use for my chatbot. You'll need to turn MFA on under "[Settings -> Security an Privacy](https://www.twitch.tv/settings/security)" page. 

Note that if you have an existing account, you can turn on "Enable additional account creation" on the Security and Privacy page which will let you use the same email address when you make your new account. 

#### [x] Step 2 - Create an app

Go here after you've setup your account with MFA: [https://dev.twitch.tv/console/apps](https://dev.twitch.tv/console/apps)

(I think you'll be asked to authorize a twitch developer account here. I don't see that anymore since I've already done it. If someone lets me know I'll update these notes. Either way, if you do see it, click the Authorize button to allow access)

Click on the "Applications" tab if you aren't automatically redirected there. 

Click "+ Register Your Application"

Put in whatever for the "Name" field 

The "OAuth Redirect URLs" don't matter for EventSub. You just need to put in a valid domain. I use `http://localhost`. 

For "Category" choose "Chat Bot"

Click "Create" which will create your bot and take you back to the Applications listing page

Click the "Manage" button on the right side of the line for you bot on the Applications listing page. This will take you into back to the app specific page. 

Copy down your "Client ID" and put it in your password manager. (I'll call this `CLIENT_ID` in the rest of this example.)

Click "New Secret" to generate a new secret and put it in your password manager. I'll call this `CLIENT_SECRET` in the rest of the example. 

That's all you need to do on the page. 

#### [x] Step 3 - Create a Bearer Token

Replace `CLIENT_ID` and `CLIENT_SECRET` in this curl command below with the ones you made in the previous step and then run the command on the command line. 

    curl -XPOST https://id.twitch.tv/oauth2/token \
    -d "client_id=CLIENT_ID&client_secret=CLIENT_SECRET&grant_type=client_credentials"

The response will look something like this:

    {"access_token":"AAAABBBB","expires_in":5069123,"token_type":"bearer"}

Copy down the value from `access_token` and put it in your password manager. I'll refer to it as `BEARER_TOKEN` in the rest of the example. 

#### [x] Step 4 - Get Account IDs

You need the numeric ID of the account you want to watch. To get it, replace `ACCOUNT_NAME` in the this curl command with the one you're looking for (e.g. `theidofalan`). Also, fill in the `BEARER_TOKEN` and `CLIENT_ID`

        curl -X GET 'https://api.twitch.tv/helix/users?login=ACCOUNT_NAME' \
        -H 'Authorization: Bearer {BEARER_TOKEN}' \
        -H 'Client-Id: {CLIENT_ID}'

    This will return something like this:


        {"data":[{"id":"125363791","login":"theidofalan","display_name":"TheIdOfAlan","type":"","broadcaster_type":"","description":"I have ideas for things and bang on code until I get them to work. Learn a bunch of stuff along the way too 👍","profile_image_url":"https://static-cdn.jtvnw.net/jtv_user_pictures/27a51fbc-edd5-4abb-8ab3-d71843a0861a-profile_image-300x300.png","offline_image_url":"https://static-cdn.jtvnw.net/jtv_user_pictures/bc2aa4ba-49c6-490d-82e8-60ca3ae7f2e6-channel_offline_image-1920x1080.png","view_count":1665,"created_at":"2016-05-28T22:09:40.648226Z"}]}


    That `id` is what we'll use for {CHANNEL_ID}


### [x] Generate Secret

- Generate your own secret between 10-100 characters with a password generator. We'll reference it as {YOUR_SECRET} below. This *is not* the Client Secret from [developer console](https://dev.twitch.tv/console/apps). It's one that you make up yourself. 


### Start flask server 

- Start up the flask server in the .py file, then in the same directory, run:

        lt --port 5000

    (I think that's the right  port, but you might have to change it)

    This will give you something like:

    your url is: https://tame-rattlesnake-5.loca.lt

    WARNING: If folks on stream see this, they'll be able to hit it. Probably fine since it won't do anything, but they can hit the flask endpoint which might be annoying





### Connect to localhost

- You'll need a server on the public internet that twitch can hit. I used localtunnel:

        http://localtunnel.github.io/www/

    I did the global installation with:

        npm install -g localtunnel




- assemble callback URL which is the domain from localtunnel plus the route setup in flask. For example:

        https://tame-rattlesnake-5.loca.lt/webhooks/twitch-callback

    This is what we'll call {CALLBACK_URL}



### Send subscription

- create a JSON file named `request.json` like this:


{
    "type": "channel.follow",
    "version": "1",
    "condition": {
        "broadcaster_user_id": "{CHANNEL_ID}"
    },
    "transport": {
        "method": "webhook",
        "callback": "{CALLBACK_URL}",
        "secret": "{YOUR_SECRET}"
    }
}




- Finally, run this to do the subscription:


curl -X POST \
-H "Client-ID: {CLIENT_ID}" \
-H "Authorization: Bearer {BEARER_TOKEN}" \
-H "Content-Type: application/json" \
-d '@request.json' \
https://api.twitch.tv/helix/eventsub/subscriptions




---


TODO: Create a python example for sending the subscription request


TOOD: Determine if you can start localtunnel before flask (just to make sure that's not a gotcha)