IA y agentes
Guarda en Notion las medidas generadas con SocialCutter
Genera cada formato con SocialCutter y llévalo a Notion con una URL externa o la File Upload API: límites de alojamiento, versiones y snippet en Python.
- Notion
- File Upload API
- base de datos
- imagen externa
- Python
- SocialCutter
- automatización
La frontera: SocialCutter genera, Notion guarda
SocialCutter recibe una imagen, la recorta de forma centrada a las medidas exactas de cada destino y devuelve una URL por salida. El recorte es centrado y sin detección de sujeto: no hay ningún análisis de contenido que decida qué parte sobra. Tampoco publica ni escribe en Notion.
Así que la integración tiene dos mitades bien separadas: generar los ficheros con la medida correcta y decidir dónde los guardas. Esta guía cubre la segunda con la API de Notion.
Por qué pre-generar antes de llevarlo a Notion
Notion escala las imágenes para que encajen en la caja donde las pones; no las recorta a una proporción concreta. Si subes el mismo maestro a un bloque vertical, a una portada ancha y a la miniatura de una tabla, el resultado depende por completo del contenedor.
| Hueco en Notion | Destino SocialCutter | Medida |
|---|---|---|
| Portada de página o cabecera del post | facebook post | 1200x630 (1.91:1) |
| Imagen cuadrada de una galería | instagram post | 1080x1080 (1:1) |
| Bloque vertical, story o reel | instagram story | 1080x1920 (9:16) |
| Miniatura apaisada de tabla o tarjeta | twitter post | 1200x675 (16:9) |
| Cabecera ancha de página | twitter header | 1500x500 (3:1) |
Pre-generar los cinco son 5 usos y sale en una sola petición, en lugar de rehacer la imagen cada vez que cambia la plantilla de la página.
Las dos vías para que una imagen acabe en Notion
| Vía | Objeto | Qué guarda Notion | Cuándo usarla |
|---|---|---|---|
| URL externa | external | Solo la URL, sin copia del fichero | La imagen vive en tu CDN o en SocialCutter y no necesita permisos |
| File Upload API | file_upload | Una copia en el almacenamiento del workspace | La imagen tiene que quedar dentro de Notion |
Los ficheros que arrastras a mano en la interfaz son de tipo file y también consumen almacenamiento del workspace, que va contra la cuota de tu plan de Notion.
Vía 1: la URL de salida como imagen externa
Es el camino corto: escribes la URL en una propiedad de tipo URL de una base de datos o la usas en un bloque de imagen.
curl -s -X PATCH "https://api.notion.com/v1/blocks/$PAGE_ID/children" \
-H "Authorization: Bearer $NOTION_TOKEN" \
-H "Notion-Version: 2022-06-28" \
-H "Content-Type: application/json" \
-d "{\"children\":[{\"object\":\"block\",\"type\":\"image\",\"image\":{\"type\":\"external\",\"external\":{\"url\":\"$OUTPUT_URL\"}}}]}"
Ventaja: cero bytes en el almacenamiento de Notion y la misma URL sirve para el CMS, la red social o el correo. Coste: si la URL caduca o se retira el maestro, la imagen desaparece de la página.
Vía 2: la File Upload API
Tres pasos, tal y como los documenta Notion:
POST /v1/file_uploadscrea el objeto en estadopendingy devuelve unupload_url. Esto permite reservar el hueco antes de tener el fichero en la mano.- Envía el contenido a ese
upload_urlconContent-Type: multipart/form-datay el fichero en el campofile. - Usa el
iddel fichero subido en un bloqueimagede tipofile_uploado en una propiedad de ficheros.
El modo single_part (el de por defecto) admite hasta 20 MB. Por encima hay que usar multi_part, que trocea en partes de 5 a 20 MB y llega hasta 5 GB en workspaces de pago. Como SocialCutter acepta maestros de 5 MB como máximo, las salidas caben siempre en la vía simple. El fichero hay que adjuntarlo dentro de la hora siguiente a crearlo o caduca.
Snippet en Python
import os
import requests
SC = "https://api.socialcutter.theboomer.dev"
NOTION = "https://api.notion.com/v1"
NOTION_VERSION = os.environ.get("NOTION_VERSION", "2022-06-28")
sc = requests.Session()
sc.headers["X-API-Key"] = os.environ["SOCIALCUTTER_API_KEY"]
nt = requests.Session()
nt.headers.update({
"Authorization": f"Bearer {os.environ['NOTION_TOKEN']}",
"Notion-Version": NOTION_VERSION,
})
# 1. Una peticion a SocialCutter, una URL por destino
resp = sc.post(f"{SC}/api/v1/images/process", json={
"source": {"type": "url", "value": "https://example.com/maestro.jpg"},
"destinations": [
{"platform": "instagram", "format": "post"},
{"platform": "instagram", "format": "story"},
{"platform": "facebook", "format": "post"},
],
}, timeout=60)
resp.raise_for_status()
salidas = resp.json()["outputs"]
# 2. Una pagina en una base de datos con una propiedad URL por destino
props = {"Nombre": {"title": [{"text": {"content": "Campana de septiembre"}}]}}
for out in salidas:
props[f"{out['platform']}-{out['format']}"] = {"url": out["url"]}
pagina = nt.post(f"{NOTION}/pages", json={
"parent": {"database_id": os.environ["NOTION_DB_ID"]},
"properties": props,
}, timeout=30)
pagina.raise_for_status()
print(pagina.json()["id"])
# 3. Alternativa: subir el fichero y adjuntarlo como imagen de la pagina
def subir_a_notion(url, nombre, content_type):
up = nt.post(f"{NOTION}/file_uploads", json={
"mode": "single_part", "filename": nombre, "content_type": content_type,
}, timeout=30)
up.raise_for_status()
fichero = sc.get(url, timeout=60).content
envio = requests.post(up.json()["upload_url"], headers={
"Authorization": nt.headers["Authorization"],
"Notion-Version": NOTION_VERSION,
}, files={"file": (nombre, fichero, content_type)}, timeout=120)
envio.raise_for_status()
return up.json()["id"]
primer = salidas[0]
fid = subir_a_notion(primer["url"], f"{primer['platform']}-{primer['format']}.webp", "image/webp")
nt.patch(f"{NOTION}/blocks/{pagina.json()['id']}/children", json={
"children": [{"object": "block", "type": "image",
"image": {"type": "file_upload", "file_upload": {"id": fid}}}],
}, timeout=30).raise_for_status()
Los nombres de las propiedades dependen de tu base de datos: la propiedad de título y las propiedades de tipo URL hay que crearlas antes, o usar los identificadores de campo en lugar de los nombres.
Los límites de alojamiento de Notion
- Notion no es un CDN. Las imágenes que subes cuentan en el almacenamiento de tu workspace, que va por plan.
- Una imagen
externalno se copia: Notion guarda la referencia y la carga desde fuera cada vez. - Las URLs de los ficheros alojados por Notion son temporales (una hora). No las guardes en caché ni las incrustes en otra web.
- Las URLs de petición admiten hasta 2000 caracteres, de modo que una URL de salida con firma larga entra sin problema.
- Si la imagen tiene que sobrevivir a la retirada del maestro, sube el fichero con la File Upload API en lugar de enlazarlo.
Las versiones de la API de Notion
El encabezado Notion-Version es obligatorio en todas las llamadas y es lo que fija el contrato. La API evoluciona: los ejemplos que sirve la documentación usan 2022-06-28, y las versiones más recientes introducen el data source como destino al crear una página dentro de una base de datos, en lugar del database_id. Si fijas una versión y la subes sin revisar el cuerpo de la petición, la creación de páginas es lo primero que rompe.
Fija la versión en una variable de entorno, como en el snippet, y consulta la referencia antes de migrar: https://developers.notion.com/reference/file-upload.
Los límites de peticiones son de Notion, no de SocialCutter: 180 peticiones por minuto por conexión en los planes estándar (una media de 3 por segundo) y 600 por minuto en Business y Enterprise. Al pasarte responde 429 con el código rate_limited, así que respeta el valor de Retry-After en lugar de reintentar en bucle.
Coste
- 1 uso por destino (plataforma y formato) por petición a SocialCutter. Los destinos repetidos no se cobran dos veces y los procesamientos fallidos se devuelven.
- Planes: 0 EUR (3 usos/día), 3 EUR (10/día), 9 EUR (30/día) y 29 EUR (100/día), todos con API y MCP.
- La API de Notion no se factura por llamada: cuenta contra los límites de tu plan de Notion.
Errores típicos
| Código | Origen | Significado |
|---|---|---|
| 400 | SocialCutter | Payload inválido: plataforma o formato desconocido |
| 401 | SocialCutter | Falta la cabecera X-API-Key o la clave no vale |
| 413 | SocialCutter | El maestro supera 5 MB |
| 429 | SocialCutter | Cuota agotada: consulta GET /api/v1/wallet |
400 validation_error | Notion | Cuerpo mal formado, versión incompatible o un parámetro fuera de límite |
401 unauthorized | Notion | El token de la integración no es válido |
403 restricted_resource | Notion | La integración no tiene acceso a esa página o base de datos: hay que compartirla |
404 object_not_found | Notion | El identificador de página, bloque o base de datos no existe |
429 rate_limited | Notion | Demasiadas peticiones: espera lo que marque Retry-After |
Siguientes pasos
- Camino con código: Procesa imágenes con la API de SocialCutter desde Python
- Terminal: Procesa imágenes con la API desde la terminal (curl)
- Sin código: Automatiza el recorte de imágenes con Zapier y Automatiza el recorte de imágenes con Make
- Panorama: Automatizar imágenes para redes sociales: los 4 caminos
- Referencia de la API de SocialCutter: https://docs.socialcutter.theboomer.dev
- File Upload API de Notion: https://developers.notion.com/reference/file-upload
Preguntas frecuentes
¿SocialCutter sube las imágenes a Notion?
No. Genera los ficheros con las medidas exactas de cada destino y devuelve una URL por salida. Subir a Notion es del llamante: con una URL externa o con la File Upload API.
¿Notion copia el fichero si uso una URL?
No. Un fichero de tipo external es solo la referencia a esa URL y Notion no descarga nada, así que si la URL deja de responder la imagen desaparece de la página aunque el bloque siga ahí.
¿Cuánto duran las URLs de los ficheros que aloja Notion?
Son temporales: la referencia oficial indica una validez de una hora y recomienda no cachearlas. Vuelve a pedir el objeto del fichero para refrescar la URL en lugar de tratarla como un CDN.
¿Qué valor pongo en Notion-Version?
Uno fijo, el que corresponda a tu integración, y lo cambias cuando migres. El encabezado es obligatorio y la API cambia entre versiones: en las recientes la pertenencia a una base de datos pasa por el data source.
¿Cuánto cuesta preparar los formatos de una página?
1 uso por destino, es decir por cada combinación de plataforma y formato. Los planes son 0, 3, 9 y 29 EUR al mes e incluyen acceso a la API y al servidor MCP.