Projeto demonstração da CodifyPro.Marca fictícia, produtos reais, código real. Nada aqui é vendido.
Micrata

Recursos · Integrações e API

integrações

Integrações e API

Com o que esta loja conversa fora dela (gateway, transportadora, ERP, fiscal, mídia paga e atendimento) e a API que deixa o seu sistema falar com ela. Para o lojista que já roda Bling, Melhor Envio ou Mercado Pago e quer saber onde isso tudo encaixa.

O mapa

A loja fica no centro e é ela quem começa quase toda conversa. O que volta sozinho (pagamento compensado, objeto entregue, estoque que mudou no ERP) volta por webhook, que é a seta tracejada.

Mapa da arquitetura. No centro fica a loja Micrata, com catálogo, carrinho, pedido, painel e rastreio. O comprador fala com ela por HTTPS, nos dois sentidos. A loja chama cinco grupos de serviço e quatro deles respondem de volta por webhook: a loja cria a cobrança no gateway de pagamento e recebe o aviso de pagamento aprovado; pede a cotação de frete e recebe o rastreio; envia o pedido ao ERP e recebe estoque e nota fiscal; dispara mensagem no atendimento e recebe a resposta do cliente. O quinto grupo, marketing, é de mão única: a loja envia o evento de compra e o catálogo, e nada volta.

a loja chama o serviçoo serviço chama a loja de volta: é aqui que entra o webhook

Os grupos, serviço por serviço

Cada linha diz o que a loja faz com aquele serviço. Nenhum deles é obrigatório e nenhum é exclusivo: a loja pode cotar em três transportadoras e cobrar em dois gateways ao mesmo tempo.

Pagamento

A loja cria a cobrança. Quem confirma é o webhook, não uma pessoa olhando extrato.

  • Mercado Pago: monta a preferência com os itens do carrinho e recebe o retorno em payment.updated; o pedido vira pago sem ninguém abrir o painel.
  • Pagar.me: cartão em até 10x com captura em duas etapas: autoriza no fechamento, captura quando o estoque confirma, e o que não confirma expira sozinho.
  • Stripe: para quem também vende fora do Brasil. Cobra em outra moeda e devolve a decisão do antifraude na mesma resposta.
  • Asaas: boleto e Pix com conciliação. O boleto compensa em D+3 e o aviso chega na compensação, não na emissão: quem amarra o e-mail de confirmação à emissão promete um prazo que ainda não começou.
  • PagBank: cartão, boleto e Pix caem na mesma conta da maquininha do balcão, então o site e a loja da rua fecham o dia num extrato só.
  • Pix direto no banco: QR dinâmico pela API do próprio banco, sem intermediário. São 5% de desconto no checkout e a baixa cai em segundos.

Frete

Cotação no carrinho pelo CEP e pelo peso cubado, etiqueta na aprovação, rastreio de volta. O valor sai no carrinho, não na última tela: frete que só aparece no fim é onde a compra morre.

  • Correios: PAC e SEDEX cotados pelo contrato do lojista quando ele tem um, e pela tabela pública quando não tem.
  • Melhor Envio: compara Correios, Jadlog, Azul e Loggi numa cotação só e imprime a etiqueta mais barata das quatro.
  • Jadlog: .Package e .Com por contrato direto, com a coleta agendada pela API assim que a etiqueta sai.
  • Loggi: entrega no mesmo dia nas capitais atendidas. Só aparece no checkout quando o CEP está de fato na área, em vez de prometer e falhar depois.
  • Frete próprio por faixa de CEP: a tabela do lojista, com faixa de CEP × peso × valor, grátis acima de R$ 299 e regra separada para a região da loja.
  • Retirada na loja: R$ 0 e prazo em horas. O item só baixa do estoque quando alguém confere o código de retirada no balcão.

ERP e gestão

