跳到正文
DEV Community· AppVerix·· 3 小時前AI 評分46

Mercado Livre API 買家問題處理:通知、佇列及以 Node.js 呼叫 /answers 回覆

Perguntas do Mercado Livre via API: notificações, fila e resposta com /answers (Node.js)

AI 導讀

Mercado Livre 的官方 API 可透過通知、佇列及 /answers 完成買家問題的接收、查詢與回覆,文章並提供 Node.js 範例。Webhook 應在 500 毫秒內回傳 HTTP 200,再把通知加入佇列處理;工作程序查詢問題後,確認狀態仍為 UNANSWERED 才提交答案。

正文

Se você já integrou um sistema com o Mercado Livre, sabe que perguntas de compradores são um dos fluxos mais sensíveis ao tempo: quem pergunta normalmente está decidindo a compra naquele momento. Neste post vou mostrar como funciona o ciclo completo pela API oficial: receber a notificação de uma nova pergunta, buscar os detalhes, decidir a resposta e publicá-la. Tudo com base na documentação oficial em developers.mercadolivre.com.br, com exemplos em Node.js.

Aviso logo de cara: a AppVerix está construindo um produto em cima desse fluxo (o AppVerix Responde). Falo dele só no final. O resto do texto serve para qualquer pessoa que queira montar a própria integração.

Visão geral do fluxo

  1. Sua aplicação assina o tópico questions no gerenciador de aplicativos do Mercado Livre e informa uma callback URL.
  2. Quando chega uma pergunta, o Mercado Livre faz um POST na sua callback com um aviso curto: o recurso (/questions/ID), não a pergunta inteira.
  3. Você confirma o recebimento com HTTP 200 imediatamente e coloca o aviso numa fila.
  4. Um worker consulta GET /questions/$QUESTION_ID com o token do vendedor.
  5. O worker decide a resposta e chama POST /answers.

Vamos por partes.

1. Assinando o tópico questions

Segundo a página Receba notificações, os tópicos são configurados no gerenciador de aplicativos, onde você criou sua aplicação. Lá você informa a callback URL e marca os tópicos desejados. A lista inclui orders_v2, items, messages, questions e outros.

A autorização do vendedor é feita por OAuth: o vendedor autoriza sua aplicação e você recebe um access_token para chamar a API em nome dele. Nada de pedir senha.

2. O formato da notificação

A notificação é leve. Ela diz o que mudou e você busca o resto. Um exemplo no formato da documentação:

{
  "resource": "/questions/5036111111",
  "user_id": 123456789,
  "topic": "questions",
  "application_id": 2069392825111111,
  "attempts": 1,
  "sent": "2026-11-01T12:00:00.000Z",
  "received": "2026-11-01T12:00:00.000Z"
}

O campo importante é resource. O user_id indica de qual vendedor é a conta, o que importa se você atende várias lojas.

3. Responda 200 rápido e processe depois

Esta é a parte que mais derruba integração. A documentação é explícita:

  • O Mercado Livre envia um POST para a callback URL e espera um HTTP 200. Se não receber, considera a mensagem não entregue e tenta de novo.
  • As novas tentativas acontecem durante 1 hora. Depois disso, a notificação é descartada.
  • A recomendação é retornar HTTP 200 em até 500 milissegundos. Integrações que falham nisso podem ter os tópicos desativados.
  • Para volume alto, a própria documentação recomenda trabalhar com filas: confirmar na hora e só depois consultar a API.

Ou seja: nada de chamar a API, um LLM ou o banco de dados pesado dentro do handler do webhook. Um exemplo mínimo com Express:

import express from "express";
import { enqueue } from "./queue.js"; // Redis, SQS, tabela no Postgres... o que você já usa

const app = express();
app.use(express.json());

app.post("/ml/notifications", (req, res) => {
  const n = req.body;
  res.sendStatus(200); // confirma primeiro

  if (n?.topic === "questions" && n?.resource) {
    enqueue({
      resource: n.resource,
      userId: n.user_id,
      receivedAt: Date.now(),
    }).catch((err) => console.error("falha ao enfileirar", err));
  }
});

app.listen(3000);

Duas observações práticas:

  • Idempotência. Como há retentativas, o mesmo resource pode chegar mais de uma vez. Use o ID da pergunta como chave única na fila ou no banco.
  • Notificações perdidas. Se seu servidor ficou fora do ar, existe o endpoint GET /missed_feeds?app_id=$APP_ID, que lista notificações que não receberam 200 após a última tentativa. Segundo a documentação, ele só guarda notificações de até 2 dias atrás, então vale rodar uma rotina de reconciliação.
curl -X GET -H "Authorization: Bearer $ACCESS_TOKEN" \
  "https://api.mercadolibre.com/missed_feeds?app_id=$APP_ID"

4. Buscando a pergunta

Com o resource em mãos, o worker consulta a pergunta. A documentação de Perguntas e Respostas mostra a chamada:

curl -X GET -H "Authorization: Bearer $ACCESS_TOKEN" \
  https://api.mercadolibre.com/questions/3957150025

A resposta traz, entre outros campos, id, item_id, seller_id, text, status (UNANSWERED ou ANSWERED) e answer. A documentação também recomenda usar o parâmetro api_version=4 para receber a estrutura nova.

Em Node (18+, com fetch nativo):

const API = "https://api.mercadolibre.com";

async function getQuestion(resource, token) {
  const r = await fetch(`${API}${resource}?api_version=4`, {
    headers: { Authorization: `Bearer ${token}` },
  });
  if (!r.ok) throw new Error(`GET ${resource} -> ${r.status}`);
  return r.json();
}

Antes de responder, confira se status ainda é UNANSWERED. O vendedor pode ter respondido pelo app enquanto a mensagem estava na fila.

Para montar uma boa resposta, você normalmente vai precisar também dos dados do anúncio (item_id): título, atributos, garantia e assim por diante. Para listar perguntas de um anúncio, existe GET /questions/search?item=$ITEM_ID.

5. Publicando a resposta

A resposta é um POST /answers com o question_id e o text:

curl -X POST -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"question_id": 3957150025, "text": "Olá! Sim, enviamos com nota fiscal."}' \
  https://api.mercadolibre.com/answers

Se der certo, o retorno mostra a pergunta com status: "ANSWERED" e answer.status: "ACTIVE". Em Node:

async function answer(questionId, text, token) {
  const r = await fetch(`${API}/answers`, {
    method: "POST",
    headers: {
      Authorization: `Bearer ${token}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ question_id: questionId, text }),
  });
  if (!r.ok) throw new Error(`POST /answers -> ${r.status} ${await r.text()}`);
  return r.json();
}

6. Juntando tudo no worker

async function handleJob(job) {
  const token = await getSellerToken(job.userId); // seu storage de OAuth (com refresh)
  const q = await getQuestion(job.resource, token);

  if (q.status !== "UNANSWERED") return; // já respondida

  const draft = await buildAnswer(q); // regras, templates ou IA
  if (!draft.confident) {
    await notifySeller(q); // deixa para um humano
    return;
  }
  await answer(q.id, draft.text, token);
}

O ponto de design mais importante está em buildAnswer: o que fazer quando você não tem certeza. Responder errado no Mercado Livre é pior do que demorar alguns minutos. Na prática, vale ter:

  • Modo sugestão vs. automático. Comece só sugerindo respostas para o vendedor aprovar. Libere o automático depois, e por tipo de pergunta.
  • Respostas baseadas no anúncio. Use só fatos que estão no anúncio ou nas regras da loja (prazo, garantia, nota fiscal). Se a informação não existe, não invente.
  • Fallback humano. Pergunta ambígua, reclamação ou negociação vai para a pessoa.
  • Log de tudo. Guarde a pergunta, o contexto usado e a resposta enviada para revisar depois.

Checklist rápido

  • [ ] Tópico questions assinado e callback URL pública com HTTPS
  • [ ] Handler responde 200 antes de qualquer processamento (meta: < 500 ms)
  • [ ] Fila com deduplicação pelo ID da pergunta
  • [ ] Rotina de reconciliação com /missed_feeds (janela de 2 dias)
  • [ ] Revalidar status antes de POST /answers
  • [ ] Refresh do access_token funcionando
  • [ ] Caminho claro para "não sei, manda para o humano"

Nota honesta: o que a AppVerix está fazendo com isso

Nós, da AppVerix, estamos construindo o AppVerix Responde, que aplica exatamente esse fluxo para vendedores que não querem manter integração própria. A ideia: você conecta a conta pela conexão oficial do Mercado Livre (sem compartilhar senha), informa prazos, garantia e políticas da loja e escolhe se a IA responde sozinha ou só sugere a resposta para você aprovar. Ela responde com base nos dados do anúncio e, quando não tem certeza, deixa a pergunta para você.

Ele ainda não está disponível. Estamos na fase de lista de espera, com preço previsto a partir de R$99/mês e teste grátis no lançamento. Quem entrar na lista recebe condição especial de acesso antecipado. Se tiver interesse, a lista está aqui: https://appverix.com/mercado-livre/

E se você preferir construir o seu, espero que este passo a passo ajude. Dúvidas e correções são bem-vindas nos comentários.

來源:DEV Community · dev.to