Contents

EventSub

Introduction

Long-term our plan is to provide a single product, EventSub, that allows developers to subscribe to events and receive notifications over many different transports: webhooks, websockets, etc..

All events and payloads have been designed to be transport agnostic. Choosing webhooks over websockets (or vice-versa) won’t change the events available to you or how those events behave. If a new event type is added to EventSub, it is added to all transports simultaneously.

Subscriptions

Subscriptions enable your application to listen for events that happen on Twitch. When an event occurs for one of your subscriptions, Twitch sends you a notification. For example, you might choose to receive a notification when:

For a complete list of the available subscription types and their requirements, see EventSub Subscription Types.

Authorization

You must include an app access token in all API requests. You do not need to include a user access token, even for subscriptions that require user authorization. This is because Twitch checks authorization throughout the lifetime of your subscription by calling Twitch’s internal authorization systems directly.

Create a subscription

To create a subscription:

  1. Call the POST https://api.twitch.tv/helix/eventsub/subscriptions endpoint with the subscription details in the request body. The URL provided in the callback field MUST use HTTPS and port 443. For local development consider using a product like ngrok to easily create an HTTPS endpoint.

    POST https://api.twitch.tv/helix/eventsub/subscriptions
    ----
    Client-ID:     crq72vsaoijkc83xx42hz6i37
    Authorization: Bearer C0BIYxs4JvnBWqvAmBvjfFc
    Content-Type: application/json
    ----
    {
        "type": "channel.follow",
        "version": "1",
        "condition": {
            "broadcaster_user_id": "12826"
        },
        "transport": {
            "method": "webhook",
            "callback": "https://example.com/webhooks/callback",
            "secret": "s3cRe7"
        }
    }
    
  2. Twitch responds indicating the subscription request’s status is webhook_callback_verification_pending. This is because Twitch needs to verify that you own the callback you specified.

    {
        "data": [{
            "id": "f1c2a387-161a-49f9-a165-0f21d7a4e1c4",
            "status": "webhook_callback_verification_pending",
            "type": "channel.follow",
            "version": "1",
            "condition": {
                "broadcaster_user_id": "12826"
            },
            "transport": {
                "method": "webhook",
                "callback": "https://example.com/webhooks/callback"
            },
            "created_at": "2019-11-16T10:11:12.123Z"
        }],
        "total": 1,
        "limit": 10000
    }
    
  3. Twitch sends a callback verification request to your server using the callback URL provided in your request.

    POST https://example.com/webhooks/callback
    ----
    Twitch-Eventsub-Message-Id:             e76c6bd4-55c9-4987-8304-da1588d8988b
    Twitch-Eventsub-Message-Retry:          0
    Twitch-Eventsub-Message-Type:           webhook_callback_verification
    Twitch-Eventsub-Message-Signature:      sha256=f56bf6ce06a1adf46fa27831d7d15d
    Twitch-Eventsub-Message-Timestamp:      2019-11-16T10:11:12.123Z
    Twitch-Eventsub-Subscription-Type:      channel.follow
    Twitch-Eventsub-Subscription-Version:   1
    ----
    {
        "challenge": "pogchamp-kappa-360noscope-vohiyo",
        "subscription": {
            "id": "f1c2a387-161a-49f9-a165-0f21d7a4e1c4",
            "status": "webhook_callback_verification_pending",
            "type": "channel.follow",
            "version": "1",
            "condition": {
                    "broadcaster_user_id": "12826"
            },
            "transport": {
                "method": "webhook",
                "callback": "https://example.com/webhooks/callback"
            },
            "created_at": "2019-11-16T10:11:12.123Z"
        }
    }
    
  4.  Verify the request signature  to make sure it came from Twitch.
  5. Return the value of challenge from the callback verification request to complete the verification process. Your response must be a raw string. If your server is using a web framework, be careful that your web framework isn’t modifying the response in an incompatible way. For example, some web frameworks default to converting responses into JSON objects.
    pogchamp-kappa-360noscope-vohiyo

  6. Your subscription is now active!

Receive a notification

When an event triggers your subscription, Twitch will send a notification to your callback.

To test receiving a notification:

  1.  Create a subscription  for when channel 12826 receives a new follower.
  2. Go to Twitch and follow that channel.
  3. You’ll receive a notification request to your subscription’s callback:

    POST https://example.com/webhooks/callback
    ----
    Twitch-Eventsub-Message-Id:             befa7b53-d79d-478f-86b9-120f112b044e
    Twitch-Eventsub-Message-Retry:          0
    Twitch-Eventsub-Message-Type:           notification
    Twitch-Eventsub-Message-Signature:      sha256=d66824350041dce130e3478f5a7
    Twitch-Eventsub-Message-Timestamp:      2019-11-16T10:11:12.123Z
    Twitch-Eventsub-Subscription-Type:      channel.follow
    Twitch-Eventsub-Subscription-Version:   1
    ----
    {
        "subscription": {
            "id": "f1c2a387-161a-49f9-a165-0f21d7a4e1c4",
            "status": "authorization_revoked",
            "type": "channel.follow",
            "version": "1",
            "condition": {
                "broadcaster_user_id": "12826"
            },
            "transport": {
                "method": "webhook",
                "callback": "https://example.com/webhooks/callback"
            },
            "created_at": "2019-11-16T10:11:12.123Z"
        },
        "event": {
            "user_id":   "1337",
            "user_name": "awesome_user",
            "broadcaster_user_id":     "12826",
            "broadcaster_user_name":   "twitch"
        }
    }
    
  4.  Verify the request signature  to make sure it came from Twitch.
  5. Acknowledge the notification by returning a 2XX status code.