O pedido pago desce para o sistema que já roda a empresa. O estoque sobe de volta.

  • Bling: o pedido aprovado vira pedido de venda; o Bling devolve o saldo de estoque e o número da nota.
  • Tiny: mesma via do Bling. A diferença está no mapeamento de SKU, que aqui é 1:1 com o SKU da loja e não uma tabela paralela.
  • Omie: para quem já tem o financeiro lá. O pedido nasce com centro de custo e forma de pagamento preenchidos.
  • Zoho Books: a loja envia o pedido e guarda o número da fatura devolvido, que é o que amarra venda e recebimento na conciliação.
  • ERP próprio, sem API: acontece mais do que parece. A ponte então é arquivo: a loja escreve um CSV ou JSON num diretório (ou numa fila) e lê o retorno de estoque no mesmo formato. É deselegante e funciona há anos.

Fiscal

A loja não emite nota. Ela pede a emissão e guarda o retorno.

  • NF-e por integração: o pedido pago vai para quem emite (o próprio ERP, ou um emissor dedicado) e volta com número, série, chave de 44 dígitos, XML e DANFE em PDF, tudo anexado ao pedido e ao e-mail do cliente.
  • Por que não emitir aqui: emitir exige o certificado A1 da empresa dentro do processo. Certificado digital no mesmo contêiner que atende a internet deixa a assinatura da empresa na porta que mais apanha. Fica fora, por escolha.
  • Cancelamento e carta de correção: seguem o mesmo caminho. A loja dispara, o emissor responde, e o pedido guarda o protocolo.

Marketing e mídia

Evento de compra pelo servidor, catálogo por feed. Nada disso depende do navegador colaborar.

  • Meta (Pixel + Conversions API): os dois juntos, com o mesmo event_id, para o evento contar uma vez só. O detalhe está logo abaixo, porque é a pergunta que mais aparece.
  • Google Ads: conversão importada com o gclid que veio no clique e ficou gravado no pedido. O anúncio leva o crédito da venda mesmo quando ela acontece três dias depois, por Pix, em outro aparelho.
  • GA4: os eventos de e-commerce (view_item, add_to_cart, begin_checkout, purchase) e, para a compra, também pelo Measurement Protocol a partir do servidor.
  • Google Merchant Center: a loja gera o feed do catálogo e atualiza a cada poucas horas. O que ele exige está logo abaixo, campo por campo, porque o feed é conferido contra a página.
  • TikTok: Pixel no navegador e Events API no servidor, no mesmo desenho da Meta.

Atendimento

O que a loja fala com o cliente depois do pedido, e onde a resposta dele cai. Pedido sem notícia vira "cadê meu produto?" no WhatsApp, e o que ninguém responde acaba no Reclame Aqui.

  • WhatsApp Cloud API: confirmação, código de rastreio e aviso de entrega por modelo aprovado. Fora da janela de 24 horas só passa modelo pago, então a régua cabe dentro dela de propósito.
  • Chatwoot: a caixa única. WhatsApp, e-mail e o chat do site caem na mesma fila, com o histórico de pedidos do cliente aberto ao lado da conversa.
  • E-mail transacional: domínio próprio com SPF, DKIM e DMARC configurados. Sem os três, o "pedido confirmado" cai no spam e o cliente abre chamado perguntando se o pedido entrou mesmo.

Meta e Google, com o detalhe que sempre falta

São as duas perguntas que todo lojista faz na reunião, e as duas respostas que costumam vir pela metade.

Por que a Conversions API recupera conversão que o pixel perde

O pixel é um script que roda no navegador do comprador. Ele só avisa da compra se conseguir carregar, executar e enviar a requisição. Isso falha em quatro situações corriqueiras:

  • Bloqueador de anúncio. A extensão derruba o domínio do pixel na origem. A pessoa comprou, o pedido está no painel, e a Meta nunca soube.
  • ITP no Safari. A proteção do Safari corta para sete dias a validade do cookie que um script grava. Cai para vinte e quatro horas quando a gravação vem logo depois de uma navegação com parâmetro na URL. É exatamente o caso do clique no anúncio, que chega com fbclid. Quem clicou na segunda e comprou no domingo já perdeu o vínculo pelo prazo mais curto.
  • Aparelho e rede ruins. Script de terceiro é o primeiro a falhar em 3G instável, e o comprador que fecha a aba na tela de obrigado leva o evento junto.
  • Compra que termina fora do navegador. O cliente sai do site e paga o Pix no aplicativo do banco. O boleto compensa três dias depois. Nos dois casos não sobrou aba aberta para disparar coisa alguma.

