Glosario

El flujo de subida de medios INIT APPEND FINALIZE de la API de X, paso a paso

Taras Shynkarenko
Taras Shynkarenko
•Actualizado: •9 min de lectura
El flujo de subida de medios INIT APPEND FINALIZE de la API de X en tres endpointsEl flujo de subida de medios INIT APPEND FINALIZE de la API de X en tres endpoints

TL;DR, Respuesta Rápida

9 min de lectura

La subida de vídeo por fragmentos en X v2 son cuatro llamadas: POST /2/media/upload/initialize devuelve un media id, POST /2/media/upload/{id}/append recibe cada fragmento con un segment_index, POST /2/media/upload/{id}/finalize cierra la sesión, y GET /2/media/upload?command=STATUS sondea processing_info hasta que state sea succeeded o failed. Los antiguos parámetros command=INIT y command=APPEND han desaparecido de todo salvo de ese GET de estado. segment_index tiene un tope de 999 y X recomienda fragmentos de 5 MB, lo que no llega a los 16 GB de total_bytes que acepta el esquema de initialize.

¿Qué es el flujo de subida de medios INIT APPEND FINALIZE de la API de X?

Cuatro llamadas componen el flujo de subida de medios INIT APPEND FINALIZE de la API de X: tres POST que mueven el archivo y un GET que informa de lo que X hizo después con él. X las lista en ese orden en la guía de subida por fragmentos.

  1. INIT, POST /2/media/upload/initialize, que X describe como "start the session and get a media_id"
  2. APPEND, POST /2/media/upload/{id}/append, "upload each chunk"
  3. FINALIZE, POST /2/media/upload/{id}/finalize, "complete the upload"
  4. STATUS, GET /2/media/upload, "wait for processing when processing_info is returned"

Los nombres de los comandos sobrevivieron al salto a v2, el transporte no. X pone el aviso justo debajo de la lista: "Do not send command=INIT, command=APPEND, or command=FINALIZE to POST /2/media/upload. Those command-style parameters were the previous upload protocol. The v2 flow uses the dedicated paths above. command=STATUS is still used only on the status GET."

Así que uno de los cuatro comandos sigue existiendo como parámetro de consulta y tres no. El código escrito contra v1.1 falla en los tres POST y sigue funcionando en el sondeo, que es una forma confusa de romperse.

Las cuatro llamadas están detrás del mismo scope de OAuth 2.0, media.write, incluido el GET de estado. Leer el estado de procesamiento de tu propia subida necesita un scope de escritura, y X no publica ninguna alternativa de solo lectura.

¿Qué envía y qué devuelve cada paso?

Cada paso lleva parámetros distintos, y solo dos de los cuatro devuelven algo que te quedes.

PasoEndpointQué envíasQué recibes
INITPOST /2/media/upload/initializemedia_type, total_bytes, media_category, additional_owners y shared opcionalesid, media_key, expires_after_secs
APPENDPOST /2/media/upload/{id}/appendmedia y segment_indexexpires_at
FINALIZEPOST /2/media/upload/{id}/finalizenada salvo el id de la rutaid, media_key, size, expires_after_secs, processing_info
STATUSGET /2/media/upload?command=STATUS&media_id=media_id, command opcionalid, media_key, size, processing_info, video o image

INIT recibe un cuerpo JSON, no campos de formulario, y X lo dice en la guía: "Send a JSON body, not multipart form fields." El enum de media_type va desde video/mp4 y video/quicktime, pasando por text/srt y text/vtt, hasta dos formatos 3D en los que casi nadie repara, model/gltf-binary y model/vnd.usdz+zip. El campo total_bytes tiene un techo duro de esquema de 17179869184, que son 16 GiB.

{
  "data": {
    "id": "1880028106020515840",
    "media_key": "13_1880028106020515840",
    "expires_after_secs": 86400
  }
}

