CMS y webs
Sube imágenes a la mediateca de Strapi con SocialCutter
Sube la imagen a la mediateca de Strapi por POST /api/upload con una petición multipart y úsala en tus entradas a su medida.
- Strapi
- mediateca
- Media Library
- api/upload
- multipart
- token de API
- relación media
- Node
Por qué generar los tamaños antes de subir
Una entrada de blog o una ficha de producto enseña la misma imagen en cuatro sitios: la tarjeta del listado, la cabecera del artículo, la tarjeta de Open Graph y la miniatura de una red social. Cada hueco pide una proporción distinta. Si subes el maestro y dejas que cada hueco lo recorte con CSS, el resultado depende del navegador y de la pantalla.
El flujo es: un maestro entra, SocialCutter devuelve cada medida y la mediateca de Strapi recibe el fichero ya recortado. El recorte del modo cover (el que se aplica por defecto) es centrado: escala la imagen y reparte el sobrante por igual a los dos lados. No hay detección de sujeto ni ningún paso que decida qué parte sobra.
| Hueco en Strapi | Destino SocialCutter | Medida |
|---|---|---|
| Imagen destacada de la entrada | linkedin post | 1200x627 (1.91:1) |
| Imagen dentro del contenido | facebook post | 1200x630 (1.91:1) |
| Tarjeta social (Open Graph) | twitter post | 1200x675 (16:9) |
| Cabecera del sitio | twitter header | 1500x500 (3:1) |
| Ficha de producto en 1:1 | instagram post | 1080x1080 (1:1) |
| Segunda imagen vertical | instagram story | 1080x1920 (9:16) |
El catálogo completo de plataformas y formatos sale de GET /api/v1/platforms, que es público, y está resumido en la guía de medidas por red social.
Qué hace Strapi por su cuenta (y qué no)
El plugin de subida de Strapi genera puntos de ruptura: thumbnail, small, medium y large. Son reescalados que conservan la proporción del original, no recortes a una proporción concreta. Una foto 3:2 sigue siendo 3:2 en los cuatro. Por eso no sustituyen a un recorte por plataforma: sirven para no descargar 4000 px en el móvil, no para llenar un hueco 1:1 o 9:16.
Tampoco hay un 4:5 en el catálogo de SocialCutter: lo vertical es 9:16 (1080x1920) y lo cuadrado es 1:1 (1080x1080). Si necesitas 4:5 exacto, recorta fuera.
Antes de empezar: token, permisos y versión
Token de API. En el panel de Strapi, Settings → API Tokens permite crear un token con tipo Full access, Read-only o Custom. El valor se muestra una sola vez y viaja en la cabecera Authorization: Bearer.
Permisos. Un token de tipo Custom lleva la misma matriz de permisos que un rol: hay que concederle la acción de subida del plugin upload y, si en la misma llamada editas la entrada, la acción de edición del tipo de contenido (update). Con Full access no hace falta marcar nada. Referencia: https://docs.strapi.io/cms/features/api-tokens
Versión. Strapi publica versiones mayores con cambios de formato en la API REST, así que fija la que usas y revisa la documentación antes de subir de una 4 a una 5:
| Detalle | Strapi 4 | Strapi 5 |
|---|---|---|
| Formato de respuesta REST | data.attributes | campos aplanados sobre data |
| Referencia de una entrada | id numérico | documentId |
| Subida de ficheros | POST /api/upload (FormData) | POST /api/upload (FormData) |
export STRAPI_URL="https://tu-strapi.com"
export STRAPI_TOKEN="tu_token_de_api"
export SC_KEY="sc_tu_clave"
1. Procesa el maestro con SocialCutter
curl -s -X POST "https://api.socialcutter.theboomer.dev/api/v1/images/process" \
-H "X-API-Key: *** \
-H "Content-Type: application/json" \
-d '{
"source": { "type": "url", "value": "https://tu-cdn.com/maestro.jpg" },
"destinations": [
{ "platform": "linkedin", "format": "post" },
{ "platform": "instagram", "format": "post" }
]
}' > sc.json
jq '.image_id, (.outputs[] | {url, platform, format, width, height})' sc.json
La respuesta trae image_id y una URL por destino. Si el maestro solo existe en tu disco, usa POST /api/v1/images/process/upload (multipart, máximo 5 MB).
2. Sube la imagen a la mediateca
POST /api/upload es multipart y el único campo obligatorio es files. Acepta varias entradas en la misma petición y devuelve un objeto por fichero con id, url y el bloque formats.
curl -s -o linkedin.jpg "$(jq -r '.outputs[0].url' sc.json)"
curl -s -X POST "$STRAPI_URL/api/upload" \
-H "Authorization: Bearer $STRAPI_TOKEN" \
-F "files=@linkedin.jpg" > media.json
jq '.[0] | {id, url, mime, width, height}' media.json
En Node (18 o superior) hay FormData y Blob globales, así que no hace falta ninguna dependencia para el multipart. El truco es descargar la salida como Blob y colgarla del formulario con un nombre de fichero:
const SC_KEY = process.env.SC_KEY
const STRAPI_URL = process.env.STRAPI_URL
const STRAPI_TOKEN = process.env.STRAPI_TOKEN
async function processMaster(masterUrl) {
const res = await fetch('https://api.socialcutter.theboomer.dev/api/v1/images/process', {
method: 'POST',
headers: { 'X-API-Key': SC_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({
source: { type: 'url', value: masterUrl },
destinations: [{ platform: 'linkedin', format: 'post' }]
})
})
if (!res.ok) throw new Error(`SocialCutter ${res.status}`)
return res.json()
}
async function uploadToMediaLibrary(imageUrl, filename) {
const bin = await fetch(imageUrl)
const blob = await bin.blob()
const form = new FormData()
form.append('files', blob, filename)
const res = await fetch(`${STRAPI_URL}/api/upload`, {
method: 'POST',
headers: { Authorization: `Bearer ${STRAPI_TOKEN}` },
body: form
})
if (!res.ok) throw new Error(`Strapi upload ${res.status}`)
const [file] = await res.json()
return file // { id, documentId?, url, formats }
}
Documentación del endpoint: https://docs.strapi.io/cms/api/rest/upload
3. Enlaza la imagen con la entrada
Hay dos caminos y ninguno necesita un plugin.
En la misma subida. /api/upload acepta ref (el UID del tipo de contenido), refId (la referencia de la entrada, documentId en Strapi 5) y field (el nombre del campo de media). El fichero nace ya enlazado:
curl -s -X POST "$STRAPI_URL/api/upload" \
-H "Authorization: Bearer $STRAPI_TOKEN" \
-F "files=@linkedin.jpg" \
-F "ref=api::article.article" \
-F "refId=abc123xyz" \
-F "field=cover"
En una segunda llamada. Sube primero, guarda el id del fichero y edita la entrada. Para un campo de media simple se manda el id; para uno múltiple, un array de ids. La forma del cuerpo depende de la versión: el envoltorio data es el mismo, pero el formato de la respuesta no.
FILE_ID=$(jq -r '.[0].id' media.json)
curl -s -X PUT "$STRAPI_URL/api/articles/abc123xyz?populate=cover" \
-H "Authorization: Bearer $STRAPI_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"data\": {\"cover\": $FILE_ID}}"
Con ?populate=cover la respuesta trae el objeto de media completo y puedes comprobar que el id coincide.
Coste
- 1 uso por destino (plataforma y formato) por petición; los repetidos no se cobran dos veces.
- Los procesamientos fallidos se devuelven.
- Planes 0/3/9/29 EUR, todos con API y MCP.
Errores típicos
| Síntoma | Causa | Solución |
|---|---|---|
403 en /api/upload | El token no tiene la acción de subida | Concede el permiso del plugin upload o usa un token Full access |
401 de Strapi | Token ausente, mal copiado o revocado | Manda Authorization: Bearer con un token activo |
400 «files is required» | Se envió JSON en vez de multipart | Usa -F en curl o FormData en Node, con el campo files |
| La entrada guarda la URL, no la imagen | Se envió una cadena en el campo de media | Envía el id del fichero, no la URL |
413 en SocialCutter | El maestro pasa de 5 MB | Reduce el maestro antes de subirlo |
429 en SocialCutter | Cuota del monedero agotada | Consulta GET /api/v1/credits o sube de plan |
Sin código
Un automatizador encadena los mismos pasos con nodos: disparador, nodo HTTP a /api/v1/images/process y un nodo HTTP a /api/upload con el fichero en multipart. El patrón general está en la guía de automatización de imágenes para redes sociales.
Siguientes pasos
- WordPress y WooCommerce: Integra SocialCutter con WordPress y WooCommerce
- Shopify: Integra SocialCutter con la Admin API de Shopify
- Terminal: Procesa imágenes con la API desde la terminal (curl)
- Automatización: Automatiza el recorte de imágenes con n8n
- Documentación: https://docs.socialcutter.theboomer.dev
Preguntas frecuentes
¿Por qué no dejo que Strapi redimensione la imagen que subo?
Strapi genera puntos de ruptura (thumbnail, small, medium, large) que escalan el maestro manteniendo su proporción. No recorta a las proporciones exactas de cada red social, así que una foto 3:2 sigue siendo 3:2 en todos esos tamaños y no sirve como post 1:1 ni como story 9:16. SocialCutter sí devuelve cada medida exacta antes de subir.
¿Qué permisos necesita el token de API?
El token debe poder usar el plugin de subida (la acción de subida del plugin upload) y, si además actualizas la entrada en la misma operación, el permiso de edición del tipo de contenido. Con un token de tipo Full access funciona; con uno Custom hay que marcar esas acciones a mano.
¿Se vincula la imagen a la entrada al subirla o en una segunda llamada?
Las dos formas valen. POST /api/upload acepta los campos ref, refId y field para crear el fichero y enlazarlo en la misma petición. Si prefieres subir primero y enlazar después, guarda el id del fichero y edita la entrada con el campo de media.
¿Qué cambia entre Strapi 4 y Strapi 5?
Sobre todo el formato de las respuestas REST. Strapi 4 envuelve los campos en data.attributes y usa un id numérico; Strapi 5 aplana los campos sobre el objeto, usa documentId como referencia estable y en el endpoint de subida devuelve ese documentId además del id. El endpoint de subida sigue siendo POST /api/upload con FormData en ambos.
¿Cuánto cuesta procesar la imagen de una entrada?
1 uso por destino, es decir por cada combinación de plataforma y formato. Pedir Instagram post y LinkedIn post para el mismo maestro son 2 usos.