Webhooks da Shelf: os dados de cada venda
Atualizado a 23 de outubro de 2026
Um webhook envia cada venda paga e cada novo lead da tua loja para um endereço teu, em segundos. É a base de todas as automações: faturas automáticas, listas de email, folhas de cálculo ou avisos à tua equipa.
Ligar um webhook
- 1No Make, cria um cenário com o módulo Webhooks → Custom webhook, clica em Add e copia o URL (começa por
https://hook.). - 2Na Shelf, vai a Definições → Integrações → Webhooks, cola o URL e clica em Ligar webhook. Depois clica em Enviar evento de teste.
- 3O Make fica a conhecer os campos da venda e podes usá-los nos módulos seguintes como
{{1.data.buyer.email}}.
- 1No Zapier, cria um Zap com o gatilho Webhooks by Zapier → Catch Hook e copia o URL (começa por
https://hooks.zapier.com/hooks/catch/). - 2Na Shelf, vai a Definições → Integrações → Webhooks, cola o URL e clica em Ligar webhook. Depois clica em Enviar evento de teste.
- 3No Zapier, clica em Test trigger: os campos aparecem com nomes como Data Buyer Email.
- 1No n8n, junta o nó Webhook com HTTP Method POST e copia o Production URL.
- 2Na Shelf, vai a Definições → Integrações → Webhooks, cola o URL e clica em Ligar webhook. Depois clica em Enviar evento de teste. Para ver o teste no editor, clica antes em Listen for test event e usa, só para isso, o Test URL.
- 3Os dados chegam dentro de
body: por exemplo{{ $json.body.data.buyer.email }}. Ativa o workflow para o Production URL ficar à escuta.
- 1Cria um endereço
https://que aceitePOSTcom JSON e responda2xxem menos de 10 segundos. - 2Na Shelf, vai a Definições → Integrações → Webhooks, cola o URL e clica em Ligar webhook. Depois clica em Enviar evento de teste. Copia o segredo de assinatura: só o vês uma vez.
- 3Confirma a assinatura de cada pedido com o corpo exatamente como chegou, antes de o converteres em JSON:
import crypto from "node:crypto";
// raw: o corpo do pedido como texto, header: o cabeçalho Shelf-Signature, secret: o segredo do webhook
export function shelfSignatureOk(raw, header, secret) {
const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
const t = Number(parts.t);
if (!t || Math.abs(Date.now() / 1000 - t) > 300) return false;
const expected = crypto.createHmac("sha256", secret).update(`${t}.${raw}`).digest("hex");
const got = Buffer.from(parts.v1 || "");
return got.length === expected.length && crypto.timingSafeEqual(got, Buffer.from(expected));
}O cabeçalho é Shelf-Signature: t=…,v1=…: t em segundos e v1 o HMAC-SHA256 de t + "." + corpo com o segredo. Recusa pedidos com mais de 5 minutos. O mesmo evento pode, raramente, chegar duas vezes: usa o id para ignorar repetidos.
Os eventos
sale.paid: uma venda paga, incluindo order bumps. Uma venda com cupão de 100% também conta, comcoupon_full: truee total 0.00.lead.created: alguém recebe um produto gratuito ou um lead magnet.lesson.completedecourse.completed: um aluno conclui uma aula ou um curso inteiro. Chegam só se os ligares no cartão do webhook (Aula concluída e Curso concluído).
O evento de teste
Enviar evento de teste envia uma venda de exemplo com "test": true, para a ferramenta conhecer os campos antes da primeira venda. Numa venda real, o campo test não existe: junta a condição «test não existe» ao filtro antes de ligar a automação a sério.
{
"id": "evt_…",
"type": "sale.paid",
"created_at": "2026-10-23T10:00:00.000Z",
"api_version": "2026-10-01",
"test": true,
"store": {
"username": "aminhaloja",
"url": "https://shelf.pt/aminhaloja"
},
"data": {
"order_id": "00000000-0000-0000-0000-000000000000",
"ordered_at": "2026-10-23T10:00:00.000Z",
"product": {
"id": "00000000-0000-0000-0000-000000000001",
"title": "Produto de teste",
"type": "digital",
"url": "https://shelf.pt/aminhaloja"
},
"buyer": {
"name": "Cliente Teste",
"email": "cliente@exemplo.pt",
"nif": "123456789",
"marketing_consent": true,
"custom_fields": {
"Como nos conheceste?": "Instagram"
}
},
"amount": {
"total": "19.00",
"original": "19.00",
"discount": "0.00",
"coupon": null,
"pwyw": false,
"currency": "EUR"
},
"consents": {
"terms": {
"version": "…",
"accepted_at": "2026-10-23T10:00:00.000Z"
},
"immediate_access": {
"kind": "digital_content",
"accepted_at": "2026-10-23T10:00:00.000Z"
}
},
"coupon_full": false,
"payment": {
"method": "mb_way",
"stripe_payment_intent": null
},
"bumps": [],
"tax": null
}
}Os campos
| O que é | Campo |
|---|---|
| Tipo de evento | type |
| Só no evento de teste | test |
| Id do evento (para ignorar repetidos) | id |
| Id da encomenda | data.order_id |
| Data da compra | data.ordered_at |
| Produto | data.product.title, id, type, url |
| Nome do cliente | data.buyer.name |
| Email do cliente | data.buyer.email |
| NIF (null quando não o indica) | data.buyer.nif |
| Aceitou emails de marketing (null: não foi perguntado) | data.buyer.marketing_consent |
| Campos personalizados, pelo nome do campo | data.buyer.custom_fields |
| O que o cliente pagou | data.amount.total |
| Valor antes do cupão | data.amount.original |
| Desconto do cupão | data.amount.discount |
| Código do cupão | data.amount.coupon |
| Moeda | data.amount.currency |
| Cupão de 100% | data.coupon_full |
| Método de pagamento | data.payment.method |
| Order bumps (título e valor) | data.bumps |
| IVA cobrado pela Shelf (null se não cobras) | data.tax |
| Termos e acesso imediato aceites | data.consents |
Os valores vêm em euros, como texto com duas casas decimais ("19.00"). Um lead (lead.created) traz o produto, o cliente, os valores e os consentimentos, sem pagamento nem order bumps.
Métodos de pagamento
card: cartão, incluindo Apple Pay e Google Pay.mb_way: MB WAY (vendas mais antigas podem trazermbway).revolut_pay: Revolut Pay, se o ligares.free: sem pagamento, numa venda com cupão de 100%.
Perguntas frequentes
O que acontece se o meu endereço estiver em baixo?+
Tentamos de novo até 8 vezes ao longo de cerca de 45 horas. Se o endereço responder 410 (removido), o webhook é desligado; reativa-o em Definições → Integrações.
Onde vejo se os envios estão a funcionar?+
Em Definições → Integrações → Webhooks, na lista Últimos envios: cada evento com o estado e o código de resposta.
Quantos webhooks posso ligar?+
Um por loja, por agora.
Os eventos trazem dados pessoais?+
Sim: o nome, o email, o NIF e os campos personalizados do cliente. Liga o webhook só a ferramentas e endereços teus. Na Shelf, os envios ficam guardados 30 dias.