Saltar al contenido principal
SocialCutter

IA y agentes

Adjunta en Airtable las medidas generadas con SocialCutter

Genera los formatos con SocialCutter y adjunta la URL de salida a un campo attachment por la API de Airtable: flujo directo, Python, curl y errores.

  • Airtable
  • attachment
  • API
  • token personal
  • Python
  • curl
  • SocialCutter

Por qué el flujo es directo en Airtable

Un campo de tipo attachment (multipleAttachments) acepta, al escribir, una lista de objetos con url. Airtable descarga el fichero desde esa URL y se queda con su propia copia. Como SocialCutter devuelve una URL pública por cada formato generado, no hace falta subir binarios ni montar ningún intermediario: generas, adjuntas y ya está.

La frontera sigue siendo la misma que en el resto de integraciones: SocialCutter genera imágenes, no publica. El recorte es centrado, sin detección de sujeto ni análisis de contenido. Publicar o adjuntar es del llamante.

Por qué pre-generar antes de adjuntar

Airtable muestra la miniatura del adjunto, pero no recorta la imagen a la proporción que pide cada hueco. Si guardas un solo maestro y lo reutilizas para la miniatura de la galería, el brief de un reel y la portada del registro, cada vista lo escala a su manera.

Hueco en el registroDestino SocialCutterMedida
Miniatura cuadrada de la galeríainstagram post1080x1080 (1:1)
Imagen vertical para un brief de reelinstagram story1080x1920 (9:16)
Tarjeta apaisada o vista de galeríatwitter post1200x675 (16:9)
Portada del registro o de la vistafacebook post1200x630 (1.91:1)
Banner ancho para una cabeceralinkedin cover1128x191 (5.9:1)

Pre-generar las cinco son 5 usos y sale en una única petición, así que el registro queda completo con las medidas ya resueltas.

Cómo escribe la API en un campo attachment

  • Forma de escritura: un array de objetos. Basta url, y filename es opcional pero recomendable para controlar el nombre del adjunto.
  • Airtable descarga el fichero. La URL tiene que ser alcanzable desde fuera, sin login ni firma caducada, y devolver un Content-Type de imagen.
  • Lo que envías es lo que queda. Los adjuntos que no incluyas en el array se eliminan del campo. Para conservarlos, mándalos otra vez con su id: el objeto que devuelve la lectura sirve tal cual.
  • Al leer, las URLs son de v5.airtableusercontent.com y caducan a las dos horas. Son para descargar, no para incrustar en otra web.
  • Límites del plan: hasta 5 GB por fichero, con un almacenamiento por base que va de 1 GB en Free a 1 TB en Enterprise. La referencia completa está en https://airtable.com/developers/web/api/field-model.

Crea el token personal

Entra en https://airtable.com/create/tokens, añade los permisos data.records:write (y schema.bases:read si quieres listar los campos de la tabla) y da acceso a la base concreta. Se envía en la cabecera Authorization: Bearer pat.... Guarda el token y el identificador de la base en variables de entorno, nunca en el código.

Flujo directo con Python

import os
import requests

SC = "https://api.socialcutter.theboomer.dev"
BASE = os.environ["AIRTABLE_BASE_ID"]
TABLE = os.environ["AIRTABLE_TABLE_ID"]

sc = requests.Session()
sc.headers["X-API-Key"] = os.environ["SOCIALCUTTER_API_KEY"]

at = requests.Session()
at.headers["Authorization"] = f"Bearer {os.environ['AIRTABLE_TOKEN']}"

# 1. Generar todos los formatos de una vez
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": "twitter", "format": "post"},
    ],
}, timeout=60)
resp.raise_for_status()
salidas = resp.json()["outputs"]

# 2. Adjuntar las salidas al registro: Airtable descarga y rehospeda
adjuntos = [
    {"url": out["url"], "filename": f"{out['platform']}-{out['format']}.webp"}
    for out in salidas
]

r = at.patch(f"https://api.airtable.com/v0/{BASE}/{TABLE}/{os.environ['RECORD_ID']}",
             json={"fields": {"Adjuntos": adjuntos}}, timeout=60)
r.raise_for_status()
for att in r.json()["fields"]["Adjuntos"]:
    print(att["filename"], att["size"], att["type"])

