Enviar um POST JSON com Python requests
requests.post(url, json=payload) envia um corpo JSON a um servidor em uma única linha. O argumento json= serializa o dicionário, define o cabeçalho Content-Type: application/json e escreve o corpo da requisição. A resposta retorna um código de status e, na maioria das APIs, os dados que o servidor armazenou, permitindo confirmar que a chamada fez o que era esperado. Este é o padrão por trás de escritas em REST APIs, webhooks e qualquer endpoint que espera uma carga JSON.
Exemplo Python requests.post para JSON
Saída:
A saída aparecerá aqui...
Saída:
Status: 201
Server stored: {'language': 'Python', 'stars': 3, 'id': 101}
Como Este Exemplo Funciona
json=serializa o dict e defineContent-Type: application/json, para que o servidor receba um objeto JSON em vez de campos de formulário.timeout=10limita a espera, para que um endpoint inacessível falhe rapidamente em vez de bloquear a execução.raise_for_status()converte uma resposta 4xx ou 5xx em exceção, para que uma resposta com falha nunca flua silenciosamente para a próxima linha.response.json()retorna a resposta como um dict Python. Esta API de teste devolve seus campos e adiciona umidatribuído pelo servidor; o status201 Createdconfirma que a chamada foi tratada como um novo recurso.
Verificar o que o Servidor Realmente Recebeu
Dois sinais independentes confirmam que o POST funcionou; uma verificação confiável usa os dois. O corpo da resposta prova que o conteúdo chegou: campos devolvidos mais um novo id significam que o servidor interpretou o JSON. Run Details prova o transporte: registra a requisição que o navegador realmente enviou.
| Sinal do Run Details | O que confirma |
|---|---|
| Um POST para jsonplaceholder.typicode.com, status 201 | A chamada saiu como POST e o servidor criou um recurso |
| A coluna de método mostra POST, não GET | requests.post enviou o verbo desejado |
| A duração da requisição em ms | Tempo de ida e volta, medido separadamente do parsing JSON |
| Status bloqueado ou falhou, sem código HTTP | A requisição não chegou ao servidor (ver CORS abaixo) |
| Packages lista requests | web.run carregou o pacote requests ao importar |
Quando o código de status é 2xx mas o corpo retornado não tem seus campos, o transporte funcionou e o conteúdo não. Essa distinção é o que a maioria dos tutoriais de POST não consegue mostrar, pois nunca colocam a requisição enviada e a resposta do servidor lado a lado.
json vs data: O Bug Silencioso de Perda de Dados
Enviar o mesmo payload com data= em vez de json= faz o servidor responder com 2xx mesmo assim, mas o corpo retornado não terá seus campos. A requisição estava correta; a codificação estava errada.
| Argumento | O que requests envia | O que o servidor interpreta |
|---|---|---|
json={"stars": 3} | corpo JSON e Content-Type: application/json | um objeto JSON |
data={"stars": 3} | corpo form-encoded e application/x-www-form-urlencoded | campos de formulário, não JSON |
data=json.dumps({"stars": 3}) | string JSON bruta sem cabeçalho JSON | texto que pode se recusar a interpretar como JSON |
Regra: passe um dict para json= em qualquer API que espere um corpo JSON, e use data= apenas ao enviar um formulário HTML. Uma API JSON que recebe form encoding normalmente responde 2xx e descarta os dados silenciosamente, por isso verificar apenas o código de status nunca é suficiente.
Quando um POST do Navegador É Bloqueado, Não Rejeitado
Um POST cross-origin se comporta diferente no navegador do que em um script de servidor. Como o corpo é application/json, o navegador envia um preflight CORS OPTIONS antes do POST. Se o endpoint não retornar os cabeçalhos Access-Control-Allow-Origin e Access-Control-Allow-Headers correspondentes, o navegador bloqueia o POST antes que ele saia.
Quando isso acontece, requests lança um erro de conexão como requests.exceptions.ConnectionError, não HTTPError, e Run Details marca a requisição como bloqueada ou falhou sem código HTTP. Um 403 ou 422 é o sinal contrário: a requisição chegou ao servidor, que decidiu rejeitá-la.
Regra: nenhum código HTTP significa um problema de rede ou CORS antes do servidor; um código HTTP significa que o servidor respondeu, mesmo que com erro. jsonplaceholder é compatível com CORS, então o exemplo envia corretamente. Muitas APIs públicas não são, razão pela qual o mesmo código requests.post pode funcionar em um terminal mas falhar neste runtime ou em qualquer Python no navegador.
Erros Comuns
Erro: enviar um dict com data= quando a API espera JSON.
Incorreto:
requests.post(url, data={"stars": 3})
Correto:
requests.post(url, json={"stars": 3})
Por que acontece: data= form-codifica o dict e define um Content-Type de formulário, então uma API JSON não recebe objeto JSON e seus campos desaparecem do resultado.
Erro: serializar o corpo duas vezes.
Incorreto:
requests.post(url, json=json.dumps({"stars": 3}))
Correto:
requests.post(url, json={"stars": 3})
Por que acontece: json= já serializa o valor. Passar uma string já construída a codifica duplamente como string JSON em vez de um objeto.
Enviar Cabeçalhos e Auth com o POST
A maioria das APIs de escrita requer autenticação, que viaja nos cabeçalhos da requisição ao lado do corpo:
response = requests.post(
url,
json=payload,
headers={"Authorization": "Bearer TOKEN"},
timeout=10,
)
requests combina seus cabeçalhos com o Content-Type que define para json=, então você fornece apenas o que é específico da API. Nunca codifique um token real em código compartilhado; leia-o de uma variável de ambiente. Um cabeçalho personalizado como Authorization já é suficiente para acionar o preflight CORS descrito acima. Para o lado de leitura correspondente, veja ler JSON de uma URL, e envolva a chamada em try/except para tratar erros de conexão.
FAQ
Como enviar um POST em Python?
Chame requests.post(url, json=payload) com um dicionário como carga. O argumento json= serializa o dict, define o cabeçalho Content-Type: application/json e envia em uma única chamada. Leia a resposta com response.json().
Por que meu POST retorna 200 mas o servidor ignora os dados?
O corpo foi enviado no formato errado, normalmente como campos de formulário via data= em vez de JSON via json=. O servidor responde 2xx à requisição em si mas nunca interpreta um objeto JSON. Mude para json= e confirme que o servidor devolveu seus campos.
Por que meu POST com requests está bloqueado no navegador?
Um POST JSON cross-origin aciona um preflight CORS. Se o endpoint não retornar Access-Control-Allow-Origin e Access-Control-Allow-Headers, o navegador bloqueia a requisição antes que ela saia; requests lança um erro de conexão sem código HTTP em vez de um 4xx. O mesmo código pode funcionar em um terminal.
Qual é a diferença entre json e data no requests.post?
json= serializa um dict em corpo JSON e define Content-Type: application/json. data= envia campos form-encoded ou uma string bruta sem o cabeçalho JSON. Use json= para APIs JSON e data= para envios de formulários HTML.