TL;DR, Resposta Rápida
9 min de leituraUpload de vídeo em partes no X v2 são quatro chamadas: POST /2/media/upload/initialize devolve um media id, POST /2/media/upload/{id}/append recebe cada parte com um segment_index, POST /2/media/upload/{id}/finalize fecha a sessão, e GET /2/media/upload?command=STATUS consulta o processing_info até o state ser succeeded ou failed. Os antigos parâmetros command=INIT e command=APPEND sumiram de tudo menos desse GET de status. O segment_index para em 999 e o X recomenda partes de 5 MB, o que não chega perto dos 16 GB de total_bytes que o schema de inicialização aceita.
O que é o fluxo de upload de mídia INIT APPEND FINALIZE da API do X?
São quatro chamadas no fluxo de upload de mídia INIT APPEND FINALIZE da API do X: três POSTs que movem o arquivo e um GET que relata o que o X fez com ele depois. O X lista as quatro nessa ordem no guia de upload em partes.
- INIT,
POST /2/media/upload/initialize, que o X descreve como "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"
Os nomes dos comandos sobreviveram à mudança para a v2, o transporte não. O X põe o aviso logo abaixo da 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."
Ou seja, um dos quatro comandos ainda existe como parâmetro de query e três não. Código escrito para a v1.1 quebra nos três POSTs e continua funcionando na consulta, o que é um jeito confuso de falhar.
As quatro chamadas ficam atrás do mesmo escopo OAuth 2.0, media.write, inclusive o GET de status. Ler o estado de processamento do seu próprio upload exige um escopo de escrita, e o X não publica alternativa somente leitura.
O que cada etapa envia e devolve?
Cada etapa leva parâmetros diferentes, e só duas das quatro devolvem algo que você guarda.
| Etapa | Endpoint | Você envia | Você recebe |
|---|---|---|---|
| INIT | POST /2/media/upload/initialize | media_type, total_bytes, media_category, opcionalmente additional_owners e shared | id, media_key, expires_after_secs |
| APPEND | POST /2/media/upload/{id}/append | media e segment_index | expires_at |
| FINALIZE | POST /2/media/upload/{id}/finalize | nada além do id no caminho | id, media_key, size, expires_after_secs, processing_info |
| STATUS | GET /2/media/upload?command=STATUS&media_id= | media_id, opcionalmente command | id, media_key, size, processing_info, video ou image |
O INIT recebe um corpo JSON, não campos de formulário, e o X diz isso no guia: "Send a JSON body, not multipart form fields." O enum de media_type vai de video/mp4 e video/quicktime a text/srt e text/vtt, passando por dois formatos 3D que quase ninguém nota, model/gltf-binary e model/vnd.usdz+zip. O campo total_bytes tem um teto rígido de schema em 17179869184, que são 16 GiB.
{
"data": {
"id": "1880028106020515840",
"media_key": "13_1880028106020515840",
"expires_after_secs": 86400
}
}Esse expires_after_secs de 86400 no exemplo do próprio X é o relógio da sessão: um dia entre o INIT e anexar a mídia pronta a alguma coisa. O id segue o padrão ^[0-9]{1,19}$, e o media_key põe na frente dele um número de tipo e um sublinhado, o mesmo formato 13_ que a Ads API documenta quando chama o valor de id de vídeo.
O APPEND é a única etapa cuja resposta não diz nada de útil sobre a mídia. O schema dele tem um campo só, expires_at, descrito como "Epoch seconds when the upload session expires." Todas as outras etapas informam a vida restante da sessão como expires_after_secs, uma contagem relativa. O APPEND informa como timestamp absoluto. O mesmo fato, duas unidades, três grafias de campo em quatro endpoints.
O FINALIZE é a requisição mais vazia do fluxo. Ele recebe o id no caminho e mais nada, sem corpo e sem parâmetros de query, e é por isso que o curl inteiro cabe em duas linhas:
curl -X POST "https://api.x.com/2/media/upload/1880028106020515840/finalize" \
-H "Authorization: Bearer $USER_ACCESS_TOKEN"A resposta dele é onde a bifurcação de verdade acontece. O X põe a regra em uma frase: "If processing_info is returned, proceed to Step 4 to wait for processing. If not, the media is ready to use." Uma imagem costuma pular a etapa quatro. Um vídeo nunca pula.

