¿Qué hace Notion?
Habla con Notion de dos maneras. El mismo token de integración funciona para ambas: elige según lo que esté disponible.
◆ CLI ntn — La CLI oficial de Notion. Sintaxis más corta, carga de archivos en una línea, necesario para Workers. Solo macOS y Linux a partir de mayo de 2026 (soporte para Windows "próximamente"). Por defecto cuando está instalado.
◆ HTTP + curl — Funciona en todas partes, incluido Windows. Respaldo por defecto cuando ntn no está instalado.
Configuración
1. Obtén un token de integración (necesario para ambos caminos)
- Crea una integración en https://notion.so/my-integrations
- Copia la clave API (empieza con
ntn_osecret_) - Guárdala en
~/.hermes/.env:NOTION_API_KEY=ntn_tu_clave_aqui - Comparte las páginas/bases de datos de destino con la integración en Notion: menú de página
...→Conectar a→ el nombre de tu integración. Sin esto, la API devuelve 404 para esa página aunque exista.
2. Instala ntn (ruta preferida en macOS / Linux)
# Recomendado
curl -fsSL https://ntn.dev | bash
# O mediante npm (necesita Node 22+, npm 10+)
npm install --global ntn
ntn --version # verificar
Omitir ntn login — usa el token de integración en su lugar. Esto funciona sin interfaz gráfica, no se necesita navegador:
export NOTION_API_TOKEN=$NOTION_API_KEY # ntn lee NOTION_API_TOKEN
export NOTION_KEYRING=0 # no intentes usar el llavero del SO
Añade esas exportaciones a tu perfil de shell (o a ~/.hermes/.env) para que cada sesión las herede.
3. Elige la ruta en tiempo de ejecución
if command -v ntn >/dev/null 2>&1; then
# usar ntn
else
# recurrir a curl
fi
Usuarios de Windows: omitan el paso 2 por completo hasta que llegue ntn nativo: la Ruta B funciona bien. Si quieren ergonomía de CLI ahora, instalen ntn dentro de WSL2.
Conceptos básicos de la API
Notion-Version: 2025-09-03 es obligatorio en todas las solicitudes HTTP. ntn lo maneja por ti. En esta versión, lo que los usuarios llaman "bases de datos" se denominan fuentes de datos en la API.
Ruta A — CLI ntn (preferida, macOS / Linux)
Llamadas API sin formato (abreviatura de curl)
ntn api v1/users # GET
ntn api v1/pages parent[page_id]=abc123 \ # POST con cuerpo en línea
properties[title][0][text][content]="Notas"
ntn api v1/pages/abc123 -X PATCH archived:=true # PATCH; := es no cadena (bool/num/null)
Notas de sintaxis:
key=value— campos de cadenakey[nested]=value— campos de objeto anidadoskey:=value— asignación tipada (booleanos, números, null, arrays)
Buscar
ntn api v1/search query="título de página"
Leer metadatos de página
ntn api v1/pages/{page_id}
Leer página como Markdown (amigable para agentes)
ntn api v1/pages/{page_id}/markdown
Leer contenido de página como bloques
ntn api v1/blocks/{page_id}/children
Crear página desde Markdown
ntn api v1/pages \
parent[page_id]=xxx \
properties[title][0][text][content]="Notas de la reunión" \
markdown="# Agenda
- Roadmap Q3
- Contratación"
Actualizar una página con Markdown
ntn api v1/pages/{page_id}/markdown -X PATCH \
markdown="## Actualización
Enviamos el prototipo."
Consultar una base de datos (fuente de datos)
ntn api v1/data_sources/{data_source_id}/query -X POST \
filter[property]=Status filter[select][equals]=Active
Para consultas complejas con sorts, múltiples cláusulas de filtro o lógica compuesta, canaliza JSON:
echo '{"filter": {"property": "Status", "select": {"equals": "Active"}}, "sorts": [{"property": "Date", "direction": "descending"}]}' | \
ntn api v1/data_sources/{data_source_id}/query -X POST --json -
Carga de archivos (una línea — la mayor ventaja de la CLI)
ntn files create < photo.png
ntn files create --external-url https://ejemplo.com/photo.png
ntn files list
Compara con el flujo HTTP de 3 pasos (crear carga → PUT bytes → referenciar).
Variables de entorno útiles
| Variable | Efecto |
|---|---|
NOTION_API_TOKEN | Token de autenticación (anula el llavero) — configúralo con tu token de integración |
NOTION_KEYRING=0 | Credenciales basadas en archivo en ~/.config/notion/auth.json en lugar del llavero del SO |
NOTION_WORKSPACE_ID | Omite el mensaje del selector de espacio de trabajo |
Ruta B — HTTP + curl (multiplataforma, predeterminado en Windows)
Todas las solicitudes siguen este patrón:
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"
En Windows, el curl incluido con Windows 10+ funciona tal cual. Los usuarios de PowerShell también pueden usar Invoke-RestMethod.
Buscar
curl -s -X POST "https://api.notion.com/v1/search" \
-H "Authorization: Bearer $NOTION_API_KEY" \
-H "Notion-Version: 2025-09-03" \
-H "Content-Type: application/json" \
-d '{"query": "título de página"}'
Leer metadatos de página
curl -s "https://api.notion.com/v1/pages/{page_id}" \
-H "Authorization: Bearer $NOTION_API_KEY" \
-H "Notion-Version: 2025-09-03"
Leer página como Markdown (amigable para agentes)
Más fácil de pasar a un modelo que el JSON de bloques.
curl -s "https://api.notion.com/v1/pages/{page_id}/markdown" \
-H "Authorization: Bearer $NOTION_API_KEY" \
-H "Notion-Version: 2025-09-03"
Leer contenido de página como bloques (cuando necesitas estructura)
curl -s "https://api.notion.com/v1/blocks/{page_id}/children" \
-H "Authorization: Bearer $NOTION_API_KEY" \
-H "Notion-Version: 2025-09-03"
Crear página desde Markdown
POST /v1/pages acepta un parámetro de cuerpo markdown.
curl -s -X POST "https://api.notion.com/v1/pages" \
-H "Authorization: Bearer $NOTION_API_KEY" \
-H "Notion-Version: 2025-09-03" \
-H "Content-Type: application/json" \
-d '{
"parent": {"page_id": "xxx"},
"properties": {"title": [{"text": {"content": "Notas de la reunión"}}]},
"markdown": "# Agenda\n\n- Roadmap Q3\n- Contratación\n\n## Decisiones\n- Enviar MVP el viernes"
}'
Actualizar una página con Markdown
curl -s -X PATCH "https://api.notion.com/v1/pages/{page_id}/markdown" \
-H "Authorization: Bearer $NOTION_API_KEY" \
-H "Notion-Version: 2025-09-03" \
-H "Content-Type: application/json" \
-d '{"markdown": "## Actualización\n\nEnviamos el prototipo."}'
Crear página en una base de datos (propiedades tipadas)
curl -s -X POST "https://api.notion.com/v1/pages" \
-H "Authorization: Bearer $NOTION_API_KEY" \
-H "Notion-Version: 2025-09-03" \
-H "Content-Type: application/json" \
-d '{
"parent": {"database_id": "xxx"},
"properties": {
"Nombre": {"title": [{"text": {"content": "Nuevo elemento"}}]},
"Estado": {"select": {"name": "Por hacer"}}
}
}'
Consultar una base de datos (fuente de datos)
curl -s -X POST "https://api.notion.com/v1/data_sources/{data_source_id}/query" \
-H "Authorization: Bearer $NOTION_API_KEY" \
-H "Notion-Version: 2025-09-03" \
-H "Content-Type: application/json" \
-d '{
"filter": {"property": "Estado", "select": {"equals": "Activo"}},
"sorts": [{"property": "Fecha", "direction": "descending"}]
}'
Crear una base de datos
curl -s -X POST "https://api.notion.com/v1/data_sources" \
-H "Authorization: Bearer $NOTION_API_KEY" \
-H "Notion-Version: 2025-09-03" \
-H "Content-Type: application/json" \
-d '{
"parent": {"page_id": "xxx"},
"title": [{"text": {"content": "Mi base de datos"}}],
"properties": {
"Nombre": {"title": {}},
"Estado": {"select": {"options": [{"name": "Por hacer"}, {"name": "Hecho"}]}},
"Fecha": {"date": {}}
}
}'
Actualizar propiedades de página
curl -s -X PATCH "https://api.notion.com/v1/pages/{page_id}" \
-H "Authorization: Bearer $NOTION_API_KEY" \
-H "Notion-Version: 2025-09-03" \
-H "Content-Type: application/json" \
-d '{"properties": {"Estado": {"select": {"name": "Hecho"}}}}'
Añadir bloques a una página
curl -s -X PATCH "https://api.notion.com/v1/blocks/{page_id}/children" \
-H "Authorization: Bearer $NOTION_API_KEY" \
-H "Notion-Version: 2025-09-03" \
-H "Content-Type: application/json" \
-d '{
"children": [
{"object": "block", "type": "paragraph", "paragraph": {"rich_text": [{"text": {"content": "¡Hola desde Hermes!"}}]}}
]
}'
Carga de archivos (flujo de 3 pasos)
# 1. Crear carga
curl -s -X POST "https://api.notion.com/v1/file_uploads" \
-H "Authorization: Bearer $NOTION_API_KEY" \
-H "Notion-Version: 2025-09-03" \
-H "Content-Type: application/json" \
-d '{"filename": "foto.png", "content_type": "image/png"}'
# 2. PUT los bytes a la upload_url devuelta arriba
curl -s -X PUT "{upload_url}" --data-binary @foto.png
# 3. Referencia {file_upload_id} en una página/bloque
Tipos de Propiedades
Formatos comunes de propiedades para elementos de base de datos:
- Título:
{"title": [{"text": {"content": "..."}}]} - Texto enriquecido:
{"rich_text": [{"text": {"content": "..."}}]} - Selección:
{"select": {"name": "Opción"}} - Selección múltiple:
{"multi_select": [{"name": "A"}, {"name": "B"}]} - Fecha:
{"date": {"start": "2026-01-15", "end": "2026-01-16"}} - Casilla de verificación:
{"checkbox": true} - Número:
{"number": 42} - URL:
{"url": "https://..."} - Correo electrónico:
{"email": "[email protected]"} - Relación:
{"relation": [{"id": "page_id"}]}
Versión de API 2025-09-03 — Bases de datos vs Fuentes de datos
- Las bases de datos se convirtieron en fuentes de datos. Usa los endpoints
/data_sources/para consultas y recuperación. - Dos ID por base de datos:
database_idydata_source_id.database_idal crear páginas:parent: {"database_id": "..."}data_source_idal consultar:POST /v1/data_sources/{id}/query
- La búsqueda devuelve bases de datos como
"object": "data_source"con el campodata_source_id.
Workers de Notion (avanzado, requiere ntn)
Los Workers son programas TypeScript que Notion aloja por ti. Un worker puede exponer cualquier combinación de:
- Sincronizaciones — extraer datos de APIs externas a una base de datos de Notion en un horario (30 min por defecto).
- Herramientas — aparecen como herramientas invocables dentro de los Agentes Personalizados de Notion.
- Webhooks — recibir eventos HTTP de servicios externos (GitHub, Stripe, etc.) y actuar en Notion.
Plan / restricción de plataforma:
- La CLI funciona en todos los planes. Desplegar Workers requiere el plan Business o Enterprise.
ntnes solo macOS/Linux a partir de mayo de 2026. Los usuarios de Windows necesitan WSL2 o esperar soporte nativo.- Gratis hasta el 11 de agosto de 2026; medido en créditos de Notion después.
Worker mínimo
ntn workers new my-worker # andamiar
cd my-worker
# Editar src/index.ts
ntn workers deploy --name my-worker
src/index.ts:
import { Worker } from "@notionhq/workers";
const worker = new Worker();
export default worker;
worker.tool("saludar", {
title: "Saludar a un usuario",
description: "Devuelve un saludo amigable",
inputSchema: { type: "object", properties: { nombre: { type: "string" } }, required: ["nombre"] },
execute: async ({ nombre }) => `¡Hola, ${nombre}!`,
});
Capacidad de webhook
worker.webhook("alPushDeGithub", {
title: "Manejador de Push de GitHub",
execute: async (events, { notion }) => {
for (const event of events) {
// event.body, event.rawBody (para verificación de firma), event.headers
console.log("entrega recibida", event.deliveryId);
}
},
});
Después del despliegue: ntn workers webhooks list muestra la URL que Notion genera. Trata esa URL como secreta: cualquiera que la tenga puede enviar eventos a menos que añadas verificación de firma.
Comandos del ciclo de vida del Worker
ntn workers deploy
ntn workers list
ntn workers exec <clave-de-capacidad> -d '{"nombre": "mundo"}'
ntn workers sync trigger <clave> # ejecutar una sincronización ahora
ntn workers sync pause <clave>
ntn workers env set GITHUB_WEBHOOK_SECRET=...
ntn workers runs list # invocaciones recientes
ntn workers runs logs <run-id>
ntn workers webhooks list
Cuando te pidan construir un Worker, andamia con ntn workers new, escribe el código en src/index.ts, configura los secretos con ntn workers env set y despliega. La documentación de Notion en https://developers.notion.com/workers cubre toda la superficie de la API.
Markdown con sabor a Notion (usado por los endpoints /markdown)
CommonMark estándar más etiquetas similares a XML para bloques específicos de Notion. Usa tabulaciones para la sangría.
Bloques más allá de CommonMark:
<callout icon="🎯" color="blue_bg">
Envía el MVP antes del **viernes**.
</callout>
<details color="gray">
<summary>Título del desplegable</summary>
Hijos sangrados con una tabulación
</details>
<columns>
<column>Lado izquierdo</column>
<column>Lado derecho</column>
</columns>
<table_of_contents color="gray"/>
En línea:
- Menciones:
<mention-user url="..."/>,<mention-page url="...">Título</mention-page>,<mention-date start="2026-05-15"/> - Subrayado:
<span underline="true">texto</span> - Color:
<span color="blue">texto</span>o a nivel de bloque{color="blue"}en la primera línea - Matemáticas: en línea
$x^2$, bloque$$ ... $$ - Citas:
[^https://ejemplo.com]
Colores: gray brown orange yellow green blue purple pink red, más variantes *_bg para fondos.
Los encabezados 5/6 se colapsan a H4. Varias líneas > se renderizan como bloques de cita separados — usa <br> dentro de un solo > para citas multilínea.
Elegir la ruta correcta
| Tarea | macOS / Linux | Windows |
|---|---|---|
| Leer/escribir páginas, buscar, consultar bases de datos | ntn api ... | curl |
| Leer una página para que un agente la resuma | ntn api v1/pages/{id}/markdown | curl /markdown endpoint |
| Subir un archivo | ntn files create < archivo | Flujo HTTP de 3 pasos |
| Exploración única de API | ntn api ... | curl |
| Construir una sincronización/webhook/herramienta alojada por Notion | ntn workers ... | WSL2 + ntn workers ... |
Notas
- Los ID de página/base de datos son UUID (con o sin guiones — ambos son aceptados).
- Límite de tasa: ~3 solicitudes/segundo en promedio. La CLI no lo evita.
- La API no puede establecer filtros de vista de base de datos — eso es solo de interfaz.
- Usa
"is_inline": trueal crear fuentes de datos para incrustarlas en una página. - Pasa siempre
-sa curl para suprimir las barras de progreso (salida de agente más limpia). - Canaliza JSON a través de
jqal leer:... | jq '.results[0].properties'. - Notion también ofrece un servidor MCP ahora (`Notion
…
[truncado para traducción]