Ese expires_after_secs de 86400 del propio ejemplo de X es el reloj de la sesión: un día desde INIT para adjuntar el medio terminado a algo. El id encaja con el patrón ^[0-9]{1,19}$, y el media_key le antepone un número de tipo y un guion bajo, la misma forma 13_ que documenta la Ads API cuando llama al valor id de vídeo.

APPEND es el único paso cuya respuesta no te dice nada útil sobre el medio. Su esquema tiene un solo campo, expires_at, descrito como "Epoch seconds when the upload session expires." Todos los demás pasos informan de la vida restante de la sesión como expires_after_secs, una cuenta relativa. APPEND la informa como marca de tiempo absoluta. El mismo dato, dos unidades, tres grafías de campo repartidas en cuatro endpoints.

FINALIZE es la solicitud más vacía del flujo. Recibe el id de la ruta y nada más, sin cuerpo y sin parámetros de consulta, y por eso el curl entero cabe en dos líneas:

curl -X POST "https://api.x.com/2/media/upload/1880028106020515840/finalize" \
  -H "Authorization: Bearer $USER_ACCESS_TOKEN"

En su respuesta está la bifurcación de verdad. X pone la regla en una frase: "If processing_info is returned, proceed to Step 4 to wait for processing. If not, the media is ready to use." Una imagen suele saltarse el paso cuatro. Un vídeo nunca.

Una persona graba vídeo con el móvil, el tipo de archivo que se divide en fragmentos para subirlo.

¿Cómo funciona segment_index?

segment_index es un contador simple que llevas tú, empieza en cero, y el esquema fija sus dos extremos: "minimum: 0, maximum: 999."

La indicación de X sobre el tamaño de fragmento está en la guía y no en el esquema: "Keep each segment at or below 5 MB (the server maximum is 8 MB). Segments are indexed from 0." El ejemplo en Python de esa misma guía lee el archivo en bloques de 4 MB e incrementa el índice tras cada llamada con éxito.

curl -X POST "https://api.x.com/2/media/upload/1880028106020515840/append" \
  -H "Authorization: Bearer $USER_ACCESS_TOKEN" \
  -F "segment_index=0" \
  -F "media=@/path/to/chunk0.mp4"

El cuerpo puede ser multipart form data como arriba o JSON, porque el esquema de la solicitud está registrado para los dos tipos de contenido. En JSON el campo media recibe base64. En multipart recibe bytes en bruto.

Ahora multiplica los dos techos publicados. Mil segmentos al máximo de servidor de 8 MB son 8 GB. Mil segmentos a los 5 MB recomendados son 5 GB. Mientras tanto, POST /2/media/upload/initialize acepta total_bytes de hasta 16 GiB, y X afirma sin rodeos que una cuenta con X Premium o verificada puede subir un vídeo de 16 GB a un Post. Esos dos hechos no pueden cumplirse a la vez con APPEND tal como está documentado, y X no publica ningún tamaño de segmento mayor, ninguna ruta alternativa ni ninguna nota que diga que el tope de 999 se mueve para archivos grandes. Todo lo que pase de 8 GB no tiene ruta documentada hacia el flujo.

AdaptlyPost
AdaptlyPost

Empieza tu prueba gratis de 7 días

Analíticas multiplataforma

Bandeja Social

Asistente con IA

La subida tampoco tiene que ser secuencial en ningún sentido publicado. X lista "Failed chunks can be retried individually" y "Uploads can be paused and resumed" entre las ventajas de fragmentar, pero nunca dice si un segmento reintentado sobrescribe al anterior, si los índices pueden llegar desordenados o qué ocurre si te saltas un número. La misma pregunta aparece en otras redes: la sesión de subida reanudable de Instagram tiene una cabecera de offset que todos los ejemplos publicados ponen a cero, y LinkedIn la responde entregándote una lista de URLs de subida, una por parte.

Una pantalla de carga en un portátil, parecida al progreso que un servidor informa mientras procesa un archivo.

