TL;DR, Réponse Rapide
9 min de lectureL'upload vidéo en morceaux sur X v2 tient en quatre appels : POST /2/media/upload/initialize renvoie un media id, POST /2/media/upload/{id}/append prend chaque morceau avec un segment_index, POST /2/media/upload/{id}/finalize clôt la session, et GET /2/media/upload?command=STATUS interroge processing_info jusqu'à ce que state vaille succeeded ou failed. Les anciens paramètres command=INIT et command=APPEND ont disparu de partout sauf de ce GET de statut. segment_index plafonne à 999 et X recommande des morceaux de 5 Mo, ce qui n'atteint pas les 16 Go de total_bytes que le schéma d'initialize accepte.
En quoi consiste le flux d'upload de médias INIT APPEND FINALIZE de l'API X ?
Quatre appels composent le flux d'upload de médias INIT APPEND FINALIZE de l'API X : trois POST qui déplacent le fichier et un GET qui rapporte ce que X en a fait ensuite. X les liste dans cet ordre sur son guide d'upload en morceaux.
- INIT,
POST /2/media/upload/initialize, que X décrit comme « start the session and get amedia_id» - APPEND,
POST /2/media/upload/{id}/append, « upload each chunk » - FINALIZE,
POST /2/media/upload/{id}/finalize, « complete the upload » - STATUS,
GET /2/media/upload, « wait for processing whenprocessing_infois returned »
Les noms de commandes ont survécu au passage en v2, le transport non. X place l'avertissement juste sous la liste : « 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. »
Donc une des quatre commandes existe encore en paramètre de requête et trois ont disparu. Du code écrit contre la v1.1 casse sur les trois POST et continue de fonctionner sur l'interrogation, ce qui est une façon déroutante de tomber en panne.
Les quatre appels passent par le même scope OAuth 2.0, media.write, y compris le GET de statut. Lire l'état de traitement de votre propre upload exige un scope d'écriture, et X ne publie aucune alternative en lecture seule.
Qu'envoie et que renvoie chaque étape ?
Chaque étape transporte des paramètres différents, et seules deux des quatre renvoient quelque chose que vous conservez.
| Étape | Endpoint | Ce que vous envoyez | Ce que vous récupérez |
|---|---|---|---|
| INIT | POST /2/media/upload/initialize | media_type, total_bytes, media_category, additional_owners et shared en option | id, media_key, expires_after_secs |
| APPEND | POST /2/media/upload/{id}/append | media et segment_index | expires_at |
| FINALIZE | POST /2/media/upload/{id}/finalize | rien d'autre que l'id du chemin | id, media_key, size, expires_after_secs, processing_info |
| STATUS | GET /2/media/upload?command=STATUS&media_id= | media_id, command en option | id, media_key, size, processing_info, video ou image |
INIT prend un corps JSON, pas des champs de formulaire, et X le dit dans le guide : « Send a JSON body, not multipart form fields. » L'énumération de media_type va de video/mp4 et video/quicktime à text/srt et text/vtt, en passant par deux formats 3D que presque personne ne remarque, model/gltf-binary et model/vnd.usdz+zip. Le champ total_bytes a un plafond de schéma strict à 17179869184, soit 16 Gio.
{
"data": {
"id": "1880028106020515840",
"media_key": "13_1880028106020515840",
"expires_after_secs": 86400
}
}Cet expires_after_secs de 86400 dans l'exemple de X est l'horloge de la session : un jour entre l'INIT et le moment d'attacher le média fini à quelque chose. L'id respecte le motif ^[0-9]{1,19}$, et le media_key le préfixe d'un numéro de type et d'un tiret bas, la même forme 13_ que l'Ads API documente quand elle appelle cette valeur un id de vidéo.
APPEND est la seule étape dont la réponse ne vous apprend rien d'utile sur le média. Son schéma ne contient qu'un champ, expires_at, décrit comme « Epoch seconds when the upload session expires. » Toutes les autres étapes rapportent la durée de vie restante de la session sous expires_after_secs, un décompte relatif. APPEND la rapporte en horodatage absolu. Même fait, deux unités, trois orthographes de champ sur quatre endpoints.
FINALIZE est la requête la plus vide du flux. Elle prend l'id du chemin et rien d'autre, ni corps ni paramètre de requête, ce qui explique que tout le curl tienne sur deux lignes :
curl -X POST "https://api.x.com/2/media/upload/1880028106020515840/finalize" \
-H "Authorization: Bearer $USER_ACCESS_TOKEN"C'est sa réponse qui porte le vrai embranchement. X met la règle en une phrase : « If processing_info is returned, proceed to Step 4 to wait for processing. If not, the media is ready to use. » Une image saute généralement l'étape quatre. Une vidéo jamais.

