Am I missing a step, or perhaps using the wrong credentials for this grant type? My understanding was that client_credentials is the correct flow for server-to-server API access for these developer scopes.
Hi @miguelncg , good question, this part of the docs is easy to misread.
HubSpot’s public app OAuth flow today only supports authorization_code (and then refresh_token) for getting access tokens. The /oauth/v1/token endpoint simply does not accept client_credentials as a valid grant_type, which is why you’re getting BAD_GRANT_TYPE even though the payload looks correct.
Private apps won’t help here, as you already spotted, because those specific scopes are only available to public apps. The clean pattern is usually: public app with the Webhooks v4 developer scopes, one install into a “control” portal, store the refresh token securely, and build a small server-side job that rotates access tokens using grant_type=refresh_token only.
That keeps it server-to-server in practice, even if the underlying OAuth flow is not pure client_credentials on the wire. If you later need to mirror those webhook events into another system reliably, Stacksync can consume HubSpot changes and keep your downstream database or CRM in step without you having to juggle custom token logic and sync code._
Did my answer help? Please mark it as a solution to help others find it too.
Ruben Burdin HubSpot Advisor Founder @ Stacksync Real-Time Data Sync between any CRM and Database
Hi @miguelncg , good question, this part of the docs is easy to misread.
HubSpot’s public app OAuth flow today only supports authorization_code (and then refresh_token) for getting access tokens. The /oauth/v1/token endpoint simply does not accept client_credentials as a valid grant_type, which is why you’re getting BAD_GRANT_TYPE even though the payload looks correct.
Private apps won’t help here, as you already spotted, because those specific scopes are only available to public apps. The clean pattern is usually: public app with the Webhooks v4 developer scopes, one install into a “control” portal, store the refresh token securely, and build a small server-side job that rotates access tokens using grant_type=refresh_token only.
That keeps it server-to-server in practice, even if the underlying OAuth flow is not pure client_credentials on the wire. If you later need to mirror those webhook events into another system reliably, Stacksync can consume HubSpot changes and keep your downstream database or CRM in step without you having to juggle custom token logic and sync code._
Did my answer help? Please mark it as a solution to help others find it too.
Ruben Burdin HubSpot Advisor Founder @ Stacksync Real-Time Data Sync between any CRM and Database
Hey, I think you are trying to hit an API endpoint. If so, then the approach you should use is to create a private app in instance, provide all the required scopes as per the need, and then use its access token to hit the API. There is no need to create the public app.
I hope this will help you out. Please mark it as Solution Accepted and upvote to help another Community member.
Unfortunately, I don't believe the private app approach will work for this use case. The scopes I am trying to access (like developer.webhooks_journal.read and developer.webhooks_journal.subscriptions.write) are for the Webhooks V4 API.
According to HubSpot's documentation, these scopes are only available for public apps and cannot be added to private apps.
I'd like to tag in some of our Top Contributors to see if they have any ideas on this one -- Hi @HubSpot_Corey@louischausse and @Teun Do any of you have any suggestions for @miguelncg?
Thank you!
Cassie, Community Manager
Loop Marketing is a new four-stage approach that combines AI efficiency and human authenticity to drive growth.