Matemática de segmentos frente al límite de 16 GB
1.000 segmentos de 5 MB (recomendado)5 GB
1.000 segmentos de 8 MB (máximo del servidor)8 GB
Límite del esquema total_bytes16 GB
Incluso con el máximo del servidor de 8 MB, 1.000 segmentos llegan solo a 8 GB, la mitad de lo que permite el esquema de initialize.

¿Qué devuelve el comando STATUS?

STATUS devuelve un objeto processing_info con tres campos, y aquel sobre el que actúas es state.

CampoQué dice el esquema
state"Processing state (pending, in_progress, failed, succeeded)"
check_after_secs"Seconds to wait before polling status again"
progress_percent"Processing completion percentage"

La guía imprime el camino feliz como un diagrama de flechas: "pending to in_progress to succeeded or failed." Dos de esos cuatro son terminales. El propio ejemplo de sondeo de X rompe el bucle en succeeded y en failed, y duerme check_after_secs en cualquier otro caso, que es la forma correcta porque el intervalo lo pone el servidor y no tu política de reintentos. El ejemplo de FINALIZE devuelve "check_after_secs": 1, así que el primer sondeo llega rápido.

curl "https://api.x.com/2/media/upload?command=STATUS&media_id=1880028106020515840" \
  -H "Authorization: Bearer $USER_ACCESS_TOKEN"

Vale la pena conocer dos huecos antes de construir el bucle.

Los cuatro valores de estado viven en una cadena de descripción, no en un enum. El esquema tipa state como cadena simple sin lista de valores permitidos, así que los cuatro nombres que imprime X son documentación y no un conjunto cerrado. Trata un estado desconocido como "sigue sondeando" en lugar de como un error.

El mayor es que processing_info no tiene dónde poner un motivo del fallo. Su esquema declara exactamente tres propiedades y luego additionalProperties: false, así que una respuesta que dice "state": "failed" no lleva ningún código, ningún mensaje ni ningún subcódigo al lado. El protocolo v1.1 devolvía un objeto de error dentro de processing_info con un nombre y un mensaje. El esquema v2 tal como está publicado no tiene campo para eso, lo que deja failed como diagnóstico completo.

progress_percent está documentado en todos los esquemas de processing_info de la referencia de medios y no aparece en ninguna respuesta de ejemplo de X, así que cuenta con que falte en lugar de con que valga cero.

¿Por qué una subida terminada sigue fallando en POST /2/tweets?

Porque X comprueba el archivo dos veces contra dos personas distintas, y lo dice dos veces. La introducción de medios abre con ello: "Upload and posting are separately enforced. A file that uploads successfully can still be rejected when you attach it to a Post."

La primera comprobación corre contra el usuario que sube, en INIT y FINALIZE. La segunda corre contra el usuario que publica, cuando el media_id llega a POST /2/tweets. X nombra el fallo con exactitud:

{
  "title": "Forbidden",
  "detail": "This user is not allowed to post a video longer than 20 minutes.",
  "type": "about:blank",
  "status": 403
}

Veinte minutos es la cifra por defecto en esa cadena. X señala que el número se mueve: "N is the posting user's duration cap (20 minutes by default, 125 minutes for Premium / verified)." Lo que significa que el mismo media_id, finalizado una vez y procesado hasta succeeded, se adjunta en una cuenta y devuelve 403 en otra. El derecho sigue a la cuenta, y los niveles que deciden qué duración de vídeo recibe una cuenta son los mismos niveles de X Premium, no tu plan de desarrollador.

Los límites de composición del Post se aplican en ese mismo momento. X permite "up to 4 photos, 1 animated GIF, or 1 video" en un Post, y un media_id que rompa esa mezcla falla al adjuntarse aunque la subida fuera limpia. La secuencia práctica para cualquier cosa larga es el recorrido completo para llevar vídeo de alta calidad a X, con el 403 tratado como resultado normal y no como excepción.

Preguntas frecuentes

