When to Use
- Admin UI database picker: Populate a dropdown list of available databases so users can select a target database for their workflow without needing to manually look up UUIDs in Notion.
- Cross-database sync inventory: Enumerate all accessible databases to build a sync manifest. Each database entry provides its ID and last-edited time, allowing a scheduler to determine which databases need updating.
- Governance audit: List all team databases at a scheduled interval to audit titles, sharing permissions, and last-edited dates. Flag databases that have not been touched in 90 days for review.
- Dynamic workflow configuration: At workflow startup, call
database/getMany to resolve a database name to its UUID. Store the UUID in a workflow variable for use in all subsequent operations.
- Permission verification sweep: After rotating or creating a new integration token, call
database/getMany to confirm which databases are visible. Compare the result against an expected list to catch missing shares.
Configuration
Authentication
| Field | Required | Description |
AuthenticationMethod | Required | "ApiToken" or "OAuth2". |
ApiToken | Required | Notion Internal Integration Token starting with secret_. Store in Credentials Manager. |
ClientId | OAuth2 | OAuth2 client ID. |
ClientSecret | OAuth2 | OAuth2 client secret. |
AccessToken | OAuth2 | OAuth2 access token. |
Operation Fields
| Field | Required | Description |
ReturnAll | Optional | When true, the node automatically pages through all results. Default: false. |
Limit | Optional | Maximum number of databases to return per call. Range: 1–100. Used when ReturnAll is false. Default: 100. |
StartCursor | Optional | Pagination cursor from a previous call's next_cursor field. Omit for the first page. |
ReturnAll vs pagination: Use ReturnAll: true when the total number of databases is small (under 50). For large workspaces or when you need cursor-based pagination across multiple workflow runs, use Limit + StartCursor and store next_cursor in a workflow variable.
Sample Configuration
{
"resource": "database",
"operation": "getMany",
"AuthenticationMethod": "ApiToken",
"ApiToken": "{{ $credentials.notionApiToken }}",
"ReturnAll": true
}
Validation Errors
| Error Code | Cause |
NOTION_UNAUTHORIZED | API token is invalid or the integration is not connected to the workspace. |
NOTION_INVALID_CONFIG | Authentication fields are missing or Limit is outside the valid range (1–100). |
NOTION_INVALID_REQUEST | StartCursor value is not a valid pagination cursor. Ensure it comes from a previous response's next_cursor field. |
NOTION_RATE_LIMITED | Rate limit exceeded. When using ReturnAll on a large workspace, the node may hit the 3 req/s limit. Add retry logic or switch to manual pagination with delays. |
Output
Success Port
| Field | Type | Description |
results | array | Array of database objects. Each item contains id, title, url, created_time, last_edited_time, properties, and parent. |
has_more | boolean | true if more pages of results exist. Only relevant when ReturnAll is false. |
next_cursor | string | Cursor to pass as StartCursor on the next call. null when has_more is false. |
Error Port
On failure the error port receives errorCode, message, and httpStatus. Wire the error port to a notification node to alert on authentication failures during scheduled audits.
Sample Output
{
"results": [
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"title": "Sprint Tasks",
"url": "https://www.notion.so/a1b2c3d4e5f67890abcdef1234567890",
"created_time": "2024-01-15T09:00:00.000Z",
"last_edited_time": "2024-06-10T14:32:00.000Z"
},
{
"id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
"title": "Customer CRM",
"url": "https://www.notion.so/b2c3d4e5f6a78901bcdef12345678901",
"created_time": "2023-11-01T08:00:00.000Z",
"last_edited_time": "2024-06-09T10:15:00.000Z"
}
],
"has_more": false,
"next_cursor": null
}
Expression Reference
| Expression | Type | Example Value | Use |
{{ $output.getManyDatabases.results.length }} | number | 12 | Count total accessible databases for audit report |
{{ $output.getManyDatabases.results[0].id }} | string | UUID | First database ID — useful when only one database is expected |
{{ $output.getManyDatabases.has_more }} | boolean | false | Gate a pagination loop on this value |
{{ $output.getManyDatabases.next_cursor }} | string | Cursor string | Pass to next call's StartCursor for manual pagination |
{{ $output.getManyDatabases.results.map(d => d.title) }} | array | ["Sprint Tasks","CRM"] | Build a list of database titles for display |
Node Policies & GuardRails
| Policy | Detail |
| Integration scope limitation | Only databases explicitly shared with the integration appear in results. Databases not shared are invisible to the API — this is by design. There is no error for invisible databases. |
| ReturnAll rate limit risk | When a workspace has more than ~50 databases, ReturnAll: true may trigger rate limiting. Switch to manual pagination (Limit: 50 + cursor loop) with a Delay node in production. |
| Results are not ordered by title | The API returns databases in internal order, not alphabetical. Use a Function node to sort by title before displaying to users. |
| Credentials in Credentials Manager | Never hard-code the API token. Use {{ $credentials.notionApiToken }}. |
| Stale cursor handling | Cursors from previous calls can expire. If a paginated loop returns NOTION_INVALID_REQUEST on a cursor, restart pagination from the beginning and update the stored cursor. |
Workflow Examples
Example 1 — Resolve Database Name to UUID at Startup
At workflow start, list all databases and find the one matching a configured name. Store its UUID for use in all downstream operations.
// Step 1: database/getMany (ReturnAll: true)
// Step 2: Function node
const db = $output.getManyDatabases.results.find(d => d.title === $vars.targetDatabaseName);
if (!db) throw new Error("Database not found: " + $vars.targetDatabaseName);
return { resolvedDbId: db.id };
// Step 3: All downstream nodes use {{ $vars.resolvedDbId }}
Example 2 — Scheduled Governance Audit
Weekly scheduled workflow audits all databases, flags those not edited in 90 days, and posts a summary to Slack.
// Step 1: ScheduledTrigger (weekly)
// Step 2: database/getMany (ReturnAll: true)
// Step 3: Function node — filter stale databases
const cutoff = new Date(Date.now() - 90 * 24 * 60 * 60 * 1000).toISOString();
const stale = $output.getManyDatabases.results.filter(d => d.last_edited_time < cutoff);
return { staleDatabases: stale, count: stale.length };
// Step 4: Slack/postMessage with stale count and list
Example 3 — Populate Form Dropdown
Build a BizFirst Form where users pick a database. Populate dropdown options dynamically from database/getMany rather than hardcoding database names.
// Step 1: database/getMany (ReturnAll: true)
// Step 2: Function node
const options = $output.getManyDatabases.results.map(d => ({ label: d.title, value: d.id }));
return { databaseOptions: options };
// Step 3: Form node uses {{ $json.databaseOptions }} as select source