Comment fonctionne segment_index ?
segment_index est un simple compteur qui vous appartient, il démarre à zéro, et le schéma en fixe les deux bornes : « minimum: 0, maximum: 999. »
Les conseils de X sur la taille des morceaux se trouvent dans le guide plutôt que dans le schéma : « Keep each segment at or below 5 MB (the server maximum is 8 MB). Segments are indexed from 0. » L'exemple Python du même guide lit le fichier par blocs de 4 Mo et incrémente l'index après chaque appel réussi.
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"Le corps peut être du multipart form data comme ci-dessus ou du JSON, parce que le schéma de requête est enregistré pour les deux types de contenu. En JSON, le champ media prend du base64. En multipart, il prend des octets bruts.
Multipliez maintenant les deux plafonds publiés. Mille segments au maximum serveur de 8 Mo font 8 Go. Mille segments aux 5 Mo recommandés font 5 Go. Pendant ce temps, POST /2/media/upload/initialize accepte un total_bytes jusqu'à 16 Gio, et X affirme sans détour qu'un compte X Premium ou vérifié peut téléverser une vidéo de 16 Go sur un Post. Ces deux faits ne peuvent pas être satisfaits ensemble via APPEND tel qu'il est documenté, et X ne publie ni taille de segment supérieure, ni chemin alternatif, ni note indiquant que le plafond de 999 bouge pour les gros fichiers. Au-delà de 8 Go, aucune route documentée n'entre dans le flux.
AdaptlyPost
Commencez votre essai gratuit de 7 jours
Analyses multiplateforme
Boîte sociale
Assistant IA
L'upload n'est pas non plus tenu d'être séquentiel, au sens publié du terme. X liste « Failed chunks can be retried individually » et « Uploads can be paused and resumed » parmi les avantages du découpage, mais ne dit jamais si un segment réessayé écrase le précédent, si les index peuvent arriver dans le désordre, ni ce qui se passe si vous sautez un numéro. La même question revient sur d'autres réseaux : la session d'upload reprenable d'Instagram a un en-tête d'offset que tous les exemples publiés mettent à zéro, et LinkedIn y répond en vous remettant une liste d'URL d'upload, une par partie.