It is expected that you’ll respond to the notification request within a few seconds. If your server takes too long to respond, the request will time out. If your server can’t process a notification request quickly enough, consider writing the payload to temporary storage, responding with a 2XX, then processing the notification afterwards.

Twitch’s subscriptions are designed as an at-least-once system. This means that if Twitch is ever unsure whether you received a notification, it’ll retry. Under some circumstances this means you may receive a notification twice. If this is problematic for your use case, review the handling duplicates section for information on how to handle this reliably.

List your subscriptions

To view your current subscriptions, call the GET https://api.twitch.tv/helix/eventsub/subscriptions endpoint. This endpoint will return a paginated list of all your subscriptions, including subscriptions that are disabled. This API endpoint is a great debugging tool if you aren’t receiving notifications for a subscription you believe should exist.

Request

GET https://api.twitch.tv/helix/eventsub/subscriptions
----
Client-ID:     crq72vsaoijkc83xx42hz6i37
Authorization: Bearer deadbeefdeadbeef

Response

{
    "data": [
        {
            "id": "26b1c993-bfcf-44d9-b876-379dacafe75a",
            "status": "enabled",
            "type": "streams.online",
            "version": "1",
            "condition": {
                "broadcaster_user_id": "1234"
            },
            "created_at": "2020-11-10T20:08:33Z",
            "transport": {
                "method": "webhook",
                "callback": "https://this-is-a-callback.com"
            }
        },
        {
            "id": "35016908-41ff-33ce-7879-61b8dfc2ee16",
            "status": "webhook-callback-verification-pending",
            "type": "users.update",
            "version": "1",
            "condition": {
                "user_id": "1234"
            },
            "created_at": "2020-11-10T20:31:52Z",
            "transport": {
                "method": "webhook",
                "callback": "https://this-is-a-callback.com"
            }
        }
    ],
    "total": 2,
    "limit": 10000,
    "pagination": {}
}

Note that the total field contains an approximate number of subscriptions. After creating or deleting a subscription, it may take a few seconds for total to update.

You can also filter by subscriptions status by including the status query parameter in the request. For example, if you want only enabled subscriptions call GET https://api.twitch.tv/helix/eventsub/subscriptions?status=enabled.

All possible statuses are:

Delete a subscription

To delete a subscription call the DELETE https://api.twitch.tv/helix/eventsub/subscriptions endpoint and specify the id for the subscription to delete.

DELETE https://api.twitch.tv/helix/eventsub/subscriptions?id=f1c2a387-161a-49f9-a165-0f21d7a4e1c4
----
Client-ID:     crq72vsaoijkc83xx42hz6i37
Authorization: Bearer deadbeefdeadbeef

Verify a signature

Whenever you receive a request from Twitch, a signature will be included in the Twitch-Eventsub-Message-Signature header. To verify that a request is authentic you must verify its signature.

The signature uses HMAC-SHA256. The HMAC key is your subscription’s secret. The HMAC message is the concatenation of the Twitch-Eventsub-Message-Id header, the Twitch-Eventsub-Message-Timestamp header, and the raw bytes of the request body.

If the signature in the Twitch-Eventsub-Message-Signature doesn’t match the signature you computed, return a 4XX status code.

Pseudocode

hmac_message = headers['Twitch-Eventsub-Message-Id'] + headers['Twitch-Eventsub-Message-Timestamp'] + request.body
signature = hmac_sha256(webhook_secret, hmac_message)
expected_signature_header = 'sha256=' + signature.hex()

if headers['Twitch-Eventsub-Message-Signature'] != expected_signature_header:
    return 403

Note: Request header names are case-insensitive. Some languages, like JavaScript, convert header names to lowercase regardless of how they were sent. If your language does this, use .toLowerCase() before checking headers.

If your use case requires resiliency against replay attacks, do the following:

Handling duplicates

Twitch’s subscriptions are designed as an at-least-once system. This means that if Twitch is ever unsure whether you received a message, it’ll retry. Under some circumstances this means you may receive a message twice.

Every message includes a Twitch-Eventsub-Message-Id header. If a message is retried, the value of the Twitch-Eventsub-Message-Id header will stay the same.

If you need to deduplicate messages, keep track of the values of Twitch-Eventsub-Message-Id you’ve seen. If you receive a message that contains a Twitch-Eventsub-Message-Id you’ve already seen, immediately return a 2XX status code.

Subscription revocation

Twitch reserves the right to revoke a subscription at any time. The most common reasons for revocation are:

When a subscription is revoked, you’ll receive a revocation request to that subscription’s callback:

POST https://example.com/webhooks/callback
----
Twitch-Eventsub-Message-Id:             84c1e79a-2a4b-4c13-ba0b-4312293e9308
Twitch-Eventsub-Message-Retry:          0
Twitch-Eventsub-Message-Type:           revocation
Twitch-Eventsub-Message-Signature:      sha256=c1f92c51dab9888b0d6fb5f7e8e758
Twitch-Eventsub-Message-Timestamp:      2019-11-16T10:11:12.123Z
Twitch-Eventsub-Subscription-Type:      channel.follow
Twitch-Eventsub-Subscription-Version:   1
----
{
    "subscription": {
        "id": "f1c2a387-161a-49f9-a165-0f21d7a4e1c4",
        "status": "authorization-revoked",
        "type": "channel.follow",
        "version": "1",
        "condition": {
            "broadcaster_user_id": "12826"
        },
        "transport": {
            "method": "webhook",
            "callback": "https://example.com/webhooks/callback"
        },
        "created_at": "2019-11-16T10:11:12.123Z"
    }
}

To handle a subscription revocation request:

  1.  Verify the request signature  to make sure it came from Twitch.
  2. Return a 2XX status code.

Limits

Twitch enforces limits on the subscriptions you create: