# Notion API Basics

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

- Skill: `theheavenlyd3mon/notion-api-basics` (Agent Skill)
- Install (CLI): `npx skillmds add theheavenlyd3mon/notion-api-basics`
- Raw SKILL.md: https://api.skillmd.com/api/skills/theheavenlyd3mon/notion-api-basics/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Integrations & APIs
- License: MIT
- Author: theheavenlyd3mon (https://skillmd.com/u/theheavenlyd3mon)
- Updated: 2026-09-09
- Page: https://skillmd.com/skills/theheavenlyd3mon/notion-api-basics

---


# 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/<profile>/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