# 3. Alta de un registro nuevo con la imagen cuadrada ya adjunta
nuevo = at.post(f"https://api.airtable.com/v0/{BASE}/{TABLE}", json={
    "records": [{"fields": {
        "Nombre": "Campana de septiembre",
        "Adjuntos": [{"url": salidas[0]["url"], "filename": "instagram-post.webp"}],
    }}],
}, timeout=60)
nuevo.raise_for_status()

Los endpoints de lote admiten 10 registros por petición, y conviene espaciarlos para no pasar de 5 peticiones por segundo y base.

Flujo directo con curl

curl -s -X PATCH "https://api.airtable.com/v0/$BASE_ID/$TABLE_ID/$RECORD_ID" \
  -H "Authorization: Bearer $AIRTABLE_TOKEN" \
  -H "Content-Type: application/json" \
  -d "{\"fields\":{\"Adjuntos\":[{\"url\":\"$OUTPUT_URL\",\"filename\":\"instagram-post.webp\"}]}}" \
  | python3 -m json.tool

Sustituye $BASE_ID por app..., $TABLE_ID por tbl... y $RECORD_ID por rec.... Para el nombre del campo puedes usar el identificador fld... en lugar del nombre, que es lo más estable si alguien renombra la columna.

Cuando Airtable no puede descargar la URL

Si el campo no se rellena y la respuesta habla de un fallo de subida, casi siempre es que Airtable no ha podido descargar el fichero. Comprueba que la URL es pública, que no depende de una sesión y que devuelve la imagen con su Content-Type. El aviso típico de la interfaz es «Couldn’t upload. Try adding again» y detrás hay un 403 del dominio de subida de Airtable; el soporte lo documenta en https://support.airtable.com/docs/attachment.

Cuando la URL no se puede exponer, queda la subida directa:

curl -s -X POST \
  "https://content.airtable.com/v0/$BASE_ID/$RECORD_ID/$FIELD_ID/uploadAttachment" \
  -H "Authorization: Bearer $AIRTABLE_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{"contentType":"image/webp","file":"<base64>","filename":"instagram-post.webp"}'

Ese endpoint acepta hasta 5 MB por fichero, exactamente el mismo techo que el maestro que admite SocialCutter, así que el respaldo cubre el mismo rango que el flujo por URL.

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 Airtable no se cobra por llamada, pero sí cuenta en el límite mensual de tu plan (1.000 llamadas al mes en Free).

Errores típicos

CódigoOrigenSignificado
400SocialCutterPayload inválido: plataforma o formato desconocido
401SocialCutterFalta la cabecera X-API-Key o la clave no vale
413SocialCutterEl maestro supera 5 MB
429SocialCutterCuota agotada: consulta GET /api/v1/wallet
401AirtableToken ausente, mal formado o sin acceso a esa base
403AirtableAirtable no ha podido descargar la URL del adjunto
404AirtableLa base, la tabla o el registro no existen
422AirtableCampo desconocido o valor que no encaja con el tipo attachment
429AirtableMás de 5 peticiones por segundo y base: espera unos 30 segundos

Siguientes pasos

Preguntas frecuentes

¿Airtable guarda la URL o el fichero?

El fichero. Al escribir una URL en un campo de tipo attachment, Airtable la descarga y rehospeda su propia copia, así que la URL de SocialCutter no tiene que seguir viva después de la escritura.

¿Puedo subir el binario directamente en vez de una URL?

Sí, con el endpoint uploadAttachment, que acepta el fichero en base64 hasta 5 MB. Por encima de ese tamaño hay que pasar por una URL pública, que es justo lo que devuelve SocialCutter.

¿Qué límite tiene la API de Airtable?

5 peticiones por segundo y base en todos los planes, con un máximo de 10 registros por petición en los endpoints de lote. Al pasarte responde 429 y conviene esperar unos 30 segundos antes de reintentar.

¿Qué pasa con los adjuntos que ya había en el campo?

Al escribir, la lista que envías es la que queda: los adjuntos que no incluyas se eliminan. Si quieres conservarlos, mándalos también en el mismo array con su id, tal y como te los devolvió la lectura.

¿Cuánto cuesta preparar los formatos de un registro?

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 API y MCP.