A Conversions API manda o mesmo evento pelo servidor, direto da loja para a Meta, na hora em que o gateway aprova o pedido. Não passa navegador no caminho. Vão o valor, a moeda, os itens e os dados de contato já em hash SHA-256, nunca em texto puro: é assim que a Meta casa a compra com a conta sem receber o e-mail do seu cliente.

Os dois convivem, e o detalhe que derruba a conta é este: pixel e servidor mandam o mesmo event_id, e a Meta descarta a cópia. Sem o identificador compartilhado, toda compra conta duas vezes, o custo por conversão parece metade do que é, e a decisão de verba sai errada.

Quanto se recupera depende do público, e não dá para prometer. Para medir, compare os pedidos aprovados no painel com as compras que a Meta registra no mesmo período. A diferença é o que você estava perdendo.

O que o Merchant Center exige do catálogo

O feed do Google não é uma lista de produtos: é uma declaração que o robô dele vai conferir na sua página. Divergiu, o Google reprova o item, e item reprovado não aparece. Reprovar item não suspende a conta: o que suspende é problema de política, e preço que não bate é justamente isso, deturpação. Mas com metade do feed reprovado a campanha de Shopping fica sem o que veicular, que na prática dá no mesmo.

  • GTIN. Todo produto de fabricante conhecido tem um código de barras global, o EAN-13 da caixa. Em eletrônicos ele é praticamente obrigatório: sem GTIN, o Google não sabe que o seu iPhone é o mesmo iPhone dos outros vinte anunciantes e não coloca o item na comparação. Só produto sem GTIN de fábrica (artesanal, sob medida) pode declarar identifier_exists: no, e mentir aqui é reprovação certa.
  • Disponibilidade batendo. availability igual a in_stock com a página dizendo "esgotado" é uma das reprovações mais comuns. A loja gera o feed a partir do mesmo saldo que desenha o botão de comprar, então os dois não têm como divergir.
  • Preço batendo. É aqui que o Brasil tropeça. O preço do feed tem que ser o que qualquer visitante vê ao abrir a página, sem condição. O preço com 5% de desconto no Pix não é o preço do feed: ele depende da forma de pagamento e só aparece no checkout. No feed vai o preço cheio. O desconto do Pix vive na página, e a própria página explica a diferença.
  • Os campos que ninguém preenche. brand, mpn, condition, shipping com prazo real e image_link em imagem sem marca d'água, sem moldura e sem texto promocional colado.
  • Dados estruturados na página. Numa loja em operação a página de produto publica schema.org/Product com preço, moeda e disponibilidade, tudo saindo da mesma fonte do feed. É o que o robô lê para conferir, e é por isso que ninguém mantém os dois à mão, cada um num canto. Esta demonstração não emite o dado estruturado.

A API

REST sobre HTTPS, JSON nos dois sentidos, autenticação por chave no cabeçalho Authorization. Os exemplos abaixo são o formato de verdade: cabeçalhos reais, códigos de status corretos, JSON que passa num parser. Os valores é que são de demonstração.

1 · Ler o catálogo

Paginado, com X-Total e X-Total-Paginas no cabeçalho para quem precisa varrer tudo. Por padrão o produto sem estoque continua na resposta, com disponivel: false. Quem quiser só o que está à venda pede disponivel=sim, mas pense duas vezes antes: some da resposta e o ERP do outro lado entende que ele foi excluído, apaga o SKU e leva junto o histórico de vendas dele.

A resposta vai com Cache-Control: private, e não public: ela é da sua chave. public autoriza qualquer cache no caminho (a CDN na frente da loja, o proxy da sua empresa) a guardar o seu catálogo e entregar para a chave do vizinho.

RequisiçãoHTTP bruto
GET /api/v1/produtos?pagina=1&por_pagina=2 HTTP/1.1
Host: micrata.example.com
Authorization: Bearer <sua-chave>
Accept: application/json
Resposta200 OK · estoque de exemplo
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Cache-Control: private, max-age=60
X-Total: 24
X-Total-Paginas: 12