Que renvoie la commande STATUS ?
STATUS renvoie un objet processing_info à trois champs, et celui sur lequel vous agissez est state.
| Champ | Ce que dit le schéma |
|---|---|
state | « Processing state (pending, in_progress, failed, succeeded) » |
check_after_secs | « Seconds to wait before polling status again » |
progress_percent | « Processing completion percentage » |
Le guide imprime le chemin nominal sous forme de flèches : « pending to in_progress to succeeded or failed. » Deux de ces quatre états sont terminaux. L'exemple d'interrogation de X sort de la boucle sur succeeded et sur failed, et dort pendant check_after_secs dans tous les autres cas, ce qui est la bonne forme puisque c'est le serveur qui fixe l'intervalle, pas votre politique de backoff. L'exemple de FINALIZE renvoie "check_after_secs": 1, donc la première interrogation arrive vite.
curl "https://api.x.com/2/media/upload?command=STATUS&media_id=1880028106020515840" \
-H "Authorization: Bearer $USER_ACCESS_TOKEN"Deux manques méritent d'être connus avant d'écrire la boucle.
Les quatre valeurs d'état vivent dans une chaîne de description, pas dans une énumération. Le schéma type state comme une simple chaîne sans liste de valeurs autorisées, donc les quatre noms imprimés par X relèvent de la documentation et non d'un ensemble fermé. Traitez un état inconnu comme un « continuez d'interroger » plutôt que comme une erreur.
Le manque le plus gênant, c'est que processing_info n'a nulle part où loger un motif d'échec. Son schéma déclare exactement trois propriétés puis additionalProperties: false, donc une réponse qui dit "state": "failed" ne porte à côté ni code, ni message, ni sous-code. Le protocole v1.1 renvoyait un objet d'erreur dans processing_info, avec un nom et un message. Le schéma v2 tel qu'il est publié n'a aucun champ pour cela, ce qui laisse « failed » comme diagnostic complet.
progress_percent est documenté sur tous les schémas processing_info de la référence média et n'apparaît dans aucune réponse d'exemple de X, donc prévoyez son absence plutôt qu'un zéro.
Pourquoi un upload terminé échoue-t-il quand même sur POST /2/tweets ?
Parce que X contrôle le fichier deux fois contre deux personnes différentes, et le dit deux fois. L'introduction média ouvre là-dessus : « Upload and posting are separately enforced. A file that uploads successfully can still be rejected when you attach it to a Post. »
Le premier contrôle s'exécute contre l'utilisateur qui téléverse, à l'INIT et au FINALIZE. Le second s'exécute contre l'utilisateur qui publie, quand le media_id arrive sur POST /2/tweets. X nomme l'échec avec exactitude :
{
"title": "Forbidden",
"detail": "This user is not allowed to post a video longer than 20 minutes.",
"type": "about:blank",
"status": 403
}Vingt minutes est le chiffre par défaut dans cette chaîne. X précise qu'il bouge : « N is the posting user's duration cap (20 minutes by default, 125 minutes for Premium / verified). » Ce qui veut dire que le même media_id, finalisé une fois et traité jusqu'à succeeded, s'attache pour un compte et renvoie un 403 pour un autre. Le droit suit le compte, et les paliers qui décident de la durée vidéo accordée à un compte sont les paliers X Premium, pas votre plan développeur.
Les limites de composition d'un Post s'appliquent au même instant. X autorise « up to 4 photos, 1 animated GIF, or 1 video » sur un Post, et un media_id qui enfreint ce mélange échoue à l'attachement même si l'upload était irréprochable. Pour tout ce qui est long, la séquence pratique est le parcours complet pour mettre une vidéo de qualité sur X, avec le 403 traité comme une issue normale et non comme une exception.
Questions fréquentes
Quels endpoints remplacent command=INIT et command=APPEND sur l'API X v2 ?
POST /2/media/upload/initialize et POST /2/media/upload/{id}/append. X indique que les paramètres de style commande « were the previous upload protocol » et ne doivent plus être envoyés à POST /2/media/upload.
command=STATUS est-il toujours valide sur l'API X v2 ?
Oui, et c'est le seul à l'être. X écrit que « command=STATUS is still used only on the status GET », c'est-à-dire GET /2/media/upload?command=STATUS&media_id=. Le schéma marque le paramètre command comme facultatif alors que tous les exemples publiés le passent.
Quel est le segment_index maximal sur l'endpoint append de l'API X ?
- Le schéma de requête d'append fixe
segment_indexà un minimum de 0 et un maximum de 999, ce qui plafonne un fichier à 1000 morceaux.
Quelle taille peut faire chaque morceau APPEND ?
X recommande 5 Mo et donne 8 Mo comme maximum serveur. Son propre exemple Python lit le fichier par blocs de 4 Mo.
AdaptlyPost
Commencez votre essai gratuit de 7 jours
Analyses multiplateforme
Boîte sociale
Assistant IA
Quels sont les états de traitement d'un upload média sur X ?
pending, in_progress, succeeded et failed. X imprime la progression de pending à in_progress puis succeeded ou failed, même si le schéma type state comme une chaîne ouverte plutôt que comme une énumération.
Pourquoi un media_id finalisé sans erreur échoue-t-il sur POST /2/tweets ?
L'upload et la publication sont contrôlés séparément, contre des droits différents. Si l'utilisateur qui publie ne peut pas attacher une vidéo aussi longue, la requête de Post renvoie un 403 Forbidden avec le détail « This user is not allowed to post a video longer than N minutes. »
Combien de temps une session d'upload de médias X reste-t-elle valide avant d'expirer ?
L'exemple d'INIT publié par X renvoie un expires_after_secs de 86400, soit un jour entre INIT et l'attachement du média terminé. FINALIZE indique le temps restant de la même façon, en expires_after_secs. APPEND rompt ce schéma et renvoie expires_at, un horodatage epoch absolu plutôt qu'un compte à rebours, si bien que la même horloge de session s'exprime en deux unités différentes.
Faut-il interroger l'endpoint STATUS pour uploader une simple photo sur X ?
Presque jamais. La règle de X est que si FINALIZE ne renvoie aucun bloc processing_info, le média est prêt à l'emploi, et un téléversement d'image revient généralement sans ce bloc. Une vidéo jamais, l'étape quatre est donc en pratique une attente réservée aux vidéos.
L'endpoint STATUS utilise-t-il un scope OAuth différent des étapes d'upload ?
Les quatre appels, INIT, APPEND, FINALIZE et STATUS, passent par le même scope media.write. Consulter l'état de traitement de son propre upload demande donc un scope d'écriture, et X ne publie aucune alternative en lecture seule.
Quels types de médias peut-on envoyer via l'endpoint initialize de l'API X ?
L'enum media_type d'INIT va de video/mp4 et video/quicktime jusqu'à text/srt et text/vtt, avec deux formats 3D, model/gltf-binary et model/vnd.usdz+zip. Un seul endpoint d'upload couvre ainsi vidéo, sous-titres et fichiers 3D.
Cet article vous a-t-il été utile ?
Dites-nous ce que vous en pensez !
Nous voir plus souvent sur Google
Un clic définit AdaptlyPost comme source préférée. Nos articles remontent alors dans vos À la une, en mode IA et dans les aperçus IA.
Avant de partir...
AdaptlyPost
Planifiez vos contenus sur toutes les plateformes
Gérez tous vos comptes de réseaux sociaux en un seul endroit avec AdaptlyPost.
Analyses multiplateforme
Boîte sociale
Assistant IA
Termes connexes du glossaire