Como funciona o segment_index?
segment_index é um contador simples que é seu, começa em zero, e o schema fixa as duas pontas: "minimum: 0, maximum: 999."
A orientação do X sobre tamanho de parte fica no guia e não no schema: "Keep each segment at or below 5 MB (the server maximum is 8 MB). Segments are indexed from 0." O exemplo em Python no mesmo guia lê o arquivo em blocos de 4 MB e incrementa o índice depois de cada chamada bem-sucedida.
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"O corpo pode ser multipart form data, como acima, ou JSON, porque o schema da requisição está registrado para os dois content types. Em JSON o campo media recebe base64. Em multipart ele recebe bytes crus.
Agora multiplique os dois tetos publicados. Mil segmentos no máximo de 8 MB do servidor dão 8 GB. Mil segmentos nos 5 MB recomendados dão 5 GB. Só que POST /2/media/upload/initialize aceita total_bytes de até 16 GiB, e o X afirma sem rodeios que uma conta X Premium ou verificada pode subir um vídeo de 16 GB em um Post. Esses dois fatos não podem ser satisfeitos ao mesmo tempo pelo APPEND como está documentado, e o X não publica segmento maior, nem caminho alternativo, nem nota dizendo que o teto de 999 muda para arquivos grandes. Qualquer coisa acima de 8 GB não tem rota documentada para entrar no fluxo.
AdaptlyPost
Comece seu teste grátis de 7 dias
Análises multiplataforma
Caixa Social
Assistente com IA
O upload também não precisa ser sequencial em nenhum sentido publicado. O X lista "Failed chunks can be retried individually" e "Uploads can be paused and resumed" entre as vantagens do upload em partes, mas nunca diz se um segmento reenviado sobrescreve o anterior, se os índices podem chegar fora de ordem ou o que acontece se você pular um número. A mesma dúvida aparece em outras redes: a sessão de upload retomável do Instagram tem um cabeçalho de offset que todos os exemplos publicados deixam em zero, e o LinkedIn responde entregando uma lista de URLs de upload, uma por parte.

O que o comando STATUS devolve?
O STATUS devolve um objeto processing_info com três campos, e aquele em que você age é o state.
| Campo | O que o schema diz |
|---|---|
state | "Processing state (pending, in_progress, failed, succeeded)" |
check_after_secs | "Seconds to wait before polling status again" |
progress_percent | "Processing completion percentage" |
O guia imprime o caminho feliz como um diagrama de setas: "pending to in_progress to succeeded or failed." Dois desses quatro são terminais. O exemplo de consulta do próprio X quebra o laço em succeeded e em failed e dorme por check_after_secs em qualquer outro caso, que é o formato certo, porque quem define o intervalo é o servidor e não a sua política de backoff. O exemplo do FINALIZE devolve "check_after_secs": 1, então a primeira consulta vem rápido.
curl "https://api.x.com/2/media/upload?command=STATUS&media_id=1880028106020515840" \
-H "Authorization: Bearer $USER_ACCESS_TOKEN"Vale conhecer duas lacunas antes de montar o laço.
Os quatro valores de estado vivem em uma string de descrição, não em um enum. O schema tipa state como string simples, sem lista de valores permitidos, então os quatro nomes que o X imprime são documentação e não um conjunto fechado. Trate um estado desconhecido como "continue consultando" em vez de como erro.
A lacuna maior é que processing_info não tem onde pôr um motivo de falha. O schema dele declara exatamente três propriedades e depois additionalProperties: false, então uma resposta que diz "state": "failed" não traz código, nem mensagem, nem subcódigo junto. O protocolo v1.1 devolvia um objeto de erro dentro de processing_info, com nome e mensagem. O schema v2 como publicado não tem campo para isso, o que deixa "failed" como o diagnóstico inteiro.
progress_percent está documentado em todos os schemas de processing_info da referência de mídia e não aparece em nenhuma resposta de exemplo do X, então conte com ele ausente em vez de zerado.
Por que um upload concluído ainda falha em POST /2/tweets?
Porque o X confere o arquivo duas vezes contra duas pessoas diferentes, e diz isso duas vezes. A introdução de mídia abre com o tema: "Upload and posting are separately enforced. A file that uploads successfully can still be rejected when you attach it to a Post."
A primeira conferência roda contra o usuário que fez o upload, no INIT e no FINALIZE. A segunda roda contra o usuário que publica, quando o media_id chega em POST /2/tweets. O X nomeia a falha exatamente:
{
"title": "Forbidden",
"detail": "This user is not allowed to post a video longer than 20 minutes.",
"type": "about:blank",
"status": 403
}Vinte minutos é a cifra padrão nessa string. O X observa que o número muda: "N is the posting user's duration cap (20 minutes by default, 125 minutes for Premium / verified)." Ou seja, o mesmo media_id, finalizado uma vez e processado até succeeded, anexa em uma conta e devolve 403 em outra. O direito segue a conta, e as faixas que decidem qual duração de vídeo uma conta recebe são as mesmas faixas do X Premium, não o seu plano de desenvolvedor.
Os limites de composição do Post valem no mesmo instante. O X permite "up to 4 photos, 1 animated GIF, or 1 video" em um Post, e um media_id que viola essa mistura falha no anexo mesmo com o upload tendo saído limpo. A sequência prática para qualquer coisa longa é o passo a passo completo para colocar vídeo de alta qualidade no X, com o 403 tratado como resultado normal e não como exceção.
Perguntas frequentes
Quais endpoints substituem command=INIT e command=APPEND na API do X v2?
POST /2/media/upload/initialize e POST /2/media/upload/{id}/append. O X afirma que os parâmetros em formato de comando "were the previous upload protocol" e não devem mais ser enviados para POST /2/media/upload.
O command=STATUS ainda vale na API do X v2?
Sim, e é o único que vale. O X escreve que "command=STATUS is still used only on the status GET", ou seja, GET /2/media/upload?command=STATUS&media_id=. O schema marca o parâmetro command como opcional mesmo que todos os exemplos publicados o enviem.
Qual o segment_index máximo no endpoint append da API do X?
- O schema da requisição de append define
segment_indexcom mínimo 0 e máximo 999, o que limita um arquivo a 1000 partes.
Qual o tamanho máximo de cada parte do APPEND?
O X recomenda 5 MB e aponta 8 MB como máximo do servidor. O exemplo em Python da própria empresa lê o arquivo em blocos de 4 MB.
AdaptlyPost
Comece seu teste grátis de 7 dias
Análises multiplataforma
Caixa Social
Assistente com IA
Quais são os estados de processamento de upload de mídia do X?
pending, in_progress, succeeded e failed. O X imprime a progressão como pending para in_progress para succeeded ou failed, ainda que o schema tipe state como string aberta e não como enum.
Por que um media_id finalizado com sucesso falha em POST /2/tweets?
Upload e publicação são fiscalizados separadamente contra direitos diferentes. Se o usuário que publica não pode anexar um vídeo tão longo, a requisição do Post devolve 403 Forbidden com o detalhe "This user is not allowed to post a video longer than N minutes."
Por quanto tempo uma sessão de upload de mídia do X fica válida antes de expirar?
O próprio exemplo de INIT do X devolve um expires_after_secs de 86400, ou seja, um dia entre o INIT e anexar a mídia pronta a alguma coisa. O FINALIZE informa o tempo restante do mesmo jeito, como expires_after_secs. O APPEND foge desse padrão e devolve expires_at, um timestamp epoch absoluto em vez de uma contagem regressiva, então o mesmo relógio de sessão aparece em duas unidades diferentes.
Fazer upload de uma foto no X exige consultar o endpoint STATUS?
Quase nunca. A regra do X é que, se o FINALIZE não devolve bloco processing_info nenhum, a mídia está pronta para uso, e um upload de imagem costuma voltar sem esse bloco. Um vídeo nunca volta sem ele, então o passo quatro é, na prática, coisa de vídeo.
O endpoint STATUS usa um escopo OAuth diferente das etapas de upload?
As quatro chamadas, INIT, APPEND, FINALIZE e STATUS, ficam atrás do mesmo escopo media.write. Consultar o estado de processamento do próprio upload exige um escopo de escrita, e o X não publica nenhuma alternativa somente leitura.
Quais tipos de mídia podem ser enviados pelo endpoint initialize da API do X?
O enum media_type do INIT vai de video/mp4 e video/quicktime até text/srt e text/vtt, chegando a dois formatos 3D, model/gltf-binary e model/vnd.usdz+zip. Um único endpoint de upload cobre vídeo, legendas e arquivos 3D.
Este artigo foi útil para você?
Conte-nos o que você achou!
Veja-nos mais no Google
Um clique marca a AdaptlyPost como fonte preferida e nossos artigos passam a aparecer mais acima nas suas Principais notícias, no modo IA e nas visões gerais com IA.
Antes de ir...
AdaptlyPost
Agende seu conteúdo em todas as plataformas
Gerencie todas as suas contas de redes sociais em um só lugar com o AdaptlyPost.
Análises multiplataforma
Caixa Social
Assistente com IA
Termos relacionados do glossário


