Skip to main content
The Client class is the main entry point for interacting with the Notion API. It handles authentication, request management, and provides access to all API endpoints.

Basic Initialization

Create a client instance with your Notion API token:
import { Client } from '@notionhq/client'

const notion = new Client({
  auth: process.env.NOTION_API_KEY,
})
Get your API key from the Notion integrations page.

Client Options

The client accepts several configuration options:

Authentication

auth
string
Your Notion integration token or OAuth access token. Can also be provided per-request.
const notion = new Client({
  auth: 'secret_1234567890abcdefghijklmnopqrstuv',
})

Base URL

baseUrl
string
default:"https://api.notion.com"
The base URL for Notion API requests. Useful for testing or proxying.
const notion = new Client({
  auth: process.env.NOTION_API_KEY,
  baseUrl: 'https://api.notion.com', // default
})

Notion Version

notionVersion
string
default:"2025-09-03"
The Notion API version to use. Defaults to Client.defaultNotionVersion.
const notion = new Client({
  auth: process.env.NOTION_API_KEY,
  notionVersion: '2025-09-03',
})

Request Timeout

timeoutMs
number
default:60000
Request timeout in milliseconds. Requests exceeding this limit will throw a RequestTimeoutError.
const notion = new Client({
  auth: process.env.NOTION_API_KEY,
  timeoutMs: 30000, // 30 seconds
})

Custom Fetch

fetch
SupportedFetch
Custom fetch implementation. Useful for testing or using alternative HTTP clients.
import fetch from 'node-fetch'

const notion = new Client({
  auth: process.env.NOTION_API_KEY,
  fetch: fetch,
})

HTTP Agent

agent
Agent
Node.js HTTP agent for connection pooling and proxy support. Silently ignored in browsers.
import { Agent } from 'node:http'

const agent = new Agent({
  keepAlive: true,
  maxSockets: 50,
})

const notion = new Client({
  auth: process.env.NOTION_API_KEY,
  agent: agent,
})

Retry Configuration

See Retries for detailed retry configuration.

Logging

See Logging for logging configuration options.

Making Requests

The client provides namespaced methods for each API resource:
// Blocks
await notion.blocks.retrieve({ block_id: 'block-id' })
await notion.blocks.update({ block_id: 'block-id', ... })
await notion.blocks.delete({ block_id: 'block-id' })
await notion.blocks.children.list({ block_id: 'block-id' })
await notion.blocks.children.append({ block_id: 'block-id', children: [...] })

// Pages
await notion.pages.create({ parent: { database_id: 'db-id' }, properties: {...} })
await notion.pages.retrieve({ page_id: 'page-id' })
await notion.pages.update({ page_id: 'page-id', properties: {...} })
await notion.pages.move({ page_id: 'page-id', parent: {...} })

// Databases
await notion.databases.create({ parent: { page_id: 'page-id' }, ... })
await notion.databases.retrieve({ database_id: 'db-id' })
await notion.databases.update({ database_id: 'db-id', ... })

// Data Sources
await notion.dataSources.create({ ... })
await notion.dataSources.retrieve({ data_source_id: 'ds-id' })
await notion.dataSources.update({ data_source_id: 'ds-id', ... })
await notion.dataSources.query({ data_source_id: 'ds-id', ... })

// Users
await notion.users.retrieve({ user_id: 'user-id' })
await notion.users.list({})
await notion.users.me({})

// Comments
await notion.comments.create({ parent: { page_id: 'page-id' }, rich_text: [...] })
await notion.comments.retrieve({ comment_id: 'comment-id' })
await notion.comments.list({ block_id: 'block-id' })

// Search
await notion.search({ query: 'meeting notes' })

Custom Requests

For advanced use cases, you can make custom requests using the request method:
const response = await notion.request({
  path: 'blocks/block-id',
  method: 'get',
  query: { filter_properties: 'title' },
})

Request Parameters

path
string
required
The API endpoint path (without the /v1/ prefix).
method
'get' | 'post' | 'patch' | 'delete'
required
The HTTP method.
query
Record<string, string | number | boolean | string[]>
URL query parameters.
body
Record<string, unknown>
Request body for POST and PATCH requests.
auth
string | { client_id: string; client_secret: string }
Override the client-level auth for this request.
headers
Record<string, string>
Additional HTTP headers.

Per-Request Authentication

You can override the client-level authentication for individual requests:
const notion = new Client() // No default auth

// Use different tokens for different requests
await notion.pages.retrieve({ 
  page_id: 'page-id',
  auth: 'secret_workspace_a_token',
})

await notion.blocks.retrieve({ 
  block_id: 'block-id',
  auth: 'secret_workspace_b_token',
})

OAuth Authentication

For OAuth flows, provide client_id and client_secret:
const notion = new Client()

// Exchange authorization code for access token
const tokenResponse = await notion.oauth.token({
  client_id: process.env.OAUTH_CLIENT_ID,
  client_secret: process.env.OAUTH_CLIENT_SECRET,
  grant_type: 'authorization_code',
  code: authorizationCode,
  redirect_uri: 'https://example.com/callback',
})

// Use the access token for subsequent requests
const authedClient = new Client({
  auth: tokenResponse.access_token,
})
See the OAuth guide for more details.

Type Safety

All methods return fully typed responses:
import { PageObjectResponse } from '@notionhq/client'

const page = await notion.pages.retrieve({ page_id: 'page-id' })

// TypeScript knows the shape of the response
if (page.object === 'page' && 'url' in page) {
  const url: string = page.url
  const createdTime: string = page.created_time
}
See TypeScript for more on working with types.

Build docs developers (and LLMs) love