Certificação Claude Developer Foundations · parte 8 de 20
Imagens, PDFs e Files API na API do Claude
Como mandar imagens e PDFs ao modelo, quanto isso custa em tokens e como reaproveitar um arquivo com a Files API sem reenviá-lo a cada chamada.
Publicada em · 36 min de leitura
Esta nota trata de conteúdo que não é texto. Uma requisição com mensagens de texto já é conhecida. Aqui a pergunta muda: como mandar ao modelo conteúdo que não é texto, como imagens e PDFs, e como reaproveitar um arquivo sem reenviá-lo em toda chamada. Os dois assuntos caminham juntos porque, no trabalho real, quem manda imagens quase sempre manda os mesmos documentos várias vezes.
Os exemplos usam Python com o SDK oficial anthropic, versão 1.15.0. O código foi executado nesta sessão, em 18/10/2026, contra um servidor local que imita o formato documentado. Nenhuma chamada saiu para a rede e nenhuma chave real foi usada. Os limites, os nomes de campos e o estado das funcionalidades vêm da documentação oficial consultada no mesmo dia, e a seção de fontes diz o que ficou sem conferência.
Mapa da aula
| Seção | O que responde |
|---|---|
| 1. Blocos de conteúdo | Como uma mensagem deixa de ser texto, e de onde o conteúdo pode vir? |
| 2. Imagens | Quais formatos, tamanhos e quantidades a API aceita? |
| 3. PDFs | O que o modelo recebe quando você manda um PDF? |
| 4. Imagem em tokens | Por que duas imagens de tamanho de arquivo diferente custam o mesmo? |
| 5. PDF em tokens | Como estimar o custo de um documento de muitas páginas? |
| 6. Por que reenviar pesa | Qual é o custo de mandar os mesmos bytes em toda chamada? |
| 7. Upload, file_id e uso | Como subir um arquivo e referenciá-lo numa mensagem? |
| 8. Reuso, expiração e exclusão | Quanto tempo o arquivo fica, e o que acontece quando ele some? |
| 9. Estado da API | A Files API ainda é beta? O que mudou com o header antigo? |
| 10. Enviar, reusar ou recortar | Quando cada caminho faz sentido? |
| 11. Dados sensíveis | O que um arquivo enviado expõe, e por quanto tempo? |
| 12. Erros comuns | Quais armadilhas aparecem em código real, e por quê? |
| 13. Exercícios | O que você pode rodar sozinho? |
| 14. Glossário | Quais termos desta aula valem guardar? |
| 15. Fontes | Onde cada fato foi confirmado e o que não foi? |
Parte 1: o que entra além do texto
1. Blocos de conteúdo: a mensagem é uma lista
Pense numa mensagem como um envelope. Quando ela era só texto, o envelope levava uma carta. Agora ele pode levar uma foto, um contrato impresso e a pergunta escrita numa folha à parte, e cada item vem com uma etiqueta dizendo o que é. Na API, cada item desses é um bloco de conteúdo, um objeto JSON com um campo type. 1.3 Mecânica da API Claude já mostrou isso do lado da resposta, quando content veio como lista de blocos. Do lado da requisição a regra é a mesma: o content de uma mensagem do papel user pode ser uma string ou uma lista de blocos.
Esta aula usa três tipos de bloco. O text leva texto, como antes. O image leva uma imagem. O document leva um PDF, e também um arquivo de texto puro. Cada um desses blocos de mídia tem um campo source, que diz de onde vem o conteúdo. A documentação define três origens possíveis para imagens e PDFs, e elas têm consequências diferentes para o seu código, para o tamanho da requisição e para a conta de tokens.
A primeira origem é base64. Base64 é uma forma de escrever bytes usando só caracteres imprimíveis, o que permite pôr um arquivo binário dentro de um JSON. O preço é tamanho: a versão em base64 fica cerca de um terço maior que o arquivo original. A segunda origem é url. Você passa um endereço e a API busca o arquivo por conta própria. Seu código não carrega os bytes, mas perde o controle sobre o que é buscado, e a documentação consultada não detalha quais endereços a API aceita, então isso fica como ponto a confirmar. A terceira origem é file, que recebe um file_id de um arquivo que você já enviou para a Files API. Esse é o caminho das seções 6 a 9.
Leia a figura da esquerda para a direita. Sua aplicação escolhe um dos três caminhos, e a espessura e a cor das linhas mostram o volume que cada um move. A linha rosa, do base64, é a mais grossa: os bytes viajam dentro da requisição. A linha verde, do upload, é fina: só o identificador viaja na requisição, e o arquivo já está do outro lado. A linha tracejada, da URL, é a que o seu código não controla: quem baixa o arquivo é a API. Repare que as três chegam na mesma caixa, a Messages API, e que o modelo só enxerga os blocos depois que a API os monta. A caixa “Corpo: 32 MB” lembra que o limite é da requisição inteira, não de cada anexo.
2. Imagens: formatos, tamanho e quantidade
A API aceita imagens JPEG, PNG, GIF e WebP, identificadas pelos tipos image/jpeg, image/png, image/gif e image/webp. Um GIF animado é lido só pelo primeiro quadro. A documentação lista esses quatro formatos e não diz o que acontece com outros, então um TIFF ou um HEIC deve ser convertido antes do envio, e a conversão fica na sua aplicação.
Os limites existem por razões diferentes, e vale entender cada uma. O tamanho por imagem protege a requisição: a documentação informa 10 MB por imagem, em base64, quando se usa a API diretamente. No Amazon Bedrock e no Google Cloud o limite cai para 5 MB, e no claude.ai é de 10 MB. A dimensão máxima é de 8000 por 8000 pixels. Esse número define o que a API aceita receber. Imagens grandes que passam dele são reduzidas antes do processamento, como a seção 4 mostra. A quantidade por requisição depende do modelo: até 100 imagens em modelos com janela de contexto de 200 mil tokens, e até 600 nos demais, na API. No claude.ai o limite é de 20 imagens por mensagem.
Existe um limite que muita gente não conhece. Quando uma única requisição tem mais de 20 imagens, cada imagem precisa ter no máximo 2000 pixels em qualquer dos lados. A documentação diz que todos os blocos image da requisição contam para esse limite, inclusive os de turnos antigos que você reenvia e as imagens que voltam dentro de um tool_result, como capturas de tela de uma ferramenta de uso do computador. Uma imagem que estoura o limite mais restrito é rejeitada com invalid_request_error, e a mensagem de erro fala em “many-image requests”. A solução que a documentação sugere é redimensionar as imagens para 2000 pixels no lado maior, ou manter a requisição com até 20 blocos de imagem ou documento.
Um bloco de imagem em base64 tem esta forma. Ele vem antes do texto, porque a documentação recomenda imagem antes de pergunta, e a figura da seção 1 mostrou o mesmo caminho:
cliente.messages.create(model="claude-haiku-5-5", max_tokens=200, messages=[{
"role": "user", "content": [
{"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": imagem_b64}},
{"type": "text", "text": "Descreva a imagem."},
]}])
Na execução, a imagem era um PNG de 1000 por 1000 pixels gerado no próprio script, com 4368 bytes. Em base64 ela virou um texto de 5824 caracteres, e a requisição que chegou ao servidor local teve 6033 bytes no corpo. O servidor registrou o tipo de cada bloco na ordem em que vieram:
PNG 1000x1000 gerado: 4368 bytes, base64 com 5824 caracteres
-- o servidor recebeu (1. imagem base64)
POST /v1/messages beta=None ctype=application/json corpo=6033 B {'blocos': ['image/base64', 'text']}
Esse número de bytes é o motivo da seção 6. Uma imagem de 4 KB é pequena, e uma foto de celular passa fácil de 3 MB. Se essa foto entra em base64 em cada turno de uma conversa, cada chamada carrega um JSON enorme só para repetir o que o modelo já leu.
Quando a conversa tem várias imagens, a documentação sugere uma etiqueta de texto antes de cada uma, como “Imagem 1:” e “Imagem 2:”, para que a pergunta possa citar cada uma pelo nome. Nos turnos seguintes você não precisa reenviar as imagens anteriores. A documentação diz que o modelo tem acesso a todas as imagens enviadas em turnos anteriores, então perguntas como “essas são parecidas com as duas primeiras?” funcionam sem repetir o conteúdo.
A página de visão lista limitações que valem para qualquer uso sério. O modelo pode errar em imagens de baixa qualidade, rotacionadas ou menores que 200 pixels. As coordenadas que ele devolve são aproximadas. As contagens de objetos são aproximadas, sobretudo com muitos objetos pequenos. E a documentação diz que o Claude não consegue determinar se uma imagem foi gerada por IA. Essas limitações entram no seu desenho: para um uso de alto risco, a saída precisa de revisão humana.
3. PDFs: página é imagem e texto
Segundo a página de suporte a PDF, consultada em 18/10/2026, o sistema trata o documento página por página. Cada página é convertida em uma imagem, e o texto dela é extraído à parte. Os dois seguem juntos para o modelo. A razão é que um texto extraído perde a informação de um gráfico, de uma tabela desenhada ou de um carimbo, e a imagem da página preserva essa informação. Mandar os dois dá ao modelo as duas leituras, e é por isso que o custo de um PDF tem duas parcelas, que a seção 5 separa.
Os requisitos da página são estes. A requisição inteira pode ter até 32 MB, e a própria página faz a ressalva de que o limite varia por plataforma. O número de páginas por requisição é de 600, e cai para 100 quando a janela de contexto da requisição é menor que 1 milhão de tokens. O PDF precisa estar no formato padrão, sem senha nem criptografia. A página também alerta que PDFs densos, com fonte pequena, tabelas complexas ou muitos gráficos, podem encher a janela de contexto antes de bater no limite de páginas. Então o limite de páginas é um teto, e não uma garantia de que o documento cabe.
Um PDF entra na mensagem como bloco document. A página mostra três origens, na mesma lógica das imagens: url, base64 com media_type igual a application/pdf, e file com file_id. O bloco aceita campos opcionais que mudam o comportamento. O campo title dá um nome ao documento. O campo context dá uma descrição que ajuda o modelo a entender do que se trata. E o campo citations com {"enabled": true} liga as citações, que fazem o modelo apontar de qual trecho tirou cada afirmação. A página de Files API mostra exatamente esse bloco com citations ativado.
Um detalhe de plataforma merece registro. A página de PDF avisa que, no Converse API do Amazon Bedrock, a análise visual das páginas exige citações ativadas. Sem elas, o Bedrock cai para extração de texto. Essa exigência é específica do Converse, e a página não a aplica à API direta. Se você usa Bedrock, leia a seção própria da página antes de confiar na leitura de gráficos.
4. Imagem em tokens
A documentação de visão explica a conta com uma imagem de termos simples. O modelo não enxerga pixels um a um. Ele enxerga blocos de 28 por 28 pixels, chamados de patches, e cada patch vale um token visual. Uma imagem custa, portanto, o número de patches que cabem nela, arredondando para cima em cada lado. A fórmula é ⌈largura / 28⌉ × ⌈altura / 28⌉, e o símbolo de teto significa arredondar para o inteiro acima. Uma imagem de 1000 por 1000 pixels dá 36 patches em cada lado, então 1296 tokens. Uma de 200 por 200 pixels dá 8 por 8, então 64 tokens.
Essa conta depende das dimensões em pixels, e não do tamanho do arquivo em bytes. Por isso duas imagens de peso muito diferente podem custar a mesma coisa. A razão está no teto de resolução de cada modelo. A documentação define dois níveis. No nível padrão, usado pelos modelos anteriores ao Claude 4.7, o lado maior é limitado a 1568 pixels e o total a 1568 tokens. No nível de alta resolução, dos modelos Claude 4.7 em diante, o lado maior vai até 2576 pixels e o total até 4784 tokens. Uma imagem maior que o teto é reduzida, mantendo a proporção, até caber. A página de visão informa que os modelos de alta resolução podem gastar até cerca de três vezes mais tokens que o nível padrão para a mesma imagem.
A tabela da documentação mostra o efeito. Uma captura de 3840 por 2160 pixels, com mais de 8 milhões de pixels, é reduzida no nível padrão para 1456 por 819, e custa 1560 tokens. Uma foto de 1920 por 1080 pixels custa o mesmo 1560 no nível padrão, mesmo sendo bem menor em pixels. O teto de custo é o que a redução garante. A consequência para o seu código é direta: se a pergunta não precisa de detalhe fino, reduzir a imagem antes de enviar corta a conta sem mudar a resposta, e reduz também a latência. A própria página de visão recomenda redimensionar antes de subir o arquivo.
O código abaixo confere a fórmula contra os valores da tabela. Ele não chama a API. Roda só a aritmética, e a saída mostra que os valores batem:
import math
casos = [
("200x200", 200, 200, 64),
("1000x1000", 1000, 1000, 1296),
("1092x1092", 1092, 1092, 1521),
("1456x819 (reduzida no padrão)", 1456, 819, 1560),
("1920x1080 alta, sem reduzir", 1920, 1080, 2691),
("2000x1500 alta", 2000, 1500, 3888),
("2576x1449 alta (4K reduzida)", 2576, 1449, 4784),
]
for nome, w, h, doc in casos:
tokens = math.ceil(w / 28) * math.ceil(h / 28)
print(f"{nome:32s} calculado={tokens:5d} doc={doc:5d} {'OK' if tokens == doc else 'DIFERE'}")
200x200 calculado= 64 doc= 64 OK
1000x1000 calculado= 1296 doc= 1296 OK
1092x1092 calculado= 1521 doc= 1521 OK
1456x819 (reduzida no padrão) calculado= 1560 doc= 1560 OK
1920x1080 alta, sem reduzir calculado= 2691 doc= 2691 OK
2000x1500 alta calculado= 3888 doc= 3888 OK
2576x1449 alta (4K reduzida) calculado= 4784 doc= 4784 OK
Uma observação sobre o que a fórmula não cobre. Ela calcula corretamente os casos em que a imagem já cabe no teto, e os casos que a documentação lista como reduzidos, quando você passa as dimensões já reduzidas. A regra exata de redução, com o algoritmo de referência, está na página de coordenadas da visão, que não foi lida nesta sessão. Para estimar uma imagem grande sem redução manual, use a contagem de tokens da API e não a fórmula sozinha.
Para transformar tokens em dinheiro, multiplique pelo preço por token do modelo que você usa. A documentação de visão dá exemplos com preços, mas eu não os copiei, porque preço muda e o número de hoje pode não valer amanhã. O caminho é a página de preços oficial.
Há um ponto sobre conversas com várias imagens. A documentação diz que, em conversas com várias rodadas, cada requisição reenvia o histórico inteiro. Uma imagem enviada no primeiro turno volta a ser entrada em todas as chamadas seguintes, a menos que o prefixo esteja em cache. Por isso uma conversa de dez turnos sobre a mesma planta baixa paga pela planta dez vezes, e o cache de prompt, que é assunto de Prompt e contexto, costuma ser a defesa mais direta.
5. PDF em tokens
O custo de um PDF tem duas partes, como a seção 3 explicou. A parte de texto é o texto extraído de cada página. A página de suporte a PDF estima entre 1500 e 3000 tokens por página, dependendo da densidade do conteúdo, e informa que o preço padrão da API se aplica sem taxa extra para PDF. A parte de imagem vem da renderização de cada página, e nela vale a mesma conta de patches da seção 4.
Para um documento de 100 páginas, a parte de texto sozinha fica entre 150 mil e 300 mil tokens, pela faixa que a documentação dá. A parte de imagem depende de como cada página é renderizada, e a documentação não informa esse número. Então a estimativa honesta é de ordem de grandeza: a parte de texto é conhecida pela faixa, e a parte de imagem só se mede. A página de PDF indica a contagem de tokens como caminho para estimar o custo de um arquivo específico. 1.3 Mecânica da API Claude citou o endpoint /v1/messages/count_tokens ao falar de estimativa. Não confirmei nesta sessão se esse endpoint aceita blocos document com PDF ou file_id, então trate isso como algo a testar antes de depender dele.
Na prática, a conta sugere uma pergunta de projeto antes de qualquer código: o documento inteiro precisa estar no contexto para a pergunta? Se a resposta for não, a seção 10 mostra o que fazer.
Parte 2: a Files API
6. Por que reenviar pesa
Levar o contrato impresso a cada reunião funciona, mas é um jeito caro de trabalhar. Guardar o contrato no arquivo do escritório e citar o número do protocolo nas reuniões seguintes é outro jeito, e o protocolo cabe num post-it. A Files API é o arquivo do escritório: você envia o documento uma vez, recebe um identificador e passa a usar esse identificador nas chamadas seguintes.
O problema que ela resolve aparece em dois cenários. No primeiro, uma aplicação faz várias perguntas sobre o mesmo documento. Sem a Files API, cada pergunta leva os bytes do PDF, em base64 ou por URL. No segundo, uma conversa tem muitos turnos ou um agente encadeia dezenas de chamadas, e o histórico inteiro volta em cada uma. A página de visão observa exatamente isso: se as imagens estão em base64, os bytes completos entram no payload de cada turno, e o tamanho da requisição cresce junto com a conversa. Referenciar pelo file_id mantém o payload pequeno, qualquer que seja o número de imagens acumuladas.
A figura da seção 8 mostra o ciclo completo. Antes dela, vale a execução real. O script abaixo sobe um PDF e depois faz duas perguntas sobre ele. O PDF é um arquivo de 200 KB com cabeçalho %PDF e conteúdo inventado, que o servidor local não interpreta. Serve para medir o tráfego, não para testar leitura de documento.
7. Upload, file_id e uso
O upload é uma requisição POST /v1/files com corpo multipart/form-data. O arquivo vai no campo chamado file. A página da Files API mostra a forma em cURL com -F "file=@...", e o SDK faz o mesmo quando você chama client.files.upload. A resposta traz os campos documentados: id (no formato file_ seguido de caracteres), type com o valor file, filename, mime_type, size_bytes, created_at, downloadable e expires_at. Dois desses campos merecem atenção imediata. O downloadable vem como false para arquivos que você sobe, porque só são baixáveis os arquivos gerados por skills ou pela ferramenta de execução de código. O expires_at vem como null quando o arquivo não tem prazo, que é o padrão.
Este é o trecho do script que faz o upload, seguido da referência numa mensagem:
arquivo = cliente.files.upload(file=("contrato.pdf", pdf, "application/pdf"))
print(f"upload feito: id={arquivo.id} downloadable={arquivo.downloadable} expires_at={arquivo.expires_at}")
Na execução, o servidor local registrou o que chegou. A requisição de upload saiu como multipart/form-data, com o campo file presente, e sem o cabeçalho anthropic-beta:
upload feito: id=file_011CTeste0001 downloadable=False expires_at=None
-- o servidor recebeu (3. upload)
POST /v1/files beta=None ctype=multipart/form-data corpo=200229 B {'campo_file_no_multipart': True}
O beta=None é uma observação sobre o SDK 1.15.0, não sobre o serviço. Ele mostra que o cliente não mandou o header de beta. A seção 9 explica por que isso importa.
Depois do upload, o arquivo entra na mensagem como bloco document (para PDF e texto) ou image (para imagem), com source de tipo file. A forma de referenciar é a mesma nos dois casos, só muda o tipo do bloco. Para datasets e outros formatos usados pela ferramenta de execução de código, a página indica um bloco container_upload, que não foi exercitado aqui.
Três limites de formato valem na hora de subir. A Files API aceita PDF e texto puro como document, e imagens como image. Formatos como .docx e .xlsx não entram como document: a página de Files API recomenda converter para texto, ou para PDF quando há imagens no documento. Um .csv ou um .md podem ser lidos como texto no próprio prompt ou subidos como text/plain. E um arquivo, depois de subido, não pode ser alterado nem renomeado. Para mudar o conteúdo, você sobe outro arquivo e apaga o antigo.
8. Reuso, expiração e exclusão
O reuso é a parte que justifica a API. O script abaixo faz duas perguntas com o mesmo file_id:
for pergunta in ["Qual é a data do contrato?", "Qual é o prazo de rescisão?"]:
cliente.messages.create(model="claude-haiku-5-5", max_tokens=200, messages=[{
"role": "user", "content": [
{"type": "document", "source": {"type": "file", "file_id": arquivo.id}},
{"type": "text", "text": pergunta},
]}])
A saída mostra o tamanho de cada corpo que chegou ao servidor. O upload levou 200229 bytes, uma vez só. As duas perguntas levaram 215 e 217 bytes, porque cada uma carrega apenas o identificador e o texto:
-- o servidor recebeu (4. duas chamadas reusando o file_id)
POST /v1/messages beta=None ctype=application/json corpo=215 B {'blocos': ['document/file', 'text']}
POST /v1/messages beta=None ctype=application/json corpo=217 B {'blocos': ['document/file', 'text']}
A diferença de tamanho entre o upload e as chamadas é o argumento central. Num cenário real, em que o PDF tem megabytes, cada pergunta reenviada em base64 pagaria esse custo de transporte de novo. Com o arquivo guardado, o custo de transporte é pago uma vez. Repare que isso fala de tamanho de requisição. A conta de tokens do documento continua existindo, porque o modelo lê o documento em cada chamada, e a seção 5 mostra essa parte.
O arquivo fica guardado até uma de duas coisas acontecer: você o apaga, ou ele atinge o expires_at. Esse prazo é definido no upload, com o campo de formulário expires_in_seconds. O valor vai de 3600 segundos (uma hora) a 7776000 (90 dias), e não pode ser alterado depois. Quando o arquivo chega ao prazo, a página de Files API descreve três efeitos. O download do conteúdo passa a dar 404. Uma mensagem que referencia o arquivo falha antes da inferência, ou seja, o modelo nem chega a ler. E os metadados continuam legíveis por até 30 dias, com o expires_at no passado. Para um arquivo temporário, como o anexo de uma sessão de suporte, o prazo curto é uma defesa que dispensa limpeza manual.
A exclusão é feita com DELETE /v1/files/{file_id}. Ela é definitiva: a página diz que o arquivo apagado não pode ser recuperado, e que deixa de ser acessível pela API pouco depois. A mesma página faz uma ressalva que importa: o arquivo pode continuar presente em chamadas de Messages que já estavam em andamento e nas ferramentas associadas. Por isso, apagar não é uma interrupção instantânea de tudo que estava em voo.
A figura acompanha o ciclo. O upload entra pela esquerda e o arquivo fica no cilindro verde, dentro do retângulo tracejado que representa o workspace. As duas chamadas leem o mesmo identificador, sem reenviar nada. Quando o uso acaba, o DELETE remove o arquivo. A linha rosa com o ✕ mostra o caminho de falha: uma chamada que ainda usa o id antigo é barrada e recebe 404. O outro caminho, pontilhado, é a expiração pelo relógio, que leva ao mesmo resultado sem nenhuma ação do seu código. A seção 11 mostra por que a fronteira do workspace decide quem consegue usar o arquivo.
A execução confirmou o caminho de falha contra o servidor local. O script apagou o arquivo e tentou usá-lo de novo:
apagado: file_011CTeste0001
chamada depois da exclusão: NotFoundError status=404 tipo=not_found_error
O 404 veio do servidor simulado, que foi programado para responder assim. A documentação lista o erro not_found_error com status 404 para um file_id inexistente ou inacessível, então o formato é o documentado, mas o comportamento real do serviço depois de uma exclusão, no tempo de propagação, não foi testado contra a API.
Dois limites de capacidade completam a seção. Cada arquivo pode ter até 500 MB, e a organização pode ter até 1 TB de armazenamento no total. Chamadas da Files API, como upload, listagem e consulta de metadados, têm um limite aproximado de 500 requisições por minuto, que a documentação diz poder ser aumentado sob pedido. As operações de upload, download, listagem, metadados e exclusão são gratuitas. O conteúdo de arquivo usado em mensagens é cobrado como token de entrada, e isso conecta esta seção à conta da seção 5.
9. Estado da API: GA e o header legado
A pergunta de estado tem resposta curta, mas o ponto precisa de cuidado. A página da Files API, consultada em 18/10/2026, marca a funcionalidade como disponível geralmente (GA) na API Claude e em outras plataformas. O texto diz que a Files API saiu do beta e não exige header beta. O header que aparecia nos exemplos antigos, anthropic-beta: files-api-2025-04-14, continua funcionando por compatibilidade, mas faz as requisições voltarem com os formatos de resposta da versão beta. Se você ainda usa esse header, a página lista as diferenças: a listagem usa data, has_more, first_id e last_id, em vez do cursor next_page; o campo expires_at só aparece quando o header está presente; e o Content-Type da parte do arquivo era obrigatório.
A migração é opcional, mas a página recomenda três passos: remover o header, trocar a paginação por next_page e ler expires_at. No SDK Python, a documentação diz que, a partir da versão 1.2.0, client.beta.files deixou de mandar o header. A página recomenda usar client.files, que é o que o script desta aula usou com o SDK 1.15.0, e o log do servidor confirmou a ausência do header na requisição de upload.
A armadilha é conhecida. Material antigo, escrito quando a Files API era beta, trata o header como obrigatório e a funcionalidade como experimental. Se alguma fonte apresentar a Files API como beta, verifique a data dela, porque o estado atual é GA.
Há um ponto de documentação que não fecha. A página de visão tem uma pergunta frequente que diz que uploads de imagem são efêmeros, que não é possível apagá-los e que eles não ficam guardados além da requisição. A página da Files API diz o contrário para arquivos enviados por ela: eles persistem até serem apagados ou atingirem o expires_at. Os dois textos não podem valer ao mesmo tempo para a mesma operação. Esta aula segue a página da Files API, que é a específica para armazenamento, mas o conflito fica registrado como ponto a confirmar antes de qualquer decisão de privacidade.
Parte 3: decidir e proteger
10. Enviar, reusar ou recortar
A escolha entre os caminhos depende de três perguntas: o arquivo se repete, quanto dele a pergunta precisa, e quem pode vê-lo. As duas primeiras decidem a técnica de transporte, e a terceira decide se a técnica é segura, como a seção 11 detalha.
Envie inline, em base64 ou por URL, quando o arquivo é usado uma vez, ou quando ele é pequeno e a conversa é curta. Nesse caso a Files API só acrescenta uma etapa e uma coisa para limpar depois. A URL tem a vantagem de não carregar bytes no seu código, mas você entrega ao serviço o controle de buscar o arquivo, e o endereço precisa ser acessível do lado da API. Quando a URL aponta para algo que muda, o resultado muda junto, então ela não serve para reprodutibilidade.
Suba para a Files API quando o mesmo arquivo serve a várias chamadas, ou quando a conversa tem muitos turnos e o histórico cresce. O ganho aparece na requisição, que fica pequena, e no tempo de resposta, que deixa de pagar o custo de transporte de megabytes a cada pergunta. O custo de tokens do documento continua existindo em cada chamada, então a Files API não é uma forma de reduzir a conta de entrada. Ela reduz o tráfego e a repetição de bytes.
Recorte quando a pergunta trata de uma parte do documento. Um manual de 300 páginas para responder uma pergunta sobre a garantia não precisa estar inteiro no contexto. Há duas formas de recortar. A primeira é escolher as páginas relevantes antes da chamada e enviar só elas, com uma ferramenta de manipulação de PDF no seu código. A segunda é indexar o documento em pedaços e recuperar só os trechos que parecem relevantes para a pergunta, que é a ideia de RAG. O recorte tem um risco que o RAG também tem: se a página certa não for escolhida, o modelo responde com base no que recebeu, e a resposta pode parecer correta sem ser. Por isso a avaliação do recorte é tão importante quanto o próprio recorte.
Não reenvie o que já está na conversa. A regra vale para imagens e documentos. Se a imagem já foi enviada num turno anterior, o modelo a enxerga nos turnos seguintes, como a seção 2 mostrou. Repetir o bloco só aumenta o payload e a conta de entrada, sem ganho de informação.
Este quadro resume a decisão, com os mesmos casos das seções anteriores:
| Situação | Caminho | Por quê |
|---|---|---|
| Uma imagem pequena, uma pergunta | base64 inline | Não vale uma etapa de upload para um uso só. |
| Um PDF com dez perguntas seguidas | Files API com file_id | O transporte acontece uma vez e as referências são pequenas. |
| Uma captura de tela num fluxo de agente | URL, se for pública e estável, ou base64 | Depende de quem controla o endereço e de quanto o agente reenvia. |
| Um manual longo para uma pergunta específica | Recorte de páginas ou RAG | A conta de tokens cai, e a pergunta fica no que importa. |
| Um documento que depende de ser lido inteiro | Files API, com contagem de tokens antes | O recorte pode perder a relação entre partes distantes. |
11. Dados sensíveis em arquivos
Um arquivo enviado para a API é uma cópia do dado, e a cópia tem vida própria. Esta seção reúne o que a documentação diz sobre isso, e marca o que é recomendação deste material e não um fato da documentação.
O primeiro ponto é o escopo de acesso. A página da Files API diz, em aviso destacado, que os arquivos enviados ficam acessíveis a todo o workspace, e não a um usuário final, uma conversa ou uma sessão. Qualquer chave de API com acesso ao workspace pode ler qualquer arquivo dele. A página também alerta que contas de serviço e usuários cuja função na organização permite acesso à API podem usar o Default Workspace, além dos workspaces em que foram adicionados. A consequência prática é que dados de clientes diferentes não devem compartilhar workspace. A documentação recomenda um workspace por inquilino em aplicações multi-inquilino, e informa que cada organização pode ter até 100 workspaces, com possibilidade de pedir mais ao time comercial.
O segundo ponto é a segurança do file_id como referência. O identificador, por si, funciona como uma chave de acesso dentro do workspace. Por isso a documentação diz para nunca aceitar file_id vindo de usuário final ou de fonte não confiável. Se a sua aplicação deixa o usuário enviar o identificador de um arquivo, ele pode ler o arquivo de outro usuário, desde que os dois compartilhem o workspace. A regra correta é guardar, no seu banco, o vínculo entre cada usuário e os arquivos dele, e usar esse vínculo para decidir quais identificadores a aplicação monta na requisição. O file_id deve ser tratado como referência interna do servidor.
O terceiro ponto é a retenção. Um arquivo fica guardado até ser apagado ou expirar, e por padrão não expira. Por isso o expires_in_seconds deve ser o padrão para tudo que é temporário. A página de Files API faz uma ressalva importante: expiração não é um mecanismo de exclusão garantida. Depois de expires_at, o conteúdo deixa de ser recuperável pela API e sai da cota de armazenamento, mas o conteúdo pode ser mantido por um período limitado para revisão de segurança antes da exclusão definitiva. Para remover um arquivo antes do prazo, use DELETE. Mesmo assim, a documentação não promete eliminação imediata de cópias internas, e isso deve entrar na avaliação de risco junto com a sua política de retenção.
O quarto ponto é o regime de retenção zero, conhecido pela sigla ZDR, de zero data retention, que significa que o provedor não guarda os dados depois de responder. A página da Files API marca a funcionalidade como não elegível a ZDR. A página de suporte a PDF marca como elegível, com exclusão de modelos cobertos por regras próprias. A consequência é que, numa organização que exige ZDR, a Files API pode não ser o caminho certo, mesmo que o PDF seja. Essa decisão é de conformidade e deve ser tomada antes da técnica. A página de retenção de dados da API, que a documentação cita, é o ponto para verificar a situação da sua organização.
O quinto ponto é a trilha de auditoria. A página da Files API informa que, se a organização tem a Compliance API ativa, a Activity Feed registra upload, download de conteúdo e exclusão feitos com chave de API ou pelo Console. Listagem e consulta de metadados não aparecem. As operações feitas enquanto a Compliance API estava desligada não são recuperadas depois, então a ativação precisa ser anterior ao uso que se quer auditar.
Dois pontos sobre as imagens. A página de visão afirma que o Claude não lê nem recebe metadados das imagens enviadas, e que a Anthropic não usa imagens enviadas para treinar modelos. A primeira afirmação não diz se o arquivo guardado, no caso da Files API, preserva os metadados, como a localização GPS de uma foto de celular. Se esse dado importa, a remoção fica na sua aplicação, antes do upload. A segunda afirmação é da documentação, e deve ser lida junto com a política de privacidade e com o contrato da sua organização. Este material não faz uma avaliação jurídica.
Uma regra prática fecha a seção: trate cada arquivo enviado como um dado que tem dono, prazo e lugar de guarda. Se a sua aplicação não consegue responder essas três perguntas para um arquivo, ele não deveria ter sido enviado.
Parte 4: erros, prática e glossário
12. Erros comuns e boas práticas
O primeiro erro é mandar imagens em base64 a cada turno de uma conversa longa. O payload cresce junto com o histórico, e a aplicação passa a gastar mais tempo transferindo bytes do que esperando o modelo. A correção é subir a imagem uma vez e referenciar o file_id, ou não reenviar o bloco nos turnos seguintes, porque o modelo já tem acesso a ele.
O segundo erro é aceitar file_id do usuário. Ele parece inofensivo porque é só um identificador, mas dentro de um workspace compartilhado o identificador dá acesso ao arquivo. O motivo está na seção 11. A correção é um vínculo no seu banco entre usuário e arquivo, e a aplicação montar a referência sem nunca confiar no que veio do cliente.
O terceiro erro é achar que o arquivo some sozinho. Por padrão ele não expira. Sem expires_in_seconds e sem DELETE, o arquivo continua no workspace indefinidamente, ocupando cota e disponível para qualquer chave com acesso. A correção é definir o prazo no upload para o que é temporário, e apagar explicitamente o que terminou de ser usado.
O quarto erro é tratar a expiração como exclusão garantida. Depois do expires_at, o arquivo deixa de ser utilizável pela API, mas o conteúdo pode ser retido por um tempo para revisão de segurança. Para dado que não pode permanecer nem por pouco tempo, a decisão precisa ser outra: não enviar, ou enviar com uma política de retenção que você pode demonstrar.
O quinto erro é enviar .docx ou .xlsx como documento. A Files API não aceita esses formatos como bloco document. A correção é converter para texto, ou para PDF se houver imagens, e enviar o resultado.
O sexto erro é mandar uma foto de 4000 pixels de lado sem necessidade. O modelo a reduz de qualquer forma, e o custo de transporte e a latência já foram pagos. Reduzir antes do envio, para o tamanho que a pergunta exige, dá o mesmo resultado com menos custo.
O sétimo erro é citar a Files API como beta com base em material antigo. A página atual diz GA e não exige header. O header antigo ainda funciona, mas muda o formato de resposta. A correção é olhar a data da fonte e a página viva antes de escrever código.
O oitavo erro é confiar no texto extraído de um PDF sem olhar as páginas com gráficos. A análise de imagem da página é o que permite ler a tabela desenhada e o gráfico. Se a sua pergunta depende de um número num gráfico, peça a referência da página e confira na origem.
Como prática, guarde um padrão simples: uma função que monta o bloco de mídia a partir de uma decisão explícita (inline, upload, recorte), um vínculo entre usuário e file_id no banco, expires_in_seconds em tudo que é temporário, uma rotina que apaga o que terminou de ser usado e uma contagem de tokens antes de qualquer lote grande.
13. Exercícios
-
Rode o script da seção 4 com outras três dimensões que você escolher, e confira o resultado com a tabela da documentação de visão. Depois escolha uma imagem real de 4000 pixels de lado e calcule o número de tokens com a fórmula, sabendo que a redução do nível padrão pode mudar as dimensões.
-
Monte o PDF de teste do script da seção 7 com um tamanho de 2 MB, e meça o tamanho do corpo do upload e o das chamadas seguintes. Confira que a diferença continua sendo a do transporte, e que a conta de tokens não muda por causa do upload.
-
Faça um upload com
expires_in_seconds=3600e confira o campoexpires_atna resposta. Depois descreva o que seu código faz quando uma chamada falha com 404 por causa de um arquivo expirado. -
Escreva a função que decide, para cada anexo de uma aplicação, entre base64, URL, upload ou recorte, e justifique cada ramo com uma das perguntas da seção 10.
-
Desenhe a tabela que liga usuário, workspace e
file_idno seu banco. Verifique que nenhum identificador vindo do cliente chega à requisição sem passar por essa tabela. -
Use a contagem de tokens da API, se ela aceitar o seu PDF, para comparar o custo do documento inteiro com o de um recorte de dez páginas. Antes disso, confirme na documentação de contagem de tokens quais blocos ela aceita.
-
Liste os tipos de arquivo que a sua aplicação recebe hoje. Para cada um, diga se a Files API o aceita como
documentouimage, se precisa de conversão e se os dados são sensíveis.
14. Glossário
| Termo | Significado |
|---|---|
| Bloco de conteúdo | Objeto com campo type que compõe o content de uma mensagem. Pode ser text, image, document e outros. |
| Base64 | Forma de escrever bytes com caracteres imprimíveis, que aumenta o tamanho em cerca de um terço. |
| Source | Campo do bloco de mídia que diz a origem do conteúdo: base64, url ou file. |
| Patch | Bloco de 28 por 28 pixels, a unidade que o modelo enxerga numa imagem. |
| Token visual | Um patch. A conta de tokens de imagem é o número de patches. |
| Redução | Diminuição automática de imagem maior que o teto do nível do modelo, mantendo a proporção. |
| Alta resolução | Nível de teto maior, para os modelos Claude 4.7 em diante, com até 2576 pixels no lado maior. |
| Files API | Armazenamento de arquivos da API, com upload, referência por file_id, listagem, metadados, download quando permitido e exclusão. |
| file_id | Identificador de um arquivo guardado no workspace. Deve ser tratado como referência interna do servidor. |
| Workspace | Fronteira de acesso a arquivos. Qualquer chave com acesso ao workspace lê os arquivos dele. |
| expires_at | Momento, em RFC 3339, em que o arquivo deixa de ser utilizável pela API. Definido no upload. |
| GA | Disponibilidade geral, o estado de uma funcionalidade fora do beta. |
| ZDR | Retenção zero de dados: o provedor não guarda os dados depois de responder. |
| Recorte | Envio de só parte do documento, por escolha de páginas ou por recuperação de trechos. |
15. Fontes
Consultadas em 18/10/2026, com os links oficiais. Os fatos desta aula vêm dessas páginas, exceto os pontos marcados como não verificados.
- Visão (formatos, limites de imagem, custo em tokens, tabela de redução, FAQ): https://platform.claude.com/docs/en/build-with-claude/vision
- Suporte a PDF (limites, origens, custo por página, cache e observação sobre citações no Bedrock): https://platform.claude.com/docs/en/build-with-claude/pdf-support
- Files API (upload, bloco
documentcomfile, exclusão, expiração, workspace, estado GA, migração e faturamento): https://platform.claude.com/docs/en/build-with-claude/files - SDK Python
anthropic, versão 1.15.0, usada na execução de 18/10/2026.
A página da Files API mostra o estado GA nos metadados da própria página e no texto da seção de migração. Não há indicação de beta na versão consultada.
O que não foi verificado, ou ficou com ressalva:
- A página de visão não foi lida na íntegra para as regras de redução com o algoritmo de referência. Essas regras estão na página de coordenadas, linkada por ela, que não foi aberta.
- O limite de 32 MB para a requisição vem citado pelas páginas de visão e de PDF, com a ressalva de que varia por plataforma. A página de visão geral da API, que o documenta, não foi aberta diretamente.
- A parte de imagem do custo de PDF depende da renderização das páginas, e a documentação não informa o número. Só a faixa de texto por página foi conferida.
- Não confirmei se o endpoint de contagem de tokens aceita blocos
documentcom PDF ou comfile_id. - O corpo da resposta do
DELETE /v1/files/{file_id}não está descrito na página lida. O servidor local respondeu com um formato próprio, e o código da aula não depende desse corpo. - Os métodos de listagem e de metadados do SDK,
client.files.listeclient.files.retrieve_metadata, não foram executados nesta sessão. - A conduta real da API para uma mensagem que referencia um arquivo recém-apagado, no tempo de propagação, não foi testada contra o serviço. O 404 da execução veio do servidor simulado.
- A página de visão e a página da Files API divergem sobre a persistência de imagens enviadas. A aula segue a página da Files API e registra o conflito.
- O limite aproximado de 500 requisições por minuto para chamadas de arquivo vem da página da Files API, sem garantia de valor atual.
- A exigência de citações no Converse do Bedrock não foi verificada na API direta, e a aula não a generaliza.
- Os exemplos rodaram contra um servidor local que imita o formato documentado. Não houve chamada à API real, e nenhuma chave real foi usada.