Toutes les valeurs de media_category de l'API Twitter et ce qu'elles autorisent
Le paramètre media_category de l'API Twitter a huit valeurs, fixe les plafonds de taille et de durée de X, et échoue au moment du Post si vous choisissez mal.


La session d'upload résumable Instagram et l'hôte rupload
Meta fait démarrer un upload résumable Instagram par upload_type=resumable sur /media, puis un POST vers rupload.facebook.com avec offset et file_size.


Meta documente quatre limites différentes pour le champ scheduled_publish_time de Facebook
Le champ scheduled_publish_time de Facebook exige au moins 10 minutes d'avance, et Meta lui donne quatre maximums : 29 jours, 30 jours, 75 jours et 6 mois.
Articles Connexes


Comment la limite de débit business use case de Meta mesure les Pages Facebook
Sur les Pages, la limite de débit business use case de Meta autorise 4800 appels par utilisateur engagé sur 24 heures et échoue avec le code 80001.


Meta impose ses exigences d'images de l'API Instagram dès l'envoi
Meta réduit les exigences d'images de l'API Instagram au JPEG, à 8 MB maximum et à un ratio de 4:5 à 1.91:1, chacune avec son code d'erreur.


Meta fixe la limite de taux de l'API Instagram à 4800 fois vos impressions
Meta fixe la limite de taux de l'API Instagram à 4800 appels par impression sur 24 heures glissantes et publie l'usage dans X-Business-Use-Case-Usage.

