API do Mercado Livre: o que ela devolve de dado de venda (e o que não devolve)
O /orders do Mercado Livre traz a comissão em sale_fee, mas o frete do vendedor exige /shipments/{id}/costs e a devolução vive em outro recurso.
A API do Mercado Livre devolve o pedido em GET /orders/$ORDER_ID com preço, quantidade e a comissão de cada item no campo sale_fee, mas não devolve o custo do frete do vendedor: esse exige uma segunda chamada, a /shipments/$SHIPMENT_ID/costs. A devolução fica em outro recurso, o /post-purchase, e os pedidos ficam salvos por até 12 meses (documentação de Orders, atualizada em 21/09/2026 e lida em 3 de novembro de 2026).
Em dois posts anteriores desta série eu disse que não tinha conseguido ler essa documentação. Desta vez li. Tudo abaixo tem o nome do campo como está na doc, com o link e a data de atualização que a página mostra.
A margem da venda não está no pedido. No Mercado Livre, receita, comissão, frete, desconto e devolução moram em recursos diferentes. Quem soma só o
/ordersmede faturamento bruto e chama de venda.
Qual é o sintoma?
O relatório de vendas do Mercado Livre não fecha com o repasse, e a diferença não cabe na comissão que alguém tem de cabeça. Ou a contagem de pedidos da integração não bate com a de “vendas” do painel do vendedor, e os dois números parecem certos.
Os dois vêm do mesmo erro: a integração leu um recurso só e o tratou como a venda inteira.
O que o /orders devolve, campo por campo?
O pedido responde em GET https://api.mercadolibre.com/orders/$ORDER_ID. A documentação lista estes campos de resposta, entre outros (Orders):
| Campo | O que a doc diz | O que isso significa para o número |
|---|---|---|
total_amount | "valor total da order" | É o valor do produto. Frete do vendedor não entra |
order_items[].unit_price | preço unitário, "após aplicar os descontos" | Já é líquido de desconto |
order_items[].gross_price | (unit_price + discounts.full) × quantity | Preço cheio. "Pode não estar presente em pedidos antigos" |
order_items[].sale_fee | "comissão de vendas" | Calculada "no momento da acreditação do pagamento" |
shipping.id | "ID do envio para esta order" | Só o ID. O custo está em outro recurso |
buyer.id | informações do comprador | No exemplo da doc, só o ID numérico |
context.channel | proximity | mp-channel | marketplace | Canal de venda do Mercado Livre, não origem de tráfego |
cancel_detail | group, code, requested_by, date | Quem cancelou e por quê |
Duas notas mudam a extração. A primeira: o recurso pode responder 206 Partial Content, com o cabeçalho X-Content-Missing listando os campos vazios; o exemplo publicado mostra buyer e feedback faltando. Quem aceita essa resposta sem ler o cabeçalho grava pedido com comprador nulo.
A segunda: context.channel não responde “de onde veio a venda”. Entre os campos documentados do pedido não há nenhum de origem de tráfego, campanha ou clique. É o mesmo desenho que descrevi em marketplace como buraco negro de dados: o canal entrega volume e não entrega procedência.
O que precisa de mais de uma chamada?
Quase tudo o que transforma faturamento em margem. A tabela é o mapa mínimo de recursos para fechar uma venda:
| Dado | Recurso | Campo |
|---|---|---|
| Itens do carrinho | /packs/$PACK_ID | pedidos do pack (relação 1 para N) |
| Frete pago pelo vendedor | /shipments/$SHIPMENT_ID/costs | senders[].cost, gross_amount |
| Envios e devoluções de um pedido | /orders/$ORDER_ID/shipments | type: forward, return |
| Descontos e quem os pagou | /orders/$ORDER_ID/discounts | amounts.total, amounts.seller |
| Documento fiscal do comprador | /orders/billing-info/{site_id}/{billing_info_id} | doc_type, doc_number |
| Devolução e dinheiro | /post-purchase/v2/claims/$CLAIM_ID/returns | status_money, refund_at |
| Cobranças do mês | /billing/integration/periods/key/{key}/summary/details | charges[].type, amount |
Carrinho. A doc de Packs (atualizada em 29/12/2025) diz que o pack “torna-se um componente obrigatório em todas as compras, pois todos os pedidos estarão associados a um pack_id”, com relação de 1 para N entre pack e pedidos. Contar order_id conta pedido, não compra. É um bom primeiro suspeito quando a contagem da integração não bate com a do painel.
Frete. O recurso /shipments/$SHIPMENT_ID/costs (atualizado em 18/09/2026) devolve gross_amount, descrito como “o custo total do shipment sem nenhum tipo de desconto”, e a lista senders com “os valores pagos pelo vendedor”. A mesma doc avisa que um envio “poderá conter produtos de diferentes vendedores”. Para chegar ao total com frete, a doc de Orders publica a fórmula total_amount_with_shipping = total_amount + taxes.amount + lead_time.cost, e o lead_time.cost só existe em /shipments.
Comprador. O documento fiscal saiu do pedido. O fluxo atual, segundo a FAQ de Billing info (atualizada em 14/08/2026), é ler buyer.billing_info.id no pedido e consultar /orders/billing-info/{site_id}/{billing_info_id}; a FAQ registra que o endpoint antigo, /orders/{order_id}/billing_info, responde 404. A mesma FAQ avisa que doc_type e doc_number podem vir nulos enquanto o documento fiscal está em PROCESSING, e que o endereço fiscal “pode ser diferente do endereço de entrega”, que mora em /shipments.
O pedido cancelado aparece?
Depende de como você pergunta, e a documentação tem uma armadilha de status.
A busca é GET /orders/search, que “não realiza nenhuma ação se não é seguido por um filtro”. Os filtros incluem order.status, order.date_created.from, order.date_closed.from e order.date_last_updated.from. A doc traz dois avisos que pesam na extração (Orders):
- “os pedidos criados são salvos por até 12 meses e se você pesquisar como vendedor, continuará a filtrar os pedidos cancelados”;
- o filtro de data “usa até a hora e descarta a informação dos minutos, segundos e milissegundos”.
A frase sobre cancelados é ambígua: não deixa claro se o cancelado some do resultado. Teste na sua conta. Se ele some, um pedido que você gravou como pago e foi cancelado depois nunca reaparece na busca para corrigir o seu registro.
A armadilha de status é mais séria. A lista oficial tem confirmed, payment_required, payment_in_process, partially_paid, paid, partially_refunded, pending_cancel, cancelled e invalid. E a doc registra: “uma order não concretizada pelo vendedor será visualizada como ‘Cancelada’ por front e por api terá ‘status = confirmed’”. O mesmo valor, confirmed, é o status inicial de um pedido ainda não pago. Um filtro que exclui só cancelled deixa passar venda que o painel mostra como cancelada.
É a mesma família de erro que vi no pedido cancelado dos ERPs: o cancelado volta pelo mesmo endereço, com cara de venda.
Onde fica a devolução?
Fora do pedido. A doc de Devoluções manda escutar o feed de reclamações, ler related_entities em /claims/$CLAIM_ID e, se houver return, consultar /post-purchase/v2/claims/$CLAIM_ID/returns.
Três campos interessam a quem fecha o mês. status_money admite retained (“dinheiro na conta mas retido”), refunded e available. refund_at diz quando o dinheiro volta ao comprador: shipped, delivered (“3 dias após o vendedor receber o envio”) ou n/a para casos low cost. O subtype separa return_total, return_partial e low_cost.
Para listar as reclamações, a doc de Reclamações documenta GET /post-purchase/v1/claims/search, que exige pelo menos um filtro e aceita stage (claim, dispute, recontact, stale, none). No pedido, o rastro é o status partially_refunded e o envio do tipo return em /orders/$ORDER_ID/shipments.
E as taxas do mês?
Ficam nos relatórios de faturamento, que a própria documentação pede para não usar como fonte de venda. A página de boas práticas dos relatórios de faturamento diz que os recursos são “estritamente destinados a operações de Pós-Venda” e “não devem ser utilizados como fonte de dados primária para gestão de vendas”.
O resumo /billing/integration/periods/key/{key}/summary/details traz as cobranças por type; o exemplo publicado mostra CV (“Cobrança por venda”), CXD (“Cobrança por Mercado Envios”) e PADS (“Campanhas de publicidade - Product Ads”). A regra de conciliação está escrita: a soma de detail_amount por detail_sub_type no detalhe “deve ser igual ao amount para o mesmo type” no resumo. A chave do período é sempre o primeiro dia do mês, YYYY-MM-01.
Como diagnosticar na sua integração?
Rode estas checagens num mês fechado:
| Verificação | Onde olhar | O que indica divergência |
|---|---|---|
| Pedidos por pack | pack_id no /orders | Contagem de pedidos maior que a de vendas do painel |
Status confirmed antigo | order.status=confirmed com date_created de semanas atrás | Venda não concretizada contada como pendente ou como venda |
| Comissão somada | soma de sale_fee × tipo CV do resumo | Diferença indica pedido faltando ou estorno de comissão |
| Frete do vendedor | soma de senders[].cost × tipo CXD | Frete tratado como zero no relatório |
| Respostas parciais | log do cabeçalho X-Content-Missing | Pedidos gravados com comprador nulo |
| Devolução | status_money em /returns | Receita contada com dinheiro retained ou refunded |
Como corrigir?
Escreva a definição antes de escrever a query. “Venda do Mercado Livre” pode ser total_amount dos pedidos paid, ou isso menos sale_fee, menos senders[].cost, menos amounts.seller dos descontos, menos o que voltou com status_money = refunded. São números diferentes e todos defensáveis. O erro é não ter decidido qual. Uma definição escrita e versionada, consultada sempre do mesmo jeito, é o que chamamos de camada semântica.
Na extração, quatro regras práticas tiradas da própria doc:
- Puxe por
order.date_last_updated, não por data de criação. É o filtro que pega o pedido que mudou de status depois de carregado. Como a busca descarta minutos, sobreponha a janela em pelo menos uma hora. - Guarde tudo. Pedido com mais de 12 meses sai do alcance da API, e o histórico passa a existir só se você o salvou.
- Renove o token antes de expirar. A doc de autenticação informa
expires_in: 21600(6 horas). Orefresh_tokené “de utilização única” e expira em 6 meses. Rotina noturna que perde o refresh para de carregar em silêncio. - Não paralelize os relatórios de faturamento. A doc recomenda “uma chamada por seller, uma vez ao dia”, paginação por
from_id(ooffsetpara em 10.000) e trata o 429 desses endpoints como “bloqueio preventivo por IP”.
O limite geral não tem número publicado: a FAQ de rate limit (atualizada em 05/05/2026) diz que o controle é “por Client ID (aplicação) na maioria dos casos e por endpoint”.
A doc de Orders também avisa que a “vista atual” de /orders/$ORDER_ID/shipments “será descontinuada a partir do final de setembro de 2026”. A vista nova sempre devolve um array; integração que lia um objeto único “falhará automaticamente”. Se a sua carga de frete parou em outubro, comece por aí.
Quando isso não tem conserto?
Origem da venda. Nenhum campo documentado do pedido diz de qual anúncio, busca ou campanha a venda veio. Dá para saber quanto você pagou de Product Ads no mês pelo tipo PADS; não dá para ligar uma venda específica a um clique pela API de pedidos.
Cliente único entre canais. O comprador vem como buyer.id interno, e o documento fiscal pode estar nulo. Cruzar a mesma pessoa entre o site e o Mercado Livre continua sem chave confiável, como mostrei em deduplicar venda entre site e marketplace.
Histórico anterior a 12 meses. Se ninguém salvou, a API de pedidos não devolve mais.
Nota fiscal emitida fora do Mercado Livre. Os recursos de nota fiscal (/users/$USER_ID/invoices/orders/$ORDER_ID e afins) cobrem operações “que utilizam nosso emissor de notas fiscais”, segundo a doc de notas fiscais (atualizada em 19/10/2026). Quem emite pelo próprio ERP busca a nota no ERP.
Quando a Precisian não é a resposta: se você vende só no Mercado Livre e o faturamento mensal já fecha com o financeiro, uma plataforma de dados é custo sem problema para resolver. O problema aparece quando o Mercado Livre precisa conversar com o site, o ERP e a mídia. Conectamos qualquer fonte que tenha API aberta.
O que este artigo não cobre?
Não cobre o Mercado Pago. O dinheiro liberado e a data de liberação são domínio da API do Mercado Pago (/v1/payments/{id}, citada na doc de Packs). Não li essa documentação para este texto.
Não traz limite numérico de requisições. Não está publicado, e não repito número de fórum.
Registro de método: o portal developers.mercadolivre.com.br responde 403 a curl direto, então li cada página por um leitor que renderiza o HTML e conferi os nomes de campo no JSON de exemplo da própria página. As páginas de autenticação, de reclamações e de boas práticas de faturamento não exibiram data de atualização; para elas vale a data da leitura, 3 de novembro de 2026.
Se o faturamento do Mercado Livre na sua planilha não fecha com o repasse, o primeiro passo é medir a diferença entre total_amount e o que sobra depois de comissão, frete e devolução. Vale uma conversa sobre o seu caso, sem compromisso de contrato, mas sem promessa de resposta em 30 minutos também.