Platform API for Partners
Last updated April 01, 2024
Table of Contents
Add-on Partners can access a subset of the Heroku Platform API via OAuth. This subset is called the Platform API for Partners. The Platform API for Partners provides the same functionality of the Legacy App Info API, along with the following significant advantages:
- The Platform API for Partners provides many official endpoints that the App Info API doesn’t support. These endpoints let you introspect security settings, discover other customer instances of the same add-on, and much more.
- Platform API for Partners endpoints are more consistent and “better traveled.” Heroku uses these endpoints internally, and customers also use them directly.
As of September 2022, you can get a full list of apps where your add-on is installed using the addons.heroku.com API V3 /apps
endpoint. Review the Apps
section of this documentation for more details.
See List of standard Platform API endpoints for a complete list of endpoints available to add-ons.
When an add-on is provisioned, it acts as an authorization step for the add-on partner to access relevant records about the add-on resource and its associations via the Platform API.
The tokens created as part of provisioning can then be used to authenticate requests to a number of Platform API endpoints. Our Platform API has a well-documented schema and already serves all of our customer-facing tooling.
Of the new concepts introduced, your add-on will now have an OAuth client secret and a number of OAuth authorizations, one token per provisioned add-on. The OAuth client secret is only used to authenticate requests to create the scoped tokens; it is not used to authenticate other requests to the Platform API.
Tutorial
All new add-ons have access to the Platform API by default. The Platform API is standard for all add-ons using the v3 API as well. If your add-on was created before May 15, 2017, your add-on will need a flag set on our end. Please open a new support ticket to enable the flag.
This tutorial assumes that you already have an add-on implemented for the existing Partner API integration. To get up to that point quickly, you can follow the Building an Add-on tutorial and refer to our add-on reference implementation.
As a prerequisite, your add-on should already implement the Add-on Partner API calls for provision
, planchange
, and deprovision
.
When the flag is enabled on your v1 add-on (or if you’re on v3), provision requests will contain a grant code that you can exchange for an access token scoped to that add-on resource. The process is described below.
Retrieving your Client Secret
You will need your client_secret
for most OAuth interactions with Heroku. You can find your Add-on’s client_secret
in the Add-on Partner Portal on the “OAuth Credentials” page.
Getting a token for a new add-on installation
Receiving the Grant code
When a provision request is POSTed to your add-on, it will contain an OAuth Grant (some fields are omitted):
{
"options": {},
"oauth_grant": {
"code": "01234567-89ab-cdef-0123-456789abcdef",
"type": "authorization_code",
"expires_at": "2016-03-03T18:01:31-0800"
},
"plan": "basic",
"region": "amazon-web-services::us-east-1",
"uuid": "01234567-89ab-cdef-0123-456789abcdef"
}
Make sure to reply to the provisioning request with a successful response code. If your service requires a longer than usual amount of time to provision, take a look at our documentation on Asynchronous Provisioning.
The provided grant code can be exchanged within 5 minutes for an Access Token and a Refresh Token using Heroku’s authentication service, id.heroku.com
.
Exchanging the Grant code
It’s time to exchange the grant code after you’ve responded to the initial provisioning request with a successful response code.
A grant code won’t be valid if you don’t respond with success to the initial provisioning request. If you respond with something other than success, we assume the provisioning request has permanently failed and invalidate the grant code.
To exchange the grant code, you will POST to https://id.heroku.com/oauth/token
including the grant code and your client secret as Content-Type: application/x-www-form-urlencoded
. For example, here’s how you might make the request with curl
.
$ curl -X POST https://id.heroku.com/oauth/token \
-d "grant_type=authorization_code&code=01234567-89ab-cdef-0123-456789abcdef&client_secret=01234567-89ab-cdef-0123-456789abcdef"
This returns a payload containing the desired tokens (some fields elided):
{
"access_token": "HRKU-4594b794-0c94-416b-a374-bb33a025411f",
"refresh_token": "95a242fe-4c4a-4059-bc06-512de9672619",
"expires_in": 2592000,
"token_type": "Bearer"
}
Save the Access Token and Refresh Token on your side.
Please be sure to encrypt the access_token
and refresh_token
values, as well as your client_secret
, when writing them to persistent storage. These secrets should not be plaintext at rest, and their decryption keys should not be easily discoverable. If you are using Sequel in Ruby, consider evaluating the attr_vault gem.
All calls that you make to the Platform API should use the access token for that add-on as authentication. Note that the token can only be used to request data about the add-on resource it was created for – you will need to use each add-on resource’s access token to get access to its data in the Platform API. All responses will be scoped to the add-on resource that the access token was created for.
Getting a token for an existing add-on installation
If you have been a Heroku Add-on Partner since before the Platform API for Partners was available, you will have a number of existing add-on installations for which you never received an OAuth Grant.
To allow you to backfill the Access Token and Refresh Token for these installations, we have an endpoint available where you can retrieve the OAuth Grant. For security reasons, this endpoint is blocked by default and must manually be opened to each Add-on Partner. Please open a new support ticket to let us know that you are interested in using this endpoint.
As noted above, always encrypt the access_token
, refresh_token
and client_secret
values when writing them to persistent storage.
We also encourage you to test out the OAuth flow for new installations on a test add-on before pursuing a backfill of Access Tokens and Refresh Tokens. Testing with the flow for new installations will allow you to build out the functionality to exchange an OAuth Grant for the tokens.
Once you receive confirmation from us that the endpoint is open, you can begin to retrieve OAuth Grants. The endpoint is in the App Info API, so you will need to retrieve your username and password for that API.
GET https://<username>:<password>@api.heroku.com/vendor/resources/:resource_uuid/oauth-grant
Content-Type: application/json
{
"oauth_grant": {
"code": "01234567-89ab-cdef-0123-456789abcdef",
"type": "authorization_code",
"expires_at": "2016-03-03T18:01:31-0800"
}
}
If you previously had an OAuth Grant code issued, and this code has yet to expire, this endpoint will return the existing OAuth Grant idempotently. If the code has already expired, the endpoint will generate a new one for you. If you have previously exchanged any Grant code for an Access Token & Refresh Token, this endpoint will error. If you have lost the Refresh Token provided by this exchange, please contact us.
The OAuth Grant code in the response will expire within 5 minutes. You must follow the flow outlined above to exchange the Grant code for the Access Token and Refresh Token.
Accessing the API using the Access Token
To access the API using the Access Token, use it like any other OAuth token on our Platform API, passing it to the API in the Authorization
header. For example, to get details about the add-on:
GET /addons/01234567-89ab-cdef-0123-456789abcdef
Host: api.heroku.com:443
Content-Type: application/json
Accept: application/vnd.heroku+json; version=3
Authorization: Bearer 4594b794-0c94-416b-a374-bb33a025411f
Refreshing the Token
The Access Token is valid for up to 8 hours but may expire early in certain circumstances, such as a credential rotation. The Refresh Token is valid for the lifetime of the add-on and can be exchanged for a new Access Token as many times as needed using a valid OAuth client secret.
The retrieve a new Access Token, you use the same endpoint in the Heroku authentication service (id.heroku.com) once again. This time, your grant_type will be “refresh_token” which you will also pass along:
$ curl -X POST https://id.heroku.com/oauth/token \
-d "grant_type=refresh_token&refresh_token=95a242fe-4c4a-4059-bc06-512de9672619&client_secret=f6a36ee4-3736-455e-9787-bb91ca679706"
That returns a payload containing the new access token (some fields elided):
{
"access_token": "HRKU-2af695e0-93e3-4821-ac2e-95f68435f128",
"refresh_token": "95a242fe-4c4a-4059-bc06-512de9672619",
"expires_in": 2592000,
"token_type": "Bearer"
}
As noted above, always encrypt the access_token
, refresh_token
and client_secret
values when writing them to persistent storage.
Using the Platform API to set config vars
The new integration includes the ability to update config vars through the Platform API rather than through the existing Add-on Partner App Info API. To accomplish this, you would start with the add-on resource UUID from the provision request and the access token for that add-on resource.
You can view existing config for this add-on resource with the GET form of the endpoint:
GET /addons/01234567-89ab-cdef-0123-456789abcdef/config
Host: api.heroku.com:443
Content-Type: application/json
Accept: application/vnd.heroku+json; version=3
Authorization: Bearer 2af695e0-93e3-4821-ac2e-95f68435f128
And you can update it by the use of the PATCH form:
PATCH /addons/01234567-89ab-cdef-0123-456789abcdef/config
Host: api.heroku.com:443
Content-Type: application/json
Accept: application/vnd.heroku+json; version=3
Authorization: Bearer 2af695e0-93e3-4821-ac2e-95f68435f128
{
"config": [
{
"name": "MY_ADDON",
"value": "bar"
}
]
}
See the Platform API Add-on Config Update documentation for further details.
Accessing app details through the Platform API
You can request information about apps attached to your add-on resource in the Platform API. The endpoints which return an app usually take either the app’s UUID or the app’s name. To get your attached apps, you will first have to request /addons/:resource_uuid
or /addons/:resource_uuid/addon-attachments
. The former will give you the primary app in the app
object, and the latter will give you all attached apps through a list of attachments.
In using the app information, prefer the UUID for requests to the Platform API, and display the app name to the user. The app name is also suitable for making requests.
For example, if we request the /addons/:resource_uuid
endpoint for an add-on resource we own, and get back (some fields elided):
json
{
"app": {
"id": "01234567-89ab-cdef-0123-456789abcdef",
"name": "example"
},
...
}
Then we can see that the app that the add-on resource was created on has ID 01234567-89ab-cdef-0123-456789abcdef
. We can use this UUID to request information about the app from other endpoints. For example, we can use this app UUID with the app domains or app collaborators endpoints.
Log drains
If your add-on has access to the ability to configure log drains for an app, it will have access to the log drains endpoints in the Platform API. These endpoints all take the add-on resource UUID as an identifier. Please see the Log drain endpoints documentation for further details.
List of standard Platform API endpoints
These endpoints are accessible by all add-ons that integrate with the Platform API:
Add-ons will only see instances of the same add-on service from these endpoints. Add-ons will only see instances of apps to which they are attached from these endpoints.
Add-on resources
- GET /addons/{add_on_id_or_name}
- GET /addons
- GET /users/{account_email_or_id_or_self}/addons
- GET /apps/{app_id_or_name}/addons
Add-on attachments
- GET /addons/{add_on_id_or_name}/addon-attachments
- GET /apps/{app_id_or_name}/addon-attachments
- GET /apps/{app_id_or_name}/addon-attachments/{add_on_attachment_id_or_name}
Add-on config
App Info
- GET /apps/{app_id_or_name}
- GET /apps
- GET /users/{account_email_or_id_or_self}/apps
- POST /filters/apps
App Collaborators
Domains
Log drains
- GET /addons/{add_on_id_or_name}/log-drains
- PUT /addons/{add_on_id_or_name}/log-drains/{log_drain_id_or_url_or_token}
- POST /apps/{app_id_or_name}/log-drains
- DELETE /apps/{app_id_or_name}/log-drains/{log_drain_id_or_url_or_token}
- GET /apps/{app_id_or_name}/log-drains/{log_drain_id_or_url_or_token}
- GET /apps/{app_id_or_name}/log-drains
Pipelines
- GET /pipelines/{pipeline_id_or_name}
- GET /pipelines
- GET /pipelines/{pipeline_id}/pipeline-couplings
- GET /pipeline-couplings
- GET /pipeline-couplings/{pipeline_coupling_id}
- GET /apps/{app_id_or_name}/pipeline-couplings
Team members
And More
We can enable other endpoints on a per-partner basis, if the use case warrants it. For example, you might want to look at the app’s formations, releases, or builds. Reach out to us and let us know what you are trying to accomplish!
Best practices
Fetch data just-in-time, if possible, and only store the add-on resource UUID, your own ID, and the combination of access token and refresh token for the add-on. Many fields on Heroku can change, including the owner’s email address and the app name, so we recommend fetching it before it is needed.
Use only UUIDs as identifiers for Heroku add-on resources and Heroku apps. All previous identifiers (such as the confusing “app123@heroku.com” identifiers) should not be used with the Platform API.
FAQ
What happens if Heroku API is down as my Access Token is about to expire?
The Refresh Token given to Add-on Partners is long-lived. It can be used even if the Access Token expires. When the Heroku API becomes available again, exchange your Refresh Token for a new Access Token.
What do I do if an Access Token has been exposed?
If the OAuth client secret has not been exposed and your connection to the Heroku API is not compromised, use the Refresh Token to get a new Access Token, which will expire the old one.
If the OAuth client secret has been compromised, see next question.
If the OAuth refresh token has been compromised, open a support ticket.
What do I do if my Oauth client secret has been exposed?
Perform a Credential Rotation immediately.
How do I perform a Credential Rotation?
Log into the Add-on Partner Portal with your Heroku Account, click on OAuth Credentials, then press the Reset
button.
A new OAuth client secret will be temporarily displayed on your screen. All existing Access Tokens will become immediately invalid and must be refreshed using the new OAuth client secret.
It is imperative that you enable Two-Factor Authentication on the Heroku accounts of all Add-on admins so that an attacker can not reset your credentials and retrieve new ones.
How do I know which API endpoints I have access to?
At this time, there is no dynamic way to show this. Endpoints for which your add-on has insufficient access will return an authorization error.
All add-ons will have access to a shared base set of endpoints which may be expanded over time. If your add-on has specific needs, you will be able to work with our partner team and engineers to grant your add-on extended privileges and wider API access on a case-by-case basis.
How does rate limiting work when using the Platform API?
Each resource gets its own rate limit when accessed with a resource-scoped token. This way, many calls against one resource do not impact the ability to make API calls for other resources owned by your add-on. Use the RateLimit-Remaining
response header on any response to check the current token count. The rate limit counts and documentation for the Platform API apply.