How to use Notion API's public integration?

Notion is a versatile productivity tool that has become increasingly popular for personal and professional use. While the software is already feature-packed, there are situations where users may want to integrate Notion with other applications or automate repetitive tasks. This is where Notion APIs come in - they allow developers to build custom integrations and extensions for Notion. In this blog, we will explore how to use Notion APIs and take advantage of the platform's extensibility. We will cover the basics of Notion's API, show you how to authenticate with Notion, and walk through a few examples of how to use Notion's API to interact with your data. Whether you're a developer looking to create custom integrations or a power user looking to automate workflows, this guide will give you the tools you need to get started with Notion's API. So let's get started ;)

To get started with the Notion API, you will need to generate an integration token for internal integration and Oauth details for public integration. Here are the steps:

Setting up API credentials

  1. Sign in to your Notion account and navigate to the Integrations page. If you are not logged in it will prompt you to log in.

  2. Click on the New Integration button and fill in the basic details like app name, and logo and select the capabilities[scope of the data you want to access] of the app.

  3. Then you will be shown your integration token for private use and you can switch to public integration for using Oauth.

  4. If you choose public integration then you will be asked for details like redirect URL (callback URL) company name etc.

  5. Fill in every detail and in the Terms of use, Privacy policy you have to give an URL not any text :) [Fill in any random URL for now and change it during production]

  6. If you want to use a template notion page for your app then you can provide the URL template (It is better to give a template because it will improve your queries). Make sure to create a new page for the template with only the outline and database initialised.

  7. You will be provided with the OAuth client ID, Oauth secret and Authorization URL. Make sure to save them locally or as your environment variables.

Creating your app

So first direct your user to authorise your app by using the auth url provided by notion. The URL already contains all the parameters it should have.

If the user clicks Allow access, then they are redirected to the redirect_uri with a temporary authorization code (code). If the user denies access, then they are redirected to the redirect_uri with an error (error).

The integration needs to exchange the temporary code for an access_token.

To set up this step, your app implementation retrieves the code parameter from the redirect_uri. Then, send the code as part of a POST request to Notion’s token URL: https://api.notion.com/v1/oauth/token.

In this post request the body of the request must be:-

{
    "grant_type":"authorization_code",
    "code":"${code}",
    "redirect_uri":"process.env.REDIRECT_URL"
}

Here grant_type will always be the same string and the code will be the temporary code received from the redirect URL params where the user has been redirected and we are handling it.

In the Authorization headers, we have to also add our client ID and client secret with base64 encoding. We can do this in express like this:-

var options = {
    url: "https://api.notion.com/v1/oauth/token",
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Authorization:
        "Basic " +
        Buffer.from(
          `${process.env.CLIENT_ID}:${process.env.CLIENT_SECRET}`
        ).toString("base64"),
    },
    body: JSON.stringify({
      grant_type: "authorization_code",
      code: req.query.code,
      redirect_uri: "http://localhost:3000/callback",
    }),
  };
  request(options, async function (error, response, body) {
    if (!error) {
      let json = JSON.parse(body);//body is in string format as i have used request package use axios for better response
      console.log(json);
      });

Notion responds to the request with an access_token and additional information. The response contains the following JSON-encoded fields:

{
    "access_token":"",
    "bot_id":"",
    "duplicated_template_id":"",
    "owner":"",
    "workspace_icon":"",
    "workspace_id":"",
    "workspace_name":"",
}

If something goes wrong when the integration attempts to exchange the code for an access_token, then the response contains a JSON-encoded body with an "error"

If everything goes well then you have an access token and duplicated template id for a specific user and page.

Now this access_token can be used for your integration for identifying the user and duplicated_template_id can be used to identify the notion page access provided by the user. Make sure to save these locally or in your database.

With this, you have set up your notion public integration and have received an access token for the user to make requests on their behalf. Now you can fiddle with the notion page shared with you. For further guidance, you can refer to this.

Notion docs are very amazing and are also very beginner friendly. There are all sorts of code snippets and also example responses for every request and error response.

Make sure to read these docs:- Guide(Get started) and API reference(Example request and response) also you can refer to my project for any code.

This is a sample use case that i used in my project:-

var options = {
    method: "POST",
    url: "https://api.notion.com/v1/pages",
    headers: {
      "Notion-Version": "2022-02-22",
      Authorization: `Bearer ${accessToken}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      parent: {
        type: "database_id",
        database_id: database_id,
      },
      properties: {
        URL: { type: "url", url: url },
        Description: {
          type: "rich_text",
          rich_text: [{ type: "text", text: { content: description } }],
        },
        Tags: {
          type: "multi_select",
          multi_select: tags,
        },
        Name: {
          type: "title",
          title: [{ type: "text", text: { content: title } }],
        },
      },
    }),
  };
  request(options, function (error, response) {
    if (error) throw new Error(error);
    console.log(response.body);
    res.json({ message: response.body });
  });

If there are any errors, problems or suggestions you can contact me✌️.