CMS y webs
Sube imágenes a HubSpot con la Files API
Sube las imágenes que genera SocialCutter al File Manager de HubSpot por la Files API, con multipart o desde una URL, y úsalas en correos, landings y redes.
- HubSpot
- Files API
- File Manager
- import-from-url
- scopes
- SocialCutter
- email marketing
Por qué pasar por el File Manager
El File Manager de HubSpot es la biblioteca de medios del portal: todo lo que insertas en correos, páginas, landings y posts de blog se sirve desde ahí, a través del CDN de HubSpot. SocialCutter genera versiones recortadas de forma centrada a las medidas exactas de cada destino y devuelve una URL pública por salida; si esas imágenes van a vivir dentro de HubSpot, conviene subirlas al File Manager en lugar de enlazar URLs externas: así las gestionas y las reutilizas.
La frontera importa: SocialCutter genera imágenes, no publica. HubSpot solo almacena y sirve el fichero.
Requisitos: Private app y scopes
Crea una Private app en Configuración → Integraciones → Private apps y marca los scopes del Files API:
| Scope | Para qué sirve |
|---|---|
files | Leer, subir y archivar ficheros y carpetas |
files.ui_hidden.read | Acceder a ficheros ocultos que no aparecen en el listado público |
El token empieza por pat- y viaja en la cabecera Authorization: Bearer pat-…. La referencia completa de la Files API, con los scopes y campos vigentes, está en https://developers.hubspot.com/docs/api-reference/latest/files/guide.
Subir un fichero por multipart
POST /files/v3/files acepta multipart/form-data. Un fichero por petición:
curl -s -X POST "https://api.hubapi.com/files/v3/files" \
-H "Authorization: Bearer pat-tu_token" \
-F "file=@instagram-post.jpg" \
-F "folderPath=/socialcutter" \
-F 'options={"access":"PUBLIC_INDEXABLE"}'
| Campo | Obligatorio | Descripción |
|---|---|---|
file | Sí | El binario a subir |
folderId o folderPath | Uno de los dos | Carpeta destino; se recomienda no subir a la raíz |
fileName | No | Nombre final; si se omite se genera del contenido |
options | No | JSON con access y, opcionalmente, ttl (de 1 día a 1 año) |
La respuesta 201 trae id, path, url, defaultHostingUrl, access, width, height e isUsableInContent. Guarda el id y la url: son lo que usas después en el editor de correos o en el selector de imágenes.
Subir desde una URL con import-from-url
Cuando SocialCutter ya te devuelve URLs, no hace falta descargar y resubir a mano. HubSpot importa desde una URL de forma asíncrona:
curl -s -X POST "https://api.hubapi.com/files/v3/files/import-from-url/async" \
-H "Authorization: Bearer pat-tu_token" \
-H "Content-Type: application/json" \
-d '{
"url": "https://cdn.socialcutter.theboomer.dev/out/twitter-post.jpg",
"access": "PUBLIC_INDEXABLE",
"folderPath": "/socialcutter",
"duplicateValidationStrategy": "REJECT",
"duplicateValidationScope": "EXACT_FOLDER"
}'
La respuesta 202 devuelve un id de tarea. Consultas el estado con GET /files/v3/files/import-from-url/async/tasks/{taskId}/status, que responde PENDING, PROCESSING, COMPLETE o CANCELED. Con COMPLETE el fichero ya está en el File Manager.
Aviso de versiones: HubSpot ha ido moviendo el Files API a rutas versionadas (de files/v3 a esquemas como files/2026-09), y los nombres de scope han cambiado entre versiones. Antes de fijar rutas en tu código, confirma la ruta y los scopes vigentes en la documentación oficial enlazada arriba.
Niveles de acceso y dónde se puede usar cada fichero
access | ¿Se puede insertar en correos, páginas y landings? |
|---|---|
PUBLIC_INDEXABLE | Sí, y además se puede indexar en buscadores |
PUBLIC_NOT_INDEXABLE | Sí, pero sin indexación |
PRIVATE | No directamente: requiere URL firmada e isUsableInContent es false |
SENSITIVE | No: pensado para datos, no para contenido |
Si la imagen va a un correo o una landing, usa acceso público. Un fichero privado no se renderiza en el correo porque el cliente de email no puede firmar la URL.
Tabla de tamaños recomendados por HubSpot
Estas son medidas orientativas que HubSpot publica para los sitios donde se usan imágenes dentro del portal. Para las medidas exactas que genera SocialCutter por red social, la referencia es la guía interna de medidas (enlazada abajo).
| Ubicación en HubSpot | Tamaño recomendado | Proporción |
|---|---|---|
| Imagen dentro de un correo | 600 px de ancho | Variable (el ancho de plantilla manda) |
| Cabecera de correo | 600x200 | 3:1 |
| Imagen destacada de blog | 1200x628 | ~1.91:1 |
| Imagen para compartir en redes (social share) | 1200x630 | 1.91:1 |
| Miniatura de blog | 400x400 | 1:1 |
| Hero / ancho completo de landing | 1920x1080 (≥1200 px de ancho) | 16:9 |
| Banner del sitio | 2500x625 | 4:1 |
| Imagen de autor | 500x500 | 1:1 |
Fuentes de HubSpot: su guía de medidas para redes (https://blog.hubspot.com/marketing/ultimate-guide-social-media-image-dimensions-infographic) y la de imágenes para web (https://blog.hubspot.com/website/image-size-for-website). Ojo con las diferencias finas: el social share de HubSpot es 1200x630 y su destacada de blog 1200x628; el destino más cercano del catálogo de SocialCutter es facebook + post (1200x630). Si necesitas una medida que no produce el catálogo, recórtala aparte.
Flujo: de SocialCutter al File Manager
- Procesa la maestra:
POST /api/v1/images/processconsourceydestinations. - Recorre el array
outputsy, por cada URL, lanza unimport-from-url/async. - Espera a
COMPLETEpor tarea y recoge laurlfinal. - Inserta esa URL en el correo, la landing o el post de blog.
import time, requests
HUB = {"Authorization": "Bearer pat-tu_token"}
BASE = "https://api.hubapi.com/files/v3/files/import-from-url/async"
def subir(url, folder="/socialcutter"):
r = requests.post(BASE, headers={**HUB, "Content-Type": "application/json"},
json={"url": url, "access": "PUBLIC_INDEXABLE", "folderPath": folder},
timeout=30)
r.raise_for_status()
task = r.json()["id"]
while True:
s = requests.get(f"{BASE}/tasks/{task}/status", headers=HUB, timeout=30).json()
if s.get("status") in ("COMPLETE", "CANCELED"):
return s
time.sleep(2)
for out in outputs: # outputs viene de SocialCutter
print(out["platform"], subir(out["url"]))
Coste
| Concepto | Valor |
|---|---|
| Coste por procesamiento | 1 uso por destino (plataforma y formato) |
| Destinos repetidos en la misma petición | No se cobran dos veces |
| Subida al File Manager de HubSpot | Sin coste adicional, dentro de los límites del portal |
| Planes de SocialCutter | 0, 3, 9 y 29 EUR, con API y MCP incluidos |
Una petición de Instagram post + LinkedIn post + X post consume 3 usos de SocialCutter y produce 3 subidas a HubSpot.
Errores típicos
| Error | Qué pasa realmente | Qué hacer |
|---|---|---|
401/403 al subir | El token no tiene el scope files | Añade el scope en la Private app y regenera el token |
| La imagen no se ve en el correo | Se subió como PRIVATE | Sube con acceso público (PUBLIC_INDEXABLE o PUBLIC_NOT_INDEXABLE) |
400 en el upload por multipart | Falta folderId/folderPath o la carpeta no existe | Crea la carpeta antes, o usa import-from-url, que puede crearla |
429 | Límite de peticiones del portal | Añade reintentos con espera exponencial |
| Nombre duplicado | Ya existe un fichero igual en la carpeta | Usa duplicateValidationStrategy: RETURN_EXISTING o overwrite |
| La URL de destino no importa | HubSpot no pudo descargar la imagen | Comprueba que la URL es pública y accesible sin sesión |
Siguientes pasos
- Guía de la API con curl: Procesa imágenes con la API desde la terminal
- Python: Procesa imágenes con la API de SocialCutter desde Python
- No-code: Automatiza el recorte de imágenes con Zapier, Make o n8n
- Estrategia: Automatizar imágenes para redes sociales: 4 caminos
- Medidas: Medidas de redes sociales: tamaños y proporciones
- Documentación de la API: https://docs.socialcutter.theboomer.dev
Preguntas frecuentes
¿Qué scopes necesita el token de HubSpot?
Para subir ficheros, el scope files. Para leer ficheros ocultos, además files.ui_hidden.read. Se conceden en una Private app del portal y el token empieza por pat-.
¿Puedo subir una imagen directamente desde su URL?
Sí. El endpoint POST /files/v3/files/import-from-url/async descarga la imagen en segundo plano y devuelve una tarea; consultas su estado hasta que ponga COMPLETE. Es la vía natural cuando SocialCutter ya te da una URL pública.
¿Por qué la imagen no se ve en un correo de HubSpot?
Casi siempre porque el fichero se subió con access PRIVATE. Un fichero privado solo se sirve con URL firmada y no es válido para insertarlo en correos o páginas. Para contenido usa acceso público.
¿Cuánto cuesta procesar una imagen con SocialCutter?
1 uso por destino, entendiendo destino como cada combinación de plataforma y formato. HubSpot no cobra por subir al File Manager dentro de los límites del portal.
¿El recorte lo decide HubSpot o SocialCutter?
SocialCutter recorta de forma centrada y determinista antes de subir: no hay detección de sujeto ni de rostros. HubSpot solo almacena y sirve el fichero que le entregas.