Can I make a Notion page public programmatically through their API?

I know how to publish a Notion page to the web manually through the interface. You just go to the page settings and toggle the public sharing option. However, I need to automate this process for multiple pages in my workspace.

I’ve been looking through the official Notion API documentation but can’t find any endpoints or methods that allow me to programmatically set a page’s public sharing status. Does anyone know if this functionality exists in the API? I want to build a script that can automatically publish certain pages based on specific conditions.

Has anyone successfully implemented this feature or found a workaround? Any help would be appreciated since manual publishing isn’t practical for my use case.

a. The Problem

You’re encountering a 404 error when attempting to add entries to a Notion database via their API, despite successfully creating new pages using the same credentials. The error message suggests the database cannot be found, implying a permissions issue. This is puzzling because the authentication for page creation works correctly.

b. :wrench: How to Fix It

The most likely cause of this issue is insufficient permissions for the integration used to access the Notion database. While your integration can create pages, it might lack the necessary permissions to interact with specific databases.

c. Step-by-Step Solution

  1. Verify Database Permissions: The core solution is to ensure your Notion integration has the correct permissions to access the specified database. In your Notion workspace, navigate to the database in question. Check its settings (usually found via a gear icon or similar). Locate the “Permissions” or “Sharing” section. Verify that the integration associated with your API key has at least “Edit” permissions (or whatever level is required by your database operations). If the integration isn’t listed, explicitly add it with the appropriate access level. Crucially, the database ID (db_id in your code) must exactly match the ID of the database you’re trying to modify within Notion itself. You may find this ID in the database’s URL.

  2. Validate Database ID: Double-check that the db_id variable in your Python function (insert_database_entry) accurately reflects the database ID in Notion. A simple typo here will result in a 404 error. Print the value of db_id before making the API request to confirm its correctness.

  3. Inspect API Request and Response: Use a tool like a browser developer console’s Network tab, or a dedicated HTTP client such as Postman, to examine the raw HTTP request and response. This will give you detailed insights into the request headers, payload, and response status codes. Look for discrepancies between what your code sends and what the Notion API expects. Pay close attention to the Authorization header and ensure your Bearer token is correctly generated and still active.

d. Use Rich Formatting

Here’s the improved code with error handling and more informative output:

import requests

def insert_database_entry(token, db_id, entry_data):
    endpoint = "https://api.notion.com/v1/pages/"
    request_headers = {
        "Authorization": f"Bearer {token}",
        "Content-Type": "application/json",
        "Notion-Version": "2022-06-28"
    }
    payload = {
        "parent": {
            "type": "database_id",
            "database_id": db_id
        },
        "properties": entry_data
    }
    
    try:
        result = requests.post(endpoint, headers=request_headers, json=payload)
        result.raise_for_status() # Raise HTTPError for bad responses (4xx or 5xx)
        print("Entry added successfully!")
        return result.json()
    except requests.exceptions.HTTPError as http_err:
        print(f"HTTP error occurred: {http_err}")
        print(f"Status Code: {result.status_code}")
        print(f"Response Text: {result.text}")
        return None
    except requests.exceptions.RequestException as e:
        print(f"An error occurred: {e}")
        return None

:speech_balloon: Still running into issues? Share your (sanitized) config files, the exact command you ran, and any other relevant details. The community is here to help!

Still can’t do this with Notion’s API unfortunately. Just checked again and there’s zero endpoints for sharing settings. Super frustrating. You could try Zapier to track which pages need publishing, then just batch process them manually?

a. The Problem:

The user is building a React application that interacts with private Notion pages. Authentication is handled using a NotionService client initialized with userId and sessionToken fetched from environment variables. The problem is that these tokens expire or change, requiring manual updates and application restarts. The user seeks a programmatic solution to automatically refresh these credentials.

b. :wrench: How to Fix It:

