Orçamento no Mercos pela API: o caminho híbrido

Vitor Ayres (abre em nova aba)

Desenho de plantas gerado a partir do primeiro commit do repositório mercos-sdk.
Plantas geradas pelo primeiro commit de mercos-sdk (6a33360).

O post sobre a API do Mercos registra que a API não cria orçamento: todo pedido criado pela rota de pedidos nasce com o status Gerado, e as rotas de pedido recusam o campo status. Para um app que precisava deixar um orçamento pronto para o vendedor revisar, isso era o problema inteiro.

Este texto registra o que mais tentamos pela API, o que o suporte respondeu, como a tela do Mercos cria um orçamento, e o caminho híbrido que funcionou: o rascunho nasce na tela e a API oficial o preenche. Tudo foi medido no sandbox do Mercos, em 22 e 25 de setembro de 2026.

Resumo

  • Testamos 39 nomes de campo no POST e 15 no PUT, nas versões 1 e 2. Todos recusados.
  • 9 rotas inventadas deram 404, igual a uma rota inexistente. O PATCH deu 405, e parâmetros na URL foram ignorados.
  • Um truque com uma chave inventada mostra quais campos a API aceita sem criar nada.
  • O suporte confirmou que é limitação do sistema, não bug. Chamado 561366, 22 de setembro.
  • A tela cria o orçamento num GET e o converte em pedido num POST sem corpo. As duas rotas exigem login.
  • Caminho híbrido: a tela cria o rascunho, o PUT da API oficial preenche. O status continua 1.
  • Riscos: a rota não tem documentação, cada abertura cria um rascunho, e a conversão por código não foi testada.

O que mais tentamos pela API

A hipótese era um campo ou uma rota não documentada. Em 25 de setembro, numa rodada de scripts com 6 segundos entre as chamadas:

Tentativa Resultado
39 nomes de campo no POST, v1 e v2 422, todos listados como inválidos
15 nomes de campo no PUT, v1 e v2 422, todos listados como inválidos
7 rotas de ação inventadas, como “reabrir” e “orçamento” 404 com página HTML, igual a 2 rotas de controle que não existem
GET /v1/orcamentos e GET /v2/orcamentos 404 com página HTML
PATCH /v2/pedidos/{id} 405
?status=1&orcamento=1&rascunho=1 na URL do POST ignorado, o pedido nasceu com status 2
POST sem data_emissao ou com null 422, o campo é obrigatório e só aceita texto
PUT num pedido cancelado 200, e o pedido continua cancelado

Os 39 nomes eram os campos que o GET devolve, como status_b2b e pedido_origem_id, mais palpites, como orcamento, rascunho, gerar_pedido, draft e quote. A rota de status, POST /v1/pedidos/{id}/status, só troca o status personalizado, que é outro campo. E um tipo de pedido chamado “Orçamento”, testado em 21 de setembro, também produziu um pedido com status 2.

Um detalhe que a listagem mostrou: a conta tinha 5 orçamentos com status 1, 4 deles sem itens. A explicação está mais abaixo.

Como achar campo não documentado sem criar nada

Mande os candidatos junto com uma chave que com certeza não existe. Essa chave garante um 422, então nada é criado. A v2 lista todos os atributos inválidos numa mensagem só, e a v1 dá um erro por chave. Qualquer candidato que não apareça na lista de inválidos é um campo aceito.

Foi assim que os 39 nomes foram testados em duas requisições. De brinde, a v1 mostrou que os itens exigem preco_bruto e recusam preco_tabela.

O que o suporte respondeu

Perguntamos pelo chat em 21 de setembro, fora do horário. Em 22 de setembro, de manhã, a primeira resposta explicou os status padrão, Orçamento, Concluído e Cancelado, e que um status personalizado só entra depois de o pedido ser concluído. Pedimos para confirmar se era bug ou limite. À tarde, a resposta: “essa é uma limitação atual do sistema e não se trata de um bug”. O time de integração estava em cópia e não tinha respondido até 25 de setembro.

O “Concluído” do suporte é o status 2 da API, que a documentação chama de Gerado. O suporte respondeu nos termos da tela.

Como a tela cria o orçamento

Capturamos as chamadas da tela do Mercos em 25 de setembro, com uma extensão do Chrome, porque o leitor de rede do navegador não mostra as requisições do próprio Mercos. A sequência:

  1. Abrir “Criar pedido / orçamento” faz um GET que já cria o orçamento no servidor e redireciona para a página dele, com o id no endereço.
  2. Cliente, itens e condição de pagamento vão em formulários comuns do Django, um POST cada.
  3. “Gerar pedido” é um POST sem corpo, que responde com o endereço de redirecionamento. O botão fica desabilitado até o orçamento ter condição de pagamento.

Como o GET cria o registro, cada abertura da tela deixa um rascunho. É por isso que a conta tinha orçamentos sem cliente e sem itens.

Com só os dois tokens da integração, as três rotas da tela que testamos responderam 302 para a página de login. Elas exigem a sessão de um usuário. O formulário de login tem só usuário e senha, e o HTML não cita captcha, o que não descarta verificação em duas etapas nem bloqueio depois de erros.

O caminho híbrido

Se a tela cria com status 1 e a API cria com status 2, e o PUT não mexe no status, basta trocar quem cria.

Testado em 25 de setembro, num rascunho recém-criado na tela, sem cliente, sem itens e sem condição de pagamento:

Passo Resultado
PUT /v2/pedidos/{id} pela API oficial, com cliente, condição e um item de 2 unidades 200
Leitura depois do PUT status 1, cliente preenchido, condição “30 / 60 / 90”, um item, total R$ 536,90

Uma segunda rodada, no mesmo dia e noutro rascunho, mediu o que o app precisava saber:

  • Um PUT sem condição de pagamento é aceito num rascunho, ao contrário do POST.
  • Um PUT com um item num rascunho que já tem quatro acrescenta o quinto. Os quatro ficam intactos, com os mesmos ids.
  • O PUT move ultima_alteracao, então a listagem por data encontra o rascunho antes e depois.
  • Desconto com 7 casas decimais dá 422. Com 4 casas é aceito, e o preço líquido volta com 5 casas, sem arredondar ao centavo.
  • O Mercos grava o preço que mandamos sem conferir pelo cadastro: 138 num produto de 137 ficou 138. Catálogo velho vira preço errado no orçamento.
  • A tela recarregada mostra os itens. Editar na tela sem recarregar não foi testado.
  • Um PUT leva de 0,5 a 0,7 segundo. Ler, gravar e ler de novo levou 19 segundos no sandbox, por causa dos 429 entre as chamadas.

No app, a escolha foi deixar a criação com a pessoa. Ela abre o orçamento na tela do Mercos, como já fazia, uma extensão lê o id no endereço da página e manda a lista de itens ao nosso servidor, e o servidor preenche o rascunho pelo PUT da API, com os tokens da integração e o mercos-sdk. Quando o preenchimento vem de um assistente de IA, o mesmo PUT passa pelo servidor MCP do app, com uma prévia obrigatória antes de gravar. Nenhuma senha guardada, o orçamento fica no nome de quem o abriu, e a escrita passa só pela API oficial. A alternativa, um usuário só para a integração fazendo login por código, ficou guardada para o dia em que o orçamento precisar nascer sem ninguém com o Mercos aberto.

Riscos e o que não medimos

A rota que cria o rascunho não tem documentação e pode mudar em qualquer deploy do Mercos. Os termos de uso não foram lidos com esse uso em mente. Por isso o app não a chama: quem a chama é a pessoa, pela tela.

O GET de criação não é idempotente. Uma chamada repetida por engano deixou um rascunho vazio na conta. Se o preenchimento falhar, o rascunho precisa ser cancelado.

Não testamos: se criador_id no PUT troca o vendedor; gerar o pedido por código, que provavelmente exige o token CSRF; quanto dura a sessão e se a conta pode exigir verificação em duas etapas; um PUT num rascunho de outra representada, que o sandbox não permite medir; e nada disso em produção, onde a leitura por id é bloqueada e o app encontra o pedido pela listagem.

Como verificamos

Sandbox do Mercos, uma conta, 22 e 25 de setembro de 2026. Cinco rodadas de scripts, com 6 segundos entre as chamadas: leitura dos status e dos orçamentos existentes; a sonda de campos no POST, sem criar nada; dois pedidos criados e cancelados para a sonda no PUT, as rotas, o PATCH e os parâmetros na URL; as rotas da tela só com os tokens; e o PUT no rascunho. Os pedidos de teste ficaram cancelados na conta. O cliente usado nos testes é fictício.

O que não medimos está na seção anterior. O projeto não tem vínculo com a Mercos.

Se a sua empresa precisa que um sistema converse com um ERP que a API não cobre inteiro, é esse o trabalho que fazemos em integrações e em engenharia reversa.

Perguntas

Existe algum campo ou rota escondida para criar orçamento pela API do Mercos?
Não achamos. Testamos 39 nomes de campo no POST e 15 no PUT, nas versões 1 e 2 da API, e 9 rotas inventadas. Tudo foi recusado com 422, 404 ou 405.
O suporte do Mercos confirma que a API não cria orçamento?
Sim. Em 22 de setembro de 2026, no chamado 561366, a resposta foi que é uma limitação atual do sistema e não se trata de um bug.
Como a tela do Mercos cria um orçamento?
Abrir a tela de criar pedido já grava um rascunho com status 1, antes de qualquer preenchimento. Cada abertura cria um rascunho novo, e a rota exige a sessão de um usuário logado.
Dá para preencher pela API um orçamento criado na tela?
Sim. O PUT /v2/pedidos/{id} num rascunho criado na tela respondeu 200, e o status continuou 1. No teste, o orçamento ficou com cliente, condição de pagamento, um item e total de R$ 536,90.
As rotas da tela funcionam só com os tokens da API?
Não. Com os dois tokens da integração, as três rotas da tela que testamos responderam 302 para a página de login. Elas precisam da sessão de um usuário.

Como podemos ajudar?

Oi (abre em nova aba)