Todos os valores de media_category da API do Twitter e o que cada um libera
O parâmetro media_category da API do Twitter tem oito valores, define os tetos de tamanho e duração do X e falha na hora do post se você errar a escolha.


A sessão de upload retomável do Instagram e o host rupload
Um upload retomável do Instagram começa com upload_type=resumable em /media, depois um POST para rupload.facebook.com com cabeçalhos offset e file_size.


A Meta documenta quatro limites diferentes para o scheduled_publish_time do Facebook
O campo scheduled_publish_time do Facebook exige um horário pelo menos 10 minutos à frente, e a Meta dá quatro máximos: 29 dias, 30 dias, 75 dias e 6 meses.
Artigos Relacionados


Como o limite de taxa de caso de uso comercial da Meta mede as Páginas do Facebook
O limite de taxa de caso de uso comercial da Meta para Páginas libera 4800 chamadas por usuário engajado a cada 24 horas e falha com o código 80001.


Os requisitos de imagem da Instagram API que a Meta aplica no upload
Os requisitos de imagem da Instagram API são apenas JPEG, 8 MB no máximo e proporção de 4:5 a 1.91:1, cada um com seu próprio código de erro.


O limite de taxa da Instagram API é 4800 vezes as suas impressões
A Meta fixa o limite de taxa da Instagram API em 4800 chamadas por impressão em 24 horas móveis e informa o uso no X-Business-Use-Case-Usage.