This guide details how to programmatically fetch updated Notion authentication tokens, eliminating the need for manual intervention. The core solution involves using the Notion API’s built-in authentication mechanisms rather than relying on directly managing cookies. We will build a refresh token approach.

c. Step-by-Step Solution:

  1. Implement a Refresh Token Strategy: Instead of directly using the session_token which expires, utilize a refresh token. This token has a longer lifetime and can be used to request new access tokens (including session_token) as needed. This requires adjusting your NotionService to handle token refreshes. Here’s a conceptual outline using the axios library for HTTP requests (adapt to your preferred library):
class NotionService {
  constructor(refreshToken) {
    this.refreshToken = refreshToken;
    this.accessToken = null; // Initialize access token
  }

  async getAccessToken() {
    if (this.accessToken) {
      return this.accessToken;
    }

    try {
      const response = await axios.post('/your-notion-refresh-endpoint', {
        refresh_token: this.refreshToken,
      });
      this.accessToken = response.data.access_token; // Assuming the API returns an access_token
      return this.accessToken;
    } catch (error) {
      console.error('Error refreshing Notion token:', error);
      throw error; // Handle the error appropriately (e.g., retry, display message)
    }
  }


  async makeNotionRequest(method, endpoint, data) {
    const accessToken = await this.getAccessToken();
    const headers = {
      Authorization: `Bearer ${accessToken}`,
      'Content-Type': 'application/json',
    };

    try {
      const response = await axios({
        method,
        url: endpoint,
        data,
        headers,
      });
      return response.data;
    } catch (error) {
      // Handle errors, potentially retrying based on error code
      console.error('Error making Notion request:', error);
      throw error;
    }
  }
}

// Initialize with a refresh token (from a secure storage)
const refreshToken = process.env.NOTION_REFRESH_TOKEN;
const notionClient = new NotionService(refreshToken);


// Use notionClient.makeNotionRequest for all your API calls
notionClient.makeNotionRequest('GET', '/your-notion-api-endpoint')
  .then(data => {
    // Handle your Notion data
    console.log(data);
  })
  .catch(error => {
    // Handle errors
    console.error("Error fetching data:", error)
  });
  1. Securely Store the Refresh Token: Do not store your refresh token directly in environment variables. Use a more secure method such as a dedicated secrets management system (e.g., AWS Secrets Manager, HashiCorp Vault, or environment variables specifically for your CI/CD pipeline which are not checked into version control), or encrypt it using a trusted method.

  2. Implement Error Handling: The provided code snippet includes basic error handling. However, robust error handling is critical. Consider scenarios like network failures, rate limiting, and invalid tokens. Implement retries with exponential backoff and clear error messages to the user.

d. Use Rich Formatting: (Already incorporated above)

:speech_balloon: Still running into issues? Share your (sanitized) config files, the exact command you ran, and any other relevant details. The community is here to help!

Nope, this doesn’t exist in the API. Hit the same wall about six months back when I was building content workflows for our docs site. The API covers pretty much everything for page content but completely skips sharing permissions - I’m guessing that’s intentional for security reasons. Here’s what worked for me: used the API to find pages that met my publishing criteria, then exported a CSV with URLs and metadata. After that, I just went through each page and flipped the sharing toggle manually. Still a pain, but way better than hunting through a massive workspace randomly. Pro tip: you can use the API to grab page properties, so set up a status field to track what needs publishing. Makes the whole manual process way less chaotic.

Yeah, this limitation still exists. I spent weeks trying to find a way to batch publish pages in our company workspace. Got closest with Selenium - basically automated a browser to click through each page’s sharing toggle. Pretty hacky though, and it’d break whenever Notion updated their UI. Plus it was slow as hell since it had to load every single page.

Ended up restructuring everything to use database views with filters instead of public pages. Not perfect, but I can automate content updates through the API now and skip the manual publishing mess entirely.

yeah, im kinda in the same boat. manual sharing is a real pain, especially for lots of pages. really hope notion sorta adds this feature soon, would save a ton of time!

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.