¿Qué endpoints sustituyen a command=INIT y command=APPEND en la API de X v2?

POST /2/media/upload/initialize y POST /2/media/upload/{id}/append. X indica que los parámetros con forma de comando "were the previous upload protocol" y que ya no deben enviarse a POST /2/media/upload.

¿Sigue siendo válido command=STATUS en la API de X v2?

Sí, y es el único que lo es. X escribe que "command=STATUS is still used only on the status GET", es decir, GET /2/media/upload?command=STATUS&media_id=. El esquema marca el parámetro command como opcional aunque todos los ejemplos publicados lo pasan.

¿Cuál es el segment_index máximo en el endpoint append de la API de X?

  1. El esquema de la solicitud append fija segment_index con un mínimo de 0 y un máximo de 999, así que un archivo tiene un tope de 1000 fragmentos.

¿Cómo de grande puede ser cada fragmento de APPEND?

X recomienda 5 MB y nombra 8 MB como máximo del servidor. Su propio ejemplo en Python lee el archivo en bloques de 4 MB.

AdaptlyPost
AdaptlyPost

Empieza tu prueba gratis de 7 días

Analíticas multiplataforma

Bandeja Social

Asistente con IA

¿Cuáles son los estados de procesamiento de la subida de medios de X?

pending, in_progress, succeeded y failed. X imprime la progresión como pending a in_progress a succeeded o failed, aunque el esquema tipa state como cadena abierta en lugar de como enum.

¿Por qué un media_id que finalizó con éxito falla en POST /2/tweets?

La subida y la publicación se controlan por separado contra derechos distintos. Si el usuario que publica no puede adjuntar un vídeo tan largo, la solicitud del Post devuelve 403 Forbidden con el detalle "This user is not allowed to post a video longer than N minutes."

¿Cuánto tiempo permanece válida una sesión de subida de medios de X antes de caducar?

El propio ejemplo de INIT de X devuelve un expires_after_secs de 86400, es decir, un día entre INIT y adjuntar el medio terminado a algo. FINALIZE informa el tiempo restante del mismo modo, como expires_after_secs. APPEND rompe ese patrón y devuelve expires_at, una marca de tiempo epoch absoluta en lugar de una cuenta regresiva, así que el mismo reloj de sesión aparece en dos unidades distintas.

¿Subir una foto a X exige consultar el endpoint STATUS?

Casi nunca. La regla de X es que si FINALIZE no devuelve ningún bloque processing_info, el medio está listo para usarse, y una subida de imagen suele volver sin él. Un vídeo nunca vuelve sin él, así que el paso cuatro es en la práctica cosa de vídeos.

¿El endpoint STATUS usa un scope de OAuth distinto al de los pasos de subida?

Las cuatro llamadas, INIT, APPEND, FINALIZE y STATUS, funcionan bajo el mismo scope media.write. Consultar el estado de procesamiento de tu propia subida exige un scope de escritura, y X no publica ninguna alternativa de solo lectura.

¿Qué tipos de medios se pueden subir por el endpoint initialize de la API de X?

El enum media_type de INIT va desde video/mp4 y video/quicktime hasta text/srt y text/vtt, y llega a dos formatos 3D, model/gltf-binary y model/vnd.usdz+zip. Un solo endpoint de subida cubre así vídeo, subtítulos y archivos 3D.

¿Te resultó útil este artículo?

¡Cuéntanos qué te parece!

Vernos más en Google

Un clic marca AdaptlyPost como fuente preferida y nuestros artículos aparecen más arriba en tus Noticias destacadas, el modo IA y los resúmenes con IA.

Antes de irte...

AdaptlyPost

AdaptlyPost

Programa tu contenido en todas las plataformas

Gestiona todas tus cuentas de redes sociales en un solo lugar con AdaptlyPost.

Analíticas multiplataforma

Bandeja Social

Asistente con IA

Términos relacionados del glosario

Artículos Relacionados