API Get Chatters - Impossible?

Okay. I have a big issue.

I was able to get the user list of a chatter trough the helix api. But now, its not longer possible in any way.

Regardless, what i try (new token, new client secret, oauth-login … nothing works anymore. I get 404 or 401 again and again.

And it feels, that the documentation is way outdated …

I work with nodeJS. So my current code looks like this:

  async getChatters(chId) {
    const headers = {
      'Client-ID': this.api.clientId,
      'Authorization': `Bearer ${this.api.moderatorToken}`,
    };
    const userListResponse = await fetch(`https://api.twitch.tv/helix/chat/chatters?` +
      `broadcaster_id=${chId}&` +
      `moderator_id=${this.auth.id}&` +
      `first=1000`,
      { headers }
    );
    const userListResponseData = await userListResponse.json();
    console.log(userListResponseData);
    var nList = [];
    for(var i = 0;i < userListResponseData.data.length;i++) {
      nList.push(userListResponseData.data[i].user_login);
    }
    return nList;
  }

The placeholders:
chld = the lower-case name of the target channel
this.api.clientId = client_id from dev-console
this.api.moderatorToken = access-token with the scope “moderator:read:chatters”
this.auth.id = the user-id of the user, where is authenticated with client id and for wich the token is created

So … what goes wrong?

Whats the body of the response?
HTTP code is half the information

The documentation is correct

Your code looks correct as it approx matches mine

I just construct the URL to call differently.

Mine looks like

async function runPage(jobResult, cursor) {
    let params = [
        [ 'broadcaster_id', jobResult.channel_id ],
        [ 'moderator_id', process.env.USER_ID ],
        [ 'first', 1000 ]
    ];
    if (cursor) {
        params.push([ 'after', cursor ]);
    }

    let url = new URL('https://api.twitch.tv/helix/chat/chatters');
    url.search = new URLSearchParams(params);

    let chattersReq = await fetch(
        url,
        {
            method: 'GET',
            headers: {
                'Client-ID': process.env.TWITCH_CLIENT_ID,
                'Authorization': `Bearer ${process.env.access_token}`,
                'Accept': 'application/json',
                'Accept-Encoding': 'gzip,deflate'
            }
        }
    );
    if (chattersReq.status != 200) {
        console.log('Failed to get chatters', await chattersReq.text());
        return;
    }
    let chattersData = await chattersReq.json();
    //console.log(chattersData);
    let { data, pagination, total } = chattersData;

This is a variation on my example at

(Which was created before userID’s were in Get Chatters so demonstrates how to take 1k into 10 pages and call get users with but I digress)

Since the Twitch API is behind a CDN, it is not unheard of for that CDN to have some regional issues and throw back weird/unexpected error codes, or your Provider is having an issue with connectivity to AWS.

So we need to see what the body message of the error response to see what that is saying.

Ich hab den ganzen Ablauf mal in Python gebastelt. Der funtkioniert auch soweit. Bis es darum geht, die Userliste zu bekommen.

import requests
import json

# Auth-Secret-Stuff. (In diesem Forum zensiert, aber trotzdem erkennbar)
secrets = {
    "client_id":             "g12************************so0",
    "client_secret":         "cpr************************8up",
    "moderator_oauth": "oauth:hco************************3h2",
    "moderator_id":          698000000, # Letzten 6 ziffern genullt ;D
}

# moderator_id ist der user, dem auch client_id und client_secret in der dev-console gehört.
# oauth-token ist gültig und korrekt

def convert_get_data_to_string(get_data):
    params = []
    for key, value in get_data.items():
        if isinstance(value, list):
            for item in value:
                params.append(f"{key}[]={item}")
        else:
            params.append(f"{key}={value}")
    return '?' + '&'.join(params)

def get_user_data(target_broadcaster):
    # Get Data for getting a access token
    get_data_1 = {
        "client_id": secrets["client_id"],
        "client_secret": secrets["client_secret"],
        "grant_type": "client_credentials",
        "scope": ["moderator:read:chatters",]
    }

    # Post-Data for getting a access token
    post_data_1 = {
        "oauth": "bearer " + secrets["moderator_oauth"]
    }

    # Target Url build up with get data for oauth2/token
    target_url = "https://id.twitch.tv/oauth2/token" + convert_get_data_to_string(get_data_1)

    # Call the api
    auth_credentials = requests.post(target_url, data=post_data_1)
    auth_credentials = auth_credentials.json()

    # For Debug purposes
    print(auth_credentials["access_token"])

    # Header for User-List-Request
    headers = {
        "Client-Id": get_data_1["client_id"],
        "Authorization": "Bearer " + auth_credentials["access_token"]
    }

    # Get Data for User-List-Request
    get_data_2 = {
        "broadcaster_id": target_broadcaster,
        "moderator_id": secrets["moderator_id"],
        "first": "1000"
    }

    # Target Url build upo with get data for chat/chatters
    target_url = "https://api.twitch.tv/helix/chat/chatters" + convert_get_data_to_string(get_data_2)

    # Call the API
    response = requests.get(target_url, headers=headers)

    # Return the result
    return response.json()


# Call get_user_data for specific channel (it works with capital letters)
response_data = get_user_data("Mindconstructor")

# Output the result
print("Server-Response:", response_data)

Führe ich das (mit korrekten secret-daten natürlich) aus, erhalte ich

Server-Response: {'error': 'Unauthorized', 'status': 401, 'message': 'Missing User OAUTH Token'}

WO soll da der oauth-token hin? Ich habs im GET und im Header probiert. Versuch ich mit POST den request für die User-Liste zu machen, erhalte ich

Server-Response: {'error': 'Not Found', 'status': 404, 'message': ''}

Bitte, wo liegt mein Fehler? (Ja. Ich schreib das grad in Python, weils so einfacher war, mal fix Requests zu testen. Mein NodeJS-Script werde ich dann auf Basis dieser Infos anpassen. Und ja, ich weiß, dass ich auch oauth2/validate nutzen müsste und so … soweit ich das in den docs verstanden hab)

Es muss doch möglich sein, diese user-liste zu bekommen. die GANZE ZEIT hats funktioniert. Ohne zu zucken … Und plötzlich, von heute auf morgen, gehts nicht mehr … <_<

You used the wrong token type.

Client Credentials token is not valid for this endpoint

The token should not be preceeded with oauth:

Tokens are only preceeded with oauth: to login to chat with.

For API usage it’s just

Authorization: Bearer tokenhere

Not

Authorization: Bearer oauth:tokenhere

You cannot POST to this endpoint hence a 404.

You can only GET chatters you cannot POST chatters. (Post implies create and you can’t create chatters)

You have a User token (with a oauth: prefix)
You overwrite that token with a client_credentials token, which is not valid for Getting cahtters with

So … its not longer possible to get the user list from client side only? i HAVE MANUALLY get a token?

crap <_<

You mean server side? Sure it is you just need to get a refreshable user token into your script.

manually create a user token/refresh token set.

Use the user token till it expires
When the user token expires use the refresh token to get a new user token

So Auth code flow: Getting OAuth Access Tokens | Twitch Developers
And refresh flow: Refreshing Access Tokens | Twitch Developers

I use a variation of https://github.com/BarryCarlyon/twitch_misc/tree/main/authentication/user_access_without_server to get a token/refresh token into my server.

And then the server runs with the access/refresh token and will get a new user token when it expires

So in summary

Once only once.

Unless the refresh token dies.

Okay … i have this stuff … including the refresh token … but now … i get the error:

Server-Response: {‘error’: ‘Forbidden’, ‘status’: 403, ‘message’: ‘user 698394232 does not have moderator permissions for channel mindconstructor’}

So my token seems to work … i made everything with the bot account wich i want to use for the user-list …

But … wait a second. Oo

{
  'data': [{
    'id': '698394232',
    'login': 'intelli_bot',
    'display_name': 'Intelli_Bot',
    'type': '',
    'broadcaster_type': '',
    'description': '(cropped)',
    'profile_image_url': '(cropped)',
    'offline_image_url': '',
    'view_count': 0,
    'created_at': '2021-06-16T12:58:30Z'
  }]
}


You can see, this bot writes as moderator in this chat already. it HAS moderator status

it HAS mod permisisons … (happens with capital letters too btw.)

<_<

Here’s my test-flow atm (refreshing and validating is the next step. but first i need the damn user list and i don’t know, why this not works … <_<)

import requests
import json

# Auth-Secret-Stuff.
secrets = {
    "client_id":             "g12************************so0",
    "client_secret":         "cpr************************8up",
    "client_access_token":   "nza************************s7i",
    "client_refresh_token":  "ego********************************************k70",
    "moderator_oauth": "oauth:0q6************************ivo",
    "moderator_id": 698394232,
}

def convert_get_data_to_string(get_data):
    params = []
    for key, value in get_data.items():
        if isinstance(value, list):
            for item in value:
                params.append(f"{key}[]={item}")
        else:
            params.append(f"{key}={value}")
    return '?' + '&'.join(params)

def get_user_data(target_broadcaster):
    # Get Data for User-List-Request
    get_data = {
        "broadcaster_id": target_broadcaster, # mindconstructor ... target channel
        "moderator_id": secrets["moderator_id"], # intelli_bot, wich is definitively moderator on the channel mindconstructor
        "first": "1000"
    }

    # Header for User-List-Request
    headers = {
        "Client-Id": secrets["client_id"],
        "Authorization": "Bearer " + secrets["client_access_token"]
    }

    # Target Url build upo with get data for chat/chatters
    target_url = "https://api.twitch.tv/helix/chat/chatters" + convert_get_data_to_string(get_data)

    # Call the API
    response = requests.get(target_url, headers=headers)

    # Return the result
    return response.json()


# Call get_user_data for specific channel (it works with capital letters)
response_data = get_user_data("mindconstructor")

# Output the result
print("Server-Response:", response_data)

Maybe i have messed around with the scopes?
i requested only the “moderator:read:chatters” scope …

You did call the Get Chatters API using a broadcaster_id of 158219238 and you didn’t pass in a broadcaster_id of mindconstructor

The API might not check what you passed in was numeric.

So 698394232 is not a moderator for channel ID mindconstructor since mindconstructor isn’t an ID

the call to the get chatters api accepts the text name of the broadcaster id before the whole time. without any issue. (the user-list was used SINCE A YEAR already this way!)

so … now i have to grab the user id of the target channel too? <_< this is b*llshit now … why twitch makes this more and more complicated?

btw: this worked before without a issue just with the display-name of the target channel! really!

getting a user id from a channel name is way the most complicated stuff trough api … <_<

That is the old API that was on tmi.twitch that old API is removed.

Helix uses numeric ID’s everywhere

Call get users, it’s not complicated I got it very quickly

CLI example

image

ID’s never change.

So if userID 123 called fred chooses to change their username
They’ll become 123 called bob

The userID is static but the “label” on the account (the username) can and will change.

damn … so now i have to rebuild my WHOLE BOT, because of this …

sigh

okay. thank you. Btw. i finally got my required response. Thank you twitch for not giving a single clue about THIS problem …

so now i’ll work on the /validate and reauthenticate stuff …

and when i solved THIS, i have to place this inside my bot code in javascript. and rewrite the database too <_<

You are also aware that all the chat commands (/ban /timeout) are API calls now? (Since februrary)

Which requires the numeric channel_id (and numeric moderator ID and the numeric id of the user in question which you can pull from the chat tags)

Every time my bot restarts the first thing it does is channelID to login so it can check it’s joining the right channel, in case some of my clients are susprirsed changed names on me

You are not already doing this for the token the bot uses to login to chat with?

The Dev Forums and Dev Discord are the locations for assistance with Third Party development, so Twitch Support, if thats whom you reached out to will have sent you here.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.