IA y agentes
Sube imágenes a Slack con files.uploadV2
Sube imágenes a Slack con files.uploadV2 o compártelas por URL, y encadena SocialCutter para responder con los formatos listos.
- Slack
- files.uploadV2
- files:write
- Block Kit
- bot
- SocialCutter
- Python
Qué resuelve
Slack es donde el equipo comparte imágenes antes de publicarlas. Un bot puede aprovechar ese momento: alguien suelta la imagen en el canal, el bot la recorta de forma centrada a las medidas de cada red y responde con los ficheros ya listos. La pieza para subir imágenes a Slack es files.uploadV2, y la pieza para generar los formatos es SocialCutter. Esta guía cubre las dos y cómo encadenarlas.
Requisitos: app, bot y scopes
| Scope | Para qué |
|---|---|
files:write | Subir, editar y borrar ficheros |
chat:write | Publicar mensajes y compartir por URL |
files:read | Leer metadatos (files.info, files.list), solo si los necesitas |
El bot usa un token xoxb-. Debe estar invitado al canal donde va a publicar; si no, recibirás not_in_channel. Referencias oficiales: https://docs.slack.dev/messaging/working-with-files y https://docs.slack.dev/reference/scopes/files.write.
Subir un fichero con files.uploadV2
files.upload está retirado. En su lugar, Slack pide la secuencia files.getUploadURLExternal y files.completeUploadExternal. Las librerías oficiales la envuelven en un método «v2», así que no tienes que orquestar los dos pasos a mano:
from slack_sdk import WebClient
client = WebClient(token="xoxb-tu_token")
client.files_upload_v2(
channel="C0123456789",
file="./instagram-post.jpg",
title="Instagram 1:1",
filename="instagram-post.jpg",
alt_text="Creatividad para el feed de Instagram",
initial_comment="Formato listo para Instagram",
)
| Parámetro | Para qué |
|---|---|
channel | Canal donde se comparte el fichero |
file / content | Ruta del fichero o bytes en memoria |
filename | Nombre con extensión |
title | Título visible del fichero |
initial_comment | Mensaje que acompaña al fichero |
alt_text | Texto alternativo para accesibilidad |
Aviso de versiones: Slack retiró files.upload y recomienda la secuencia de dos pasos; además, el comportamiento de los métodos de ficheros ha ido cambiando. Comprueba la documentación vigente en el changelog oficial antes de fijar una implementación: https://docs.slack.dev/changelog/2024-04-a-better-way-to-upload-files-is-here-to-stay.
Compartir por URL con Block Kit
Si ya tienes una URL pública (SocialCutter devuelve una por destino), no necesitas subirla a Slack: puedes mostrarla con un bloque image dentro de chat.postMessage. Este camino solo requiere chat:write.
client.chat_postMessage(
channel="C0123456789",
blocks=[
{"type": "image", "image_url": out["url"], "alt_text": f"{out['platform']} {out['format']}"},
{"type": "context", "elements": [{"type": "mrkdwn", "text": f"{out['width']}x{out['height']} listo para publicar"}]},
],
)
La pega: el bloque image carga la imagen desde Slack y necesita una URL accesible sin autenticación. Si el destino exige sesión o caduca rápido, sube el fichero con files.uploadV2 en lugar de enlazarlo. Como referencia general de bloques, consulta la documentación oficial de Block Kit: https://docs.slack.dev/block-kit.
Encadenar SocialCutter: el bot que responde con los formatos
El flujo completo:
- Alguien sube la imagen al canal. Tu servicio recibe el evento
file_shared(oapp_mention). - El bot descarga el fichero. Con
url_private_downloady el tokenxoxb-en la cabeceraAuthorization. - El bot llama a SocialCutter.
POST /api/v1/images/process/uploadpor multipart, con el binario y la lista dedestinations. - SocialCutter responde con
image_idy un arrayoutputs, una URL por destino. - El bot devuelve los formatos al canal, con
files_upload_v2por salida o con un bloqueimage.
import requests
from slack_sdk import WebClient
SLACK_TOKEN = "xoxb-tu_token"
SC_KEY = "sc_tu_clave"
client = WebClient(token=SLACK_TOKEN)
def procesar_fichero(file_id, channel):
# 1. Metadatos y descarga con el token del bot
info = client.files_info(file=file_id)["file"]
img = requests.get(info["url_private_download"],
headers={"Authorization": f"Bearer {SLACK_TOKEN}"}, timeout=30)
img.raise_for_status()
# 2. Pide los formatos a SocialCutter
r = requests.post(
"https://api.socialcutter.theboomer.dev/api/v1/images/process/upload",
headers={"X-API-Key": SC_KEY},
files={"file": ("original.jpg", img.content, "image/jpeg")},
data={"destinations": '[{"platform":"instagram","format":"post"},'
'{"platform":"twitter","format":"post"},'
'{"platform":"tiktok","format":"cover"}]'},
timeout=60,
)
r.raise_for_status()
outputs = r.json()["outputs"]
# 3. Devuelve cada formato al canal
for out in outputs:
fichero = requests.get(out["url"], timeout=30)
client.files_upload_v2(
channel=channel,
content=fichero.content,
filename=f"{out['platform']}-{out['format']}.jpg",
title=f"{out['platform']} {out['format']} ({out['width']}x{out['height']})",
initial_comment=f"Listo para {out['platform']}",
)
Detalles honestos sobre el resultado: el recorte es centrado y determinista; no hay detección de sujeto ni de rostros. Si tu imagen tiene el motivo descentrado, revisa el encuadre antes de publicar. Y SocialCutter no publica en Instagram, X o TikTok: entrega ficheros. Slack recibe las versiones; publicar es otro paso.
El file_shared trae el file_id y el channel_id; los campos exactos del payload del evento pueden variar entre versiones de la Events API, así que valida el evento contra la documentación oficial de Slack antes de depender de un campo concreto.
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 de ficheros a Slack | Sin coste por API, dentro de los límites del workspace |
| Planes de SocialCutter | 0, 3, 9 y 29 EUR, con API y MCP incluidos |
El bot del ejemplo pide tres destinos: consume 3 usos por cada imagen que llegue al canal y devuelve tres ficheros.
Errores típicos
| Error | Qué pasa realmente | Qué hacer |
|---|---|---|
invalid_auth | El token no es válido o está revocado | Reinstala la app y usa el xoxb- vigente |
missing_scope | Falta files:write o chat:write | Añade el scope, reinstala y reinicia el bot |
not_in_channel | El bot no está en el canal destino | Invítalo con /invite |
file_not_found | El file_id no existe o el bot no lo ve | Comprueba el scope files:read y el id |
El bloque image no se ve | La URL no es pública o redirige a un login | Sube el fichero con files.uploadV2 |
413 al procesar | La imagen supera los 5 MB | Comprime la maestra o sirve una versión más ligera |
| El fichero se ve borroso en Slack | Se subió un recorte pequeño y se amplía en pantalla | Parte de una maestra mayor para ese destino |
Siguientes pasos
- Python: Procesa imágenes con la API de SocialCutter desde Python
- Node.js: Procesa imágenes con la API de SocialCutter desde Node.js
- MCP: Usa SocialCutter desde tu LLM o editor con MCP
- No-code: Automatiza el recorte con Zapier 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 bot?
files:write para subir ficheros, chat:write para publicar mensajes y files:read si además lees metadatos de ficheros existentes. El token de bot empieza por xoxb-.
¿Sigue sirviendo files.upload?
No conviene. Slack retiró files.upload en favor de la secuencia getUploadURLExternal más completeUploadExternal. Las librerías oficiales lo envuelven en el método uploadV2, que es el que debes usar.
¿Cómo comparto una imagen sin descargarla a Slack?
Con un bloque image de Block Kit dentro de chat.postMessage, apuntando a una URL pública. Necesita solo chat:write, pero la imagen debe ser accesible sin autenticación.
¿Cuánto cuesta el bot que procesa las imágenes?
Cada procesamiento de SocialCutter consume 1 uso por destino. Slack no cobra por subir ficheros dentro de los límites del plan del workspace.
¿El bot publica en las redes sociales?
No. SocialCutter genera los ficheros con las medidas correctas y los devuelve como URLs; el bot los sube a Slack. Publicar en la red social es un paso aparte.