Server2Server OAuth returning {'code': 200, 'message': 'Account does not enabled REST API.'}

Hello all.
I’m trying to move from JWT to OAuth, and despite having set-up everything correctly as far as I can tell, I’m getting a reply that the “Account does not enabled REST API”.
Disregarding the incorrect grammar of this message, I’m not sure why I would be getting this message to begin with!
I’ve tried various versions of code, but they all lead to this error and message.
Here’s one example of my python code that causes this issue:

oauth_url = f'https://zoom.us/oauth/token?grant_type=account_credentials&account_id={ACCOUNT_NUMBER}'  # ACCOUNT_NUMBER obtained  by looking under "account number" on the account profile page

auth_header = f'Basic {base64.b64encode(f"{CLIENT_ID}:{CLIENT_SECRET}".encode()).decode()}'
headers = {'Authorization': auth_header}
response = requests.post(oauth_url, headers=headers)

Here’s another code snippet I’ve tried with the same result:

def make_authorization_url():
    params = {"client_id": CLIENT_ID,
              "response_type": "code",
              "redirect_uri": REDIRECT_URI}
    url = "https://zoom.us/oauth/authorize?" + urllib.parse.urlencode(params)
    return url

auth_url = make_authorization_url()
response = requests.post(auth_url)

The thing is, I’ve tried logging the auth_url, and when copying the url from the log-file and pasting into a browser, I get back a valid token! So what gives??

I’ve already checked the settings on my zoom account, and it looks like all the right boxes are checked (for owner at least):

Please assist if you can, and feel free ask anything which can help clarify the situation.
Thanks!

Hello!
I have exactly the same problem.
moving from JWT to Server-to-Server OAuth in this case, and using PHP (Curl)
I have a valid Authtoken but when i ask to the API i get
{“code”:200,“message”:“Account does not enabled REST API.”}

The Scopes on the app are ok, and the permissions on the roles ( i use the main account) it´s ok
Please can we have some answers for this?
Thanks

Hi @shlomi.fenster @ecodes please see the following:

Hi @gianni.zoom!
Of course I saw this before posting this issue. But unless I’m missing something obvious, I’ve done exactly as that post shows.
Do you see anything flawed in the way I’ve done things in the code snippets I included?
Did you read the details of my post (e.g., copy-pasting the url into a browser returns a token as expected).
Please assist with attention to the specific problem I’m having.
What am I doing wrong? What am I doing differently to the post you linked?

Thanks!!

Hello i find the solution with PHP and curl, and Server-to-Server OAuth:

I published the code on github

$accountID = 'xxxxxxxxxxxx';
$clientId = 'xxxxxxxxxxxxx';
$clientSecret = 'xxxxxxxxxxxxxxx';

$authHeader = base64_encode($clientId . ':' . $clientSecret);
$url = 'https://zoom.us/oauth/token';

$data = [
    'grant_type' => 'account_credentials',
    'account_id' => $accountID,
];

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Host: zoom.us',
    'Authorization: Basic ' . $authHeader,
]);

$response = curl_exec($ch);

if ($response === false) {
    echo 'Error CURL: ' . curl_error($ch);
} else {
    $responseData = json_decode($response, true);
	$access_token = $responseData['access_token'];
}

curl_close($ch);

if($access_token) {
	$apiCurl = curl_init('https://api.zoom.us/v2/users/me/webinars');
	curl_setopt($apiCurl, CURLOPT_HTTPGET, true);
	curl_setopt($apiCurl, CURLOPT_RETURNTRANSFER, true);
	curl_setopt($apiCurl, CURLOPT_HTTPHEADER, array(
	'Authorization: Bearer ' . $access_token,
	));
	$apiResponse = curl_exec($apiCurl);

	if ($apiResponse === false) echo 'Error: ' . curl_error($apiCurl);
	else echo $apiResponse;
	curl_close($apiCurl);	
}

Now this is working for me thanks!

That’s nice for you @ecodes. However, I’m using python, and as the creator of this post I’d be very pleased to get some help with getting my python code to work, as moving to php/curl/etc. isn’t an option for me.

Hello Shlomi.

Looking at the code snippets you posted I think they are attempting to do two different things. The first example is attempting to use server to server oath to get an access token directly, a process which doesn’t require user input, while the second code snippet is attempting to get an authorization code, which can then be exchanged for an access token, and does require user input.

Do you know which of these frameworks you are trying to use / which app you built on the marketplace? For reference, looking at this page Create a Server-to-Server OAuth app, you can see the two different app types. Do you remember/know which one you made?

Additionally, when you say you post the url into a browser, can you specify which one that was? If it was the 2nd one, labelled auth_url, what you got back was not an access token, but an authorization code. There is a 2nd call that must be made to exchange the code for the actual access token.

I’ll be happy to follow up with additional details and python examples, if you can provide some of these clarifications.

1 Like

@joshua.allen thank you for helping! These are valid questions.

@shlomi.fenster , Joshua is right. The second code snippet looks like something you would use for a OAuth 2.0 external app. Server-to-Server is internal.

Here’s our Postman workspace which lays out the set up for retrieving a valid access token for Server-to-Server: Postman

You can use the Code Snippet feature for sample code:

Once you have a valid access token, you can use on the subsequent API endpoints that you have scoped permission to access.

Thanks for the clarifications! I’m still not 100% sure which I need.
Considering my actual point is to try and get a list of meeting recordings from my account, I geuss I need the server-to-server option for getting a token.
Assuming that I indeed need the server-to-server option, (but if I’m wrong about that please correct me!), I went ahead and put in all the relevant details in the postman example you linked, but I’m still getting an error, albeit a different one:

"error": "unsupported_grant_type"

I feel like we’re making progress, but I still can’t get my code to run and my app is still down because of that…

Thanks for the assistance!
Hoping we get this working soon…

Hi @shlomi.fenster ,

You can use either Server-to-Server or OAuth 2.0 application to query Zoom Meeting API.

Server-to-Server apps are for internal account usage. These do not get published.

OAuth 2.0 apps have the ability to be published and used by external account users (upon publishing approval).

Here are more details about the differences: When to use Server-to-Server OAuth app and when to use OAuth app ? - DEV Community

After reviewing, which do you need?

If you’re getting unsupported grant type error, please ensure you have account_credentials written for the grant_type field in your query parameters for Server-to-Server access token endpoint. For the account_id value field, literally put your account id there in place of [account_id] :slight_smile:

You should get a valid S2S access token to use with the Get Meeting Recordings endpoint.

I need the server to server option.
I tried the postman with all the correct parameters as far as I can tell, obviously replacing things like the account id.
That’s when I get the error I described in my last post.

בתאריך יום ג׳, 26 בספט׳ 2023, 15:35, מאת Gianni via Zoom Developer Forum ‏<notifications@zoomdeveloper.discoursemail.com>:

@shlomi.fenster , I cannot reproduce, can you please confirm “body” is set to “none”? If that is already the case, please share screenshots of each part of the Postman Gui and your error in the private message I’ll create.

Hi @gianni.zoom!
Yes, it’s set to none. Where do I find the private message so that I may send you screenshots of the various fields in postman?
Thanks again!!!

Hi @shlomi.fenster , check your notifications. You should see a message from me. Click on user profile → click the “envelope” icon. Your messages are there.

Developer needed to paste account id in query parameters for access code request.

So, it turns out I was using the wrong “app”. After defining a server-to-server oauth app, and using those credetials and details, (and setting up the postman headers and variables correctly) it’s finally working!
Thank you very very much to @gianni.zoom for all the help! She’s been messaging with me back and forth for a while and being very patient and helpful!
Hope this helps others as well…

@gianni.zoom - If you want to elaborate I can mark your message as the solution, seeing as you’re the one who found my mistakes and helped me get it running…

1 Like

Appreciate your kind message! I’m glad everything is working as expected.