{
  "pagina": 1,
  "por_pagina": 2,
  "total": 24,
  "itens": [
    {
      "id": 1042,
      "sku": "IP17PM-256-TIT",
      "slug": "iphone-17-pro-max",
      "nome": "iPhone 17 Pro Max 256 GB",
      "marca": "Apple",
      "gtin": "7899999999999",
      "preco": 10899.00,
      "preco_regular": 10899.00,
      "preco_pix": 10354.05,
      "moeda": "BRL",
      "estoque": 7,
      "disponivel": true,
      "peso_kg": 0.227,
      "dimensoes_cm": { "c": 18, "l": 11, "a": 6 },
      "imagem": "https://micrata.example.com/produtos/iphone-17-pro-max.webp",
      "url": "https://micrata.example.com/produto/iphone-17-pro-max",
      "atualizado_em": "2026-09-05T14:22:08-03:00"
    },
    {
      "id": 1038,
      "sku": "GS26U-256-PRE",
      "slug": "samsung-galaxy-s26-ultra-5g-256gb",
      "nome": "Samsung Galaxy S26 Ultra 5G 256 GB",
      "marca": "Samsung",
      "gtin": "7899999999982",
      "preco": 11499.00,
      "preco_regular": 11499.00,
      "preco_pix": 10924.05,
      "moeda": "BRL",
      "estoque": 0,
      "disponivel": false,
      "peso_kg": 0.234,
      "dimensoes_cm": { "c": 18, "l": 11, "a": 6 },
      "imagem": "https://micrata.example.com/produtos/samsung-galaxy-s26-ultra-5g-256gb.webp",
      "url": "https://micrata.example.com/produto/samsung-galaxy-s26-ultra-5g-256gb",
      "atualizado_em": "2026-09-05T09:41:00-03:00"
    }
  ]
}

2 · Criar um pedido

O corpo manda o que comprar, não quanto custa: a loja calcula preço, desconto e frete com a tabela dela, na hora do pedido. Quem manda o preço junto abre a porta para o cliente mandar o preço que quiser.

Idempotency-Key é obrigatório. A rede cai entre o seu POST e a nossa resposta, e você repete a chamada. Sem a chave, o comprador recebe dois iPhones e uma cobrança dupla. Com ela, a segunda chamada devolve o mesmo pedido e o mesmo 201.

RequisiçãoHTTP bruto
POST /api/v1/pedidos HTTP/1.1
Host: micrata.example.com
Authorization: Bearer <sua-chave>
Content-Type: application/json
Idempotency-Key: 7f3c-exemplo-0001

{
  "cliente": {
    "nome": "Joana Fictícia Ribeiro",
    "email": "[email protected]",
    "documento": "111.111.111-11",
    "telefone": "+5511999999999"
  },
  "entrega": {
    "cep": "01001-000",
    "logradouro": "Praça da Sé",
    "numero": "s/n",
    "bairro": "Sé",
    "cidade": "São Paulo",
    "uf": "SP",
    "servico": "correios:pac"
  },
  "itens": [
    { "sku": "IP17PM-256-TIT", "quantidade": 1 }
  ],
  "pagamento": { "metodo": "pix" },
  "origem": {
    "utm_source": "google",
    "utm_medium": "cpc",
    "utm_campaign": "marca",
    "gclid": "<gclid-do-clique>"
  }
}
Resposta201 Created
HTTP/1.1 201 Created
Location: /api/v1/pedidos/MIC-2026-004182
Content-Type: application/json; charset=utf-8

{
  "numero": "MIC-2026-004182",
  "status": "aguardando_pagamento",
  "criado_em": "2026-09-05T14:31:52-03:00",
  "expira_em": "2026-09-05T15:01:52-03:00",
  "itens": [
    {
      "sku": "IP17PM-256-TIT",
      "nome": "iPhone 17 Pro Max 256 GB",
      "quantidade": 1,
      "preco_unitario": 10899.00,
      "total": 10899.00
    }
  ],
  "totais": {
    "produtos": 10899.00,
    "desconto_pix": 544.95,
    "frete": 0.00,
    "total": 10354.05
  },
  "frete": {
    "transportadora": "Correios",
    "servico": "PAC",
    "prazo_dias_uteis": 6,
    "valor": 0.00,
    "gratis_acima_de": 299.00
  },
  "pagamento": {
    "metodo": "pix",
    "desconto_percentual": 5,
    "qr_code": "<codigo-pix-copia-e-cola>",
    "qr_code_base64": "<png-em-base64>"
  },
  "links": {
    "self": "https://micrata.example.com/api/v1/pedidos/MIC-2026-004182",
    "rastreio": "https://micrata.example.com/rastreio?pedido=MIC-2026-004182"
  }
}

3 · O webhook do gateway chegando na loja

Este é o corpo que a loja recebe quando o Pix compensa, em geral em menos de dez segundos. Ninguém abriu o painel, ninguém conferiu extrato: é esta chamada que muda o pedido para pago, dispara o WhatsApp de confirmação e manda o pedido para o ERP separar.

O nome do cabeçalho de assinatura muda em cada gateway: o Stripe usa Stripe-Signature com t= e v1=, o Mercado Pago usa x-signature. E tem gateway que nem assina: o Pagar.me na v5 autentica o webhook por Basic Auth, com usuário e senha definidos no painel. Ali você confere a credencial que chega no Authorization, não o corpo. O que não muda é a pergunta que você responde antes de tocar no pedido: essa chamada veio mesmo de quem diz que veio?

Chamada recebidaa assinatura do exemplo é falsa
POST /webhooks/pagamento HTTP/1.1
Host: micrata.example.com
Content-Type: application/json
User-Agent: Gateway-Webhook/1.0
X-Gateway-Evento: pagamento.aprovado
X-Gateway-Entrega: ent-exemplo-0001
X-Gateway-Tentativa: 1
X-Gateway-Timestamp: 1788629590
X-Gateway-Assinatura: sha256=assinatura-de-exemplo-nao-e-um-hmac-valido

{
  "id": "evt-exemplo-0001",
  "tipo": "pagamento.aprovado",
  "criado_em": "2026-09-05T14:33:10-03:00",
  "dados": {
    "pedido": "MIC-2026-004182",
    "transacao": "txn-exemplo-0001",
    "metodo": "pix",
    "valor": 10354.05,
    "moeda": "BRL",
    "pago_em": "2026-09-05T14:33:07-03:00",
    "e2e": "E12345678202609051433EXEMPLO0001",
    "pagador": { "nome": "Joana Fictícia Ribeiro", "documento": "111.***.***-11" }
  }
}

4 · Por que a assinatura HMAC não é opcional

A URL do webhook não é segredo. Ela aparece no painel do gateway, no log do proxy, no histórico de quem já mexeu na loja e num print mandado no grupo do WhatsApp do projeto. Sem verificar a assinatura, qualquer um que descubra o endereço manda um POST com {"tipo": "pagamento.aprovado"} e o número de um pedido. A loja marca como pago, avisa o cliente e libera a separação. Não é ataque sofisticado: é um comando de terminal.

A assinatura é um HMAC-SHA256 do carimbo de tempo mais o corpo bruto, com um segredo que só o gateway e a loja conhecem. Três detalhes derrubam quem implementa na pressa, e os três estão no código abaixo.

verificar-assinatura.jsNode 18+
// Verificação da assinatura, do jeito que ela roda em produção.
// Node 18+, sem dependência: o crypto é o da própria plataforma.
import { createHmac, timingSafeEqual } from 'node:crypto';

export function assinaturaValida(corpoBruto, cabecalhos, segredo) {
  const ts = String(cabecalhos['x-gateway-timestamp'] || '');
  const recebida = String(cabecalhos['x-gateway-assinatura'] || '');

  // Janela de 5 minutos. Sem o carimbo de tempo DENTRO do que foi assinado,
  // uma chamada legítima capturada hoje continua valendo para sempre, e
  // "pagamento aprovado" vira algo que qualquer um repete à vontade.
  if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false;

  // corpoBruto são os BYTES que chegaram, não o objeto já convertido.
  // JSON.parse seguido de JSON.stringify reordena chaves e come espaço: o
  // corpo continua equivalente, e a assinatura nunca mais bate. É o primeiro
  // lugar onde procurar quando a assinatura para de bater.
  const esperada = 'sha256=' + createHmac('sha256', segredo)
    .update(ts + '.' + corpoBruto, 'utf8')
    .digest('hex');

  const a = Buffer.from(esperada);
  const b = Buffer.from(recebida);
  if (a.length !== b.length) return false;

  // Comparar com === devolve a resposta mais depressa quanto mais errado for
  // o primeiro byte. Repetido alguns milhares de vezes, esse tempo conta a
  // assinatura byte a byte. timingSafeEqual leva sempre o mesmo tempo.
  return timingSafeEqual(a, b);
}

Depois de validar, a loja responde 200 na hora e joga o resto numa fila. Emitir nota, chamar o ERP e mandar WhatsApp dentro da requisição estoura o tempo limite do gateway, que entende que a entrega falhou e reenvia. Aí o mesmo pagamento entra duas vezes.

Os webhooks que a loja emite

O caminho inverso: o seu sistema assina um endereço e a loja avisa quando algo acontece, em vez de você ficar perguntando de minuto em minuto. Todo envio leva os cabeçalhos X-Micrata-Evento, X-Micrata-Entrega, X-Micrata-Timestamp e X-Micrata-Assinatura. A assinatura usa o mesmo HMAC explicado acima, agora saindo do nosso lado.

EventoGatilhoO que vai no corpo
pedido.criadoO comprador fecha o checkout, antes de pagar.numero · status · itens[] · totais · cliente · entrega · origem (UTM e gclid)
pagamento.aprovadoO gateway confirma. Pix em segundos, cartão na autorização, boleto em D+3.pedido · transacao · metodo · valor · pago_em · nsu ou e2e
pagamento.recusadoO emissor nega ou o antifraude reprova.pedido · motivo · codigo_adquirente · pode_repetir
pedido.enviadoAlguém posta a etiqueta e a transportadora registra o primeiro evento.pedido · transportadora · servico · rastreio · postado_em · prazo_estimado
pedido.entregueEvento de entrega da transportadora, ou baixa da retirada no balcão.pedido · entregue_em · recebido_por · comprovante
pedido.canceladoCancelamento pelo cliente, pelo painel, ou por expirar sem pagamento.pedido · motivo · cancelado_por · estorno
estoque.baixoO saldo de um SKU cruza o mínimo definido no painel. Uma vez por cruzamento, não a cada venda.sku · nome · saldo · minimo · media_diaria_30d · dias_de_cobertura

A tabela rola para o lado.

Entrega ao menos uma vez, nunca exatamente uma vez

Qualquer resposta 2xx conta como aceita. Qualquer outra coisa (incluindo tempo esgotado) vira nova tentativa, com espera crescente: na hora, 1 minuto, 5 minutos, 30 minutos, 2 horas e 6 horas. Depois disso a loja marca a entrega como falha e ela fica no painel esperando reenvio manual.

Como a rede às vezes entrega duas vezes o que saiu uma, o cabeçalho X-Micrata-Entrega repete o mesmo identificador em todas as tentativas do mesmo evento. Quem recebe precisa guardar esse identificador e ignorar o que já processou. Sem isso, uma retentativa emite a segunda nota fiscal do mesmo pedido. Cancelar nota é bem mais caro do que gravar um id.

Nada disso está ligado aqui. É o desenho, não a falta dele

Nenhuma das integrações desta página está ativa nesta demonstração. Não existe chave de gateway, token da Meta, credencial de ERP ou certificado digital nesta máquina. Não estão escondidos em variável de ambiente: não existem.

Não é limitação de demonstração, é a mesma regra que vale nas lojas reais que operamos: segredo vive só onde é usado. Uma vitrine pública que não processa pagamento não tem por que carregar a chave que o processa: o que não está na máquina não vaza dela. Por isso o token da Conversions API fica no servidor e nunca chega ao navegador, e por isso o certificado A1 fica no emissor fiscal e não no contêiner que atende a internet.

A rota /api/v1 também não está publicada aqui: o formato é real, o endereço não. Numa loja de verdade ela nasce com chave por integração, escopo por chave e registro de cada chamada. Trocou de contador ou de agência? Você revoga só aquela chave, e as outras continuam de pé.