# 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.
- URL: https://socialcutter.theboomer.dev/guias/slack/
- Idioma: es
- Familia: ia
- Actualizado: 2026-09-24
- Palabras clave: 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:

```python
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`.

```python
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:

1. **Alguien sube la imagen al canal.** Tu servicio recibe el evento `file_shared` (o `app_mention`).
2. **El bot descarga el fichero.** Con `url_private_download` y el token `xoxb-` en la cabecera `Authorization`.
3. **El bot llama a SocialCutter.** `POST /api/v1/images/process/upload` por multipart, con el binario y la lista de `destinations`.
4. **SocialCutter responde** con `image_id` y un array `outputs`, una URL por destino.
5. **El bot devuelve los formatos al canal**, con `files_upload_v2` por salida o con un bloque `image`.

```python
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](/guias/python/)
- Node.js: [Procesa imágenes con la API de SocialCutter desde Node.js](/guias/node/)
- MCP: [Usa SocialCutter desde tu LLM o editor con MCP](/guias/mcp/)
- No-code: [Automatiza el recorte con Zapier](/guias/zapier/) o [n8n](/guias/n8n/)
- Estrategia: [Automatizar imágenes para redes sociales: 4 caminos](/guias/automatizar-imagenes-redes-sociales/)
- Medidas: [Medidas de redes sociales: tamaños y proporciones](/guias/medidas-redes-sociales/)
- Documentación de la API: https://docs.socialcutter.theboomer.dev