Integrations can be authorized for a single workspace or use OAuth to access multiple workspaces. Learn about implementing the right authorization for your integration.


The Notion API uses bearer tokens to authorize requests from integrations. As an integration developer, you'll need to choose the appropriate integration type for the integration you create. Based on the integration type, you'll receive and store bearer tokens differently. For both types, an integration must send the bearer token in the HTTP Authorization request header, as shown:

GET /v1/pages/b55c9c91-384d-452b-81db-d1ef79372b75 HTTP/1.1
Authorization: Bearer {MY_NOTION_TOKEN}

Integrations are granted access to resources (pages and databases) which users have shared with the integration. Once an integration has been added to a workspace, the user who added the integration can see it within Share menus inside Notion.


Integrations have broad access to resources

When a user grants an integration access to a page or databases, the integration can read and write to that resource and its children. In the future, integrations may be allowed to request specific kinds of access (such as read-only) to give users more clarity and control.

Integration types

There are two types of integrations:

  1. Internal integrations are used to integrate the tools and services in use by you and your team in a way that's tailored to your people, workflows, and resources.
  2. Public OAuth integrations are used to build a product that is used by a broad audience, across many Notion workspaces.

By default, newly created integrations are internal integrations. After creation, the type can be changed to public integration in the integration settings.

Internal integrations are much simpler to develop. Public integrations require additional configuration and implement the client side of OAuth 2.0. Read on for details on how to implement authorization for each integration type.

Integration Capabilities

Both internal and public integrations have associated capabilities which enforce what an integration can do and see in a Notion workspace. These capabilities when put together enforce which API endpoints an integration can call, and what content and user related information they are able to see.

Content Capabilities

Content capabilities affect how an integration can interact with database objects, page objects, and block objects via the API. Additionally, these capabilities affect what information is exposed to an integration in API responses. To verify which capabilities are needed for an endpoint's desired behavior, please use the API reference. It is possible to have any combination of these content capabilities.

  • Read content - this capability gives the integration access to read existing content in a Notion workspace.
  • Insert content - this capability gives the integration permission to create new content in a Notion workspace. This capability does not give the integration access to read full objects.
  • Update content - this capability gives the integration permission to update content in a Notion workspace. This capability does not give the integration access to read full objects.

Additionally, an integration can different levels of user capabilities, which affect how user objects are returned from the Notion API:

  • No user information - the integration will not be able to request any information about users. User objects will not include information about the user, including name, profile images, or their email address.
  • User information without email addresses - user objects will include other information about the user, including their name or profile images, but omit the email address.
  • User information with email addresses - user objects will include all information about the user, including name, profile images, and their email address.


Any integrations created before December 15, 2021 automatically will have all content capabilities, and user capabilities that give access to user information including email addresses.

For further information on capabilities and best practices, see the capabilities reference.

Authorizing internal integrations

Internal integrations simply use a single integration token as the bearer token for all requests. In order to create an internal integration, you must choose an associated workspace. You must have Admin access level within the workspace you choose.


Not an admin in your current workspace?

You can start building right now by creating a new personal workspace. Later, you can ask an admin to help you move the integration into another workspace. This may require using a different token, which is easy to do if you keep the token outside of source code using environment variables.

You can view the integration token later in the integration settings. This token is a secret. You should avoid storing it in your source code and avoid committing it in version control. Instead, we recommend reading the the token from an environment variable in your source code, and using a secret manager or deployment system to set the the token in the environment.

In each API request, send the token in the Authorization header as shown:

GET /v1/pages/b55c9c91-384d-452b-81db-d1ef79372b75 HTTP/1.1
Authorization: Bearer {MY_NOTION_TOKEN}

Authorizing public integrations

Public OAuth integrations receive an access token each time a user grants the integration access. The access token which is granted is associated with the user account that installed your integration. This process follows OAuth 2.0 using an authorization code grant, described in a few simple steps below.

The integration stores all the access tokens it receives (typically in a database) and chooses one as the bearer token for each request the integration sends to the Notion API.

Once a user has installed your integration, only that user will be able to interact with your integration in Notion. The installing user will be able to share additional pages and databases with your integration using the Share menu in Notion. Any additional user that wants to use your integration will need to go through the authorization process for themselves.

Prompting users to add an integration

The first step in the OAuth process is to request authorization from a user. This is done by sending a user to the authorization URL. You may send the user to this URL with a simple hyperlink or a redirect from another request.

The authorization URL is created using a few parameters. The URL begins with and the parameters are added in the query string.

client_idAn identifier for your integration, found in the integration settings
redirect_uriA URL where the user should return after granting access. This is described in detail below.
response_typeAlways use code
ownerAlways use user
stateIf the user was in the middle of an interaction or operation, this parameter can be used to restore state after the user returns. It is also can be used to prevent CSRF attacks.

As an example, the following hyperlink can be used to request authorization from a user:

<a href="">Add to Notion</a>



If a user who has already added the integration visits your authorization URL again and chooses the same workspace, that user may reauthorize the integration and add or remove the integration from pages in the workspace. The access token received after exchanging the grant will be the same as the initial access token received.

User grants access

Once a user is sent to the authorization URL, they see a prompt which discloses the capabilities of the integration and choose whether to grant the integration access or not.

Integration authorizationIntegration authorization

Integration authorization

If the user grants access, they are shown a page picker where they can search for and select pages and databases to share with your integration. Just like in the Notion app, users need Full Access permission to a page in order to share it with an integration, so the page picker will only show pages and databases for which the user has Full Access permission.

If the user allows access, they are redirected to the redirect_uri with a temporary authorization code (code).

Page pickerPage picker

Page picker

If the user denies access, they are redirected to the redirect_uri with an error (error).

Exchanging the grant for an access token

After the user grants access, the integration will receive an incoming request to the redirect_uri with the following information in the query string.

codeA temporary authorization code
stateThe value provided by the integration when the user was prompted for access.

Finally, the integration exchanges the authorization code for an access token by sending an HTTP POST request to Notion's token URL: This request is authorized using HTTP Basic Authentication, using the integration's client_id and client_secret (found in the integration settings) to create a credential: {client_id}:{client_secret}. Please note, in HTTP Basic Authentication, the credentials are base64 encoded before adding to the Authorization header.

The body of the request contains the following JSON-encoded fields:

"grant_type"stringAlways use "authorization_code"
"code"stringThe temporary authorization code received in the incoming request to the
"redirect_uri"stringThe "redirect_uri" that was provided in the Authorization step

The following is an example request to exchange the authorization code for an access token:

POST /v1/oauth/token HTTP/1.1
Authorization: Basic NDYzNTU4YTMtNzI1ZS00ZjM3LWI2ZDMtMDg4OTg5NGY2OGRlOnNlY3JldF95b3VfZm91bmRfbXlfZmFrZV9zZWNyZXQ=
Content-Type: application/json

{"grant_type":"authorization_code","code":"e202e8c9-0990-40af-855f-ff8f872b1ec6", "redirect_uri":""}

Notion will respond to the request with an access token and some additional information. The response contains the following JSON-encoded fields:

FieldTypeDescriptionNot null
"access_token"stringAn access token used to authorize requests to the Notion API.
"workspace_id"stringThe ID of the workspace where this authorization took place.
"workspace_name"stringA human-readable name which can be used to display this authorization in UI.
"workspace_icon"stringA URL to an image which can be used to display this authorization in UI.
"bot_id"stringAn identifier for this authorization.
"owner"objectAn object containing information about who can view and share this integration. { "workspace": true } will be returned for installations of workspace-level tokens. For user level tokens, a user object will be returned.

Tips for storing and using access tokens

  • Store all of the information your integration receives with the access token. You never know when your UI requirements or product requirements might change, and you find some use of this data. It's really hard (or impossible) to send users to authorize again to get this information.
  • The bot_id returned along with your token should act as your primary key when storing information.
  • When storing this information in a database, build relations between this information and the resources in Notion that you are accessing. For example, if you store a Notion database or page ID, relate those records with the correct access token that you can use to authorize requests when reading or writing to that database or page.

Handling errors

Integrations should be prepared for two kinds of errors: user authorization failures and token request failures.

User authorization failures

User authorization failures occur when Notion cannot create an authorization code before redirecting back to the redirect_uri. This type of failure is normal - a user simply choosing not to approve the authorization request will trigger a failure. Integrations should be built to handle these cases gracefully.

In some cases, Notion sends the user back to the redirect_uri with additional error query parameter. Integrations should present the user with a helpful user interface. Notion uses the common error codes in the OAuth specification. In other cases, Notion shows the error to the user without redirecting. These are logical errors and should be remedied by updating the integration implementation.

Token request failures

Token request failures occur when the integration attempts to exchange the code grant for an access token, but something goes wrong. In these cases, the response contains a JSON-encoded body with an "error" field. Once again, Notion uses the common error codes from the OAuth specification.

Did this page help you?