Skip to content
Back to skills

Notion Api Basics

BSecurity

Notion API fundamentals: authentication, curl patterns, property types, API version differences, and troubleshooting.

  • 36 stars
  • 0 votes
  • 0 copies
  • 5 views
  • Added September 10, 2026
ai-agentspythonbashdebuggingapidatabase

Works with

  • terminal
  • cli
  • api

Security analysis

B75/100
  • criticalExfiltrates credentials via HTTP — exact pattern from Snyk ToxicSkills study

Pro shows the line behind each finding and how to fix it

Scanned September 10, 2026

npx -y skills add theheavenlyd3mon/hermes-profiles --skill notion-api-basics --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Notion Api Basics?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Notion Api Basics
[![Security: B — Skills Directory](https://www.skillsdirectory.com/api/skills/theheavenlyd3mon-notion-api-basics-hermes-profiles/badge)](https://www.skillsdirectory.com/skills/theheavenlyd3mon-notion-api-basics-hermes-profiles)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: notion-api-basics
description: "Notion API fundamentals: authentication, curl patterns, property types, API version differences, and troubleshooting."
version: 1.0.0
author: hermes
license: MIT
platforms: [linux, macos, windows]
metadata:
  hermes:
    tags: [Notion, API, Authentication, Integration]
    homepage: https://developers.notion.com
    related_skills: [notion-databases, notion-pages, notion-blocks, notion-search]
prerequisites:
  env_vars: [NOTION_API_KEY]
---

# Notion API Basics

Foundation skill for all Notion API operations. Covers authentication, the base curl pattern, property types, API version differences, and common troubleshooting.

## Prerequisites

1. Create an integration at https://notion.so/my-integrations
2. Copy the API key (starts with `ntn_` or `secret_`)
3. Store it in `~/.hermes/.env`:
   ```bash
   echo 'NOTION_API_KEY=ntn_your_key_here' >> ~/.hermes/.env
   ```
4. **Important:** Share target pages/databases with your integration in Notion (click "..." → "Connect to" → your integration name)
5. Find a page/database ID: open it in Notion, copy the URL — the ID is the UUID segment (32 hex chars, dashes optional)

### Pitfall: Check the key isn't commented out

```bash
grep '^NOTION_API_KEY=' ~/.hermes/.env
```
If you see `# NOTION_API_KEY=...` (commented out), uncomment it:
```bash
sed -i '' 's/^# NOTION_API_KEY=/NOTION_API_KEY=/' ~/.hermes/.env
```

The `.env` file is write-protected from Hermes tools — use `sed` via terminal.

### Pitfall: Terminal sandbox points HOME elsewhere

When running inside a profile (e.g. Senna), `$HOME` resolves to `~/.hermes/profiles/senna/home` — NOT `~`. This means `source ~/.hermes/.env` fails. Always use the absolute path:

```bash
source ~/.hermes/.env
```

This applies to cron jobs and terminal() calls inside the profile sandbox.

## Authentication Options

| Method | What it is | Page sharing needed? | Workspace scope |
|--------|-----------|----------------------|-----------------|
| **Internal Integration** (recommended) | A bot with its own permissions | ✅ Share each page/database with the bot explicitly | One workspace |
| **PAT (Personal Access Token)** | Acts as *you* — has your existing permissions | ❌ No sharing needed — sees what you see | One user in one workspace |
| **OAuth 2.0** | For apps distributed to other people's workspaces | ❌ Users pick pages during install | Any workspace |

**Recommendation:** Start with an **Internal Integration** unless the user explicitly asks for a PAT.

## Base curl Pattern

All requests follow this pattern:

```bash
curl -s -X GET "https://api.notion.com/v1/..." \
  -H "Authorization: Bearer $NOTION_API_KEY" \
  -H "Notion-Version: 2025-09-03" \
  -H "Content-Type: application/json"
```

Key points:
- `Notion-Version` header is **required** — this skill uses `2025-09-03` (latest)
- Add `-s` to suppress curl progress bars (cleaner output)
- Pipe through `jq` for readable JSON: `| jq '.results[0].properties'`
- For quick debugging: `| head -c 500` or `| python3 -m json.tool | head -40`

## Property Types Reference

When creating or updating database entries (pages), properties follow these formats:

| Type | JSON Format |
|------|------------|
| **Title** | `{"title": [{"text": {"content": "..."}}]}` |
| **Rich text** | `{"rich_text": [{"text": {"content": "..."}}]}` |
| **Select** | `{"select": {"name": "Option"}}` |
| **Multi-select** | `{"multi_select": [{"name": "A"}, {"name": "B"}]}` |
| **Date** | `{"date": {"start": "2026-01-15", "end": null}}` |
| **Checkbox** | `{"checkbox": true}` |
| **Number** | `{"number": 42}` |
| **URL** | `{"url": "https://..."}` |
| **Email** | `{"email": "user@example.com"}` |
| **Relation** | `{"relation": [{"id": "page_id"}]}` |

## Key API Version Differences (2025-09-03 vs older)

- **Databases → Data Sources:** Use `/v1/data_sources/` endpoints for queries and retrieval
- **Two IDs per database:**
  - `database_id` — used when creating pages (`parent: {"database_id": "..."}`)
  - `data_source_id` — used when querying (`POST /v1/data_sources/{id}/query`)
- **Search finds data sources:** Results return `"object": "data_source"` with their `data_source_id`
- **Creating databases:** `POST /v1/databases` with `initial_data_source.properties` (NOT top-level `properties`)

## Notes

- Page/database IDs are UUIDs (with or without dashes)
- Rate limit: ~3 requests/second average (bursts allowed)
- The API cannot set database view filters — that's UI-only
- Use `is_inline: true` when creating data sources to embed them in pages
- **No `DELETE /v1/databases/{id}` endpoint** — to remove a database, use the Notion UI

## Troubleshooting

### `object_not_found` (404)

Almost always a **permissions issue**, not a missing page. The integration hasn't been granted access.

**Fix:** In Notion, open the page → "..." → "Connect to" → select your integration name.

### `validation_error` — property doesn't exist

The property name in your JSON doesn't match the schema. Fetch actual property names:

```bash
source ~/.hermes/.env
DS_ID=$(curl -s "https://api.notion.com/v1/databases/{database_id}" \
  -H "Authorization: Bearer $NOTION_API_KEY" \
  -H "Notion-Version: 2025-09-03" | jq -r '.data_sources[0].id')
curl -s "https://api.notion.com/v1/data_sources/$DS_ID" \
  -H "Authorization: Bearer $NOTION_API_KEY" \
  -H "Notion-Version: 2025-09-03" | jq '.properties | keys'
```

### Properties silently dropped during database creation

If you used `POST /v1/databases` with top-level `properties` (old API pattern), the properties are silently dropped — only a default `"Name"` title property exists. Fix by PATCHing the data source (see notion-databases skill).

## Load-bearing URLs

- API docs: https://developers.notion.com
- Integrations: https://notion.so/my-integrations
- Reference API: https://developers.notion.com/reference/intro

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.