# Exemplos: Hotmart, Kiwify, Shopify e formulários

> O que a Hotmart, a Kiwify e a Shopify mandam por webhook e os caminhos de telefone, e-mail, nome, produto e status. E um formulário do site sem expor o link.

Endereço: https://docs.nextags.com.br/webhooks/exemplos-de-plataformas/
Tipo: Guia

Atualizado em: 26/10/2026

Hotmart, Kiwify e Shopify avisam cada venda por webhook. O caminho é o mesmo nas três: o webhook da plataforma manda os dados para um webhook de entrada da NexTags, que acha ou cria o contato e inicia o fluxo. Para cada plataforma, este guia mostra um trecho do JSON da documentação oficial e o caminho (JSONPath) de cada dado. No fim, um formulário do seu site que manda os dados pelo seu servidor, sem expor o link.

**Antes de começar**

- Um webhook de entrada para cada plataforma, com o link copiado em **Obter Link**. Veja [Webhook de entrada: receber dados de outro sistema](https://docs.nextags.com.br/webhooks/webhook-de-entrada/).
- O fluxo de cada aviso, publicado. Para quem não falou com você nas últimas 24 horas, um fluxo de WhatsApp começa com um Modelo de Mensagem aprovado. Veja [Modelo de mensagem do WhatsApp no fluxo](https://help.nextags.com.br/tutoriais/fluxos/modelos-no-fluxo/).
- Um envio de teste de cada plataforma, para conferir os caminhos com dados reais.

## Passo a passo

### Passo 1: Hotmart: compras e outros eventos

Na Hotmart, em **Ferramentas** › **Ver todas** › **Webhook (API e notificações)**, clique em **+ Cadastrar Webhook**, marque os eventos e cole o link da NexTags como URL. Os dados da venda vêm em `data`, e o nome do evento, em `event`. Trecho do exemplo oficial da Hotmart (evento de compra, versão 2.0.0), encurtado:

```json
{
  "id": "1234567890123456789",
  "creation_date": 12345678,
  "event": "PURCHASE_APPROVED",
  "version": "2.0.0",
  "data": {
    "product": {
      "id": 213344,
      "name": "Product Name"
    },
    "buyer": {
      "email": "buyer@email.com",
      "name": "Buyer Name",
      "first_name": "Buyer",
      "last_name": "Name",
      "checkout_phone": "999999999",
      "checkout_phone_code": "31"
    },
    "purchase": {
      "status": "STARTED",
      "transaction": "HP02316330308193"
    }
  }
}
```

| Dado | JSONPath | No exemplo |
|---|---|---|
| Telefone | `$.data.buyer.checkout_phone` | `999999999` |
| DDD (só compradores do Brasil) | `$.data.buyer.checkout_phone_code` | `31` |
| E-mail | `$.data.buyer.email` | `buyer@email.com` |
| Nome | `$.data.buyer.name` | `Buyer Name` |
| Produto | `$.data.product.name` | `Product Name` |
| Status da compra | `$.data.purchase.status` | `STARTED` |
| Evento | `$.event` | `PURCHASE_APPROVED` |
| Código da transação | `$.data.purchase.transaction` | `HP02316330308193` |

No exemplo oficial, o telefone vem sem o código do país e sem o DDD, que chega à parte em `checkout_phone_code`. A Hotmart diz que, nas vendas para fora do Brasil, o código do país vem junto ao telefone. Como a tela do webhook de entrada usa um caminho só para o telefone, confira um envio real no **Histórico** da Hotmart. Se o número vier incompleto, identifique o contato pelo e-mail e guarde o DDD e o telefone em campos, ou receba o webhook num servidor seu, monte o número completo (`55` + DDD + número) e repasse para a NexTags, como no formulário do último passo.

A Hotmart manda em todas as requisições o cabeçalho `X-HOTMART-HOTTOK`, que identifica a sua conta. A tela do webhook de entrada não tem onde conferir esse cabeçalho: para conferir, receba o webhook num servidor seu. Fonte: [Eventos de pedidos do Webhook da Hotmart](https://developers.hotmart.com/docs/pt-BR/2.0.0/webhook/purchase-webhook/). A configuração na NexTags, passo a passo: [Hotmart](https://help.nextags.com.br/integracoes/hotmart/).

### Passo 2: Kiwify: compra aprovada, Pix e boleto

Na Kiwify, em **Apps** › **Webhooks**, crie um webhook, cole o link da NexTags como URL, escolha os produtos e os eventos. Cada evento chega por POST com o JSON no corpo. A Kiwify acrescenta ao link o parâmetro `signature`, uma assinatura do corpo; a tela do webhook de entrada não tem onde conferir, mas um servidor seu pode. O exemplo oficial da Kiwify, que omite os dados do cliente:

```json
{
  "order_id": "9b1c2d3e-0000-4000-8000-000000000001",
  "order_status": "paid",
  "webhook_event_type": "order_approved"
}
```

| Dado | JSONPath |
|---|---|
| Telefone, e-mail e nome | No bloco `Customer`. Os exemplos oficiais omitem esse bloco: confira os nomes num **Testar Webhook**, em **Ver logs**, e escolha os caminhos com a lupa do editor. |
| Produto | Confira no envio real, em **Ver logs**. |
| Status do pedido | `$.order_status` |
| Evento | `$.webhook_event_type` |
| ID do pedido | `$.order_id` |

O gatilho que você marca na Kiwify e o valor que chega em `webhook_event_type` nem sempre têm o mesmo nome:

| Gatilho na Kiwify | `webhook_event_type` | `order_status` |
|---|---|---|
| `compra_aprovada` | `order_approved` | `paid` |
| `pix_gerado` | `pix_created` | `waiting_payment` |
| `boleto_gerado` | `billet_created` | `waiting_payment` |
| `compra_recusada` | `order_rejected` | `refused` |
| `compra_reembolsada` | `order_refunded` | `refunded` |
| `chargeback` | `chargeback` | `chargedback` |

O carrinho abandonado chega em outro formato, sem `webhook_event_type` nem `order_status`: use um webhook de entrada só para ele. A Kiwify espera uma resposta de 200 a 299 em até 40 segundos, tenta de novo quando falha e pode mandar o mesmo evento mais de uma vez. Fonte: [Receber e validar webhooks, da Kiwify](https://docs.kiwify.com.br/api-reference/webhooks/receiving). A configuração na NexTags, passo a passo: [Kiwify](https://help.nextags.com.br/integracoes/kiwify/).

### Passo 3: Shopify: pedidos

No admin da Shopify, em **Configurações** › **Notificações** › **Webhooks**, clique em **Criar webhook**. Em **Evento**, escolha o aviso, como **Criação de pedido**; deixe o **Formato** em **JSON** e cole o link da NexTags em **URL**. O evento não muda depois: crie um webhook para cada aviso, como **Pagamento de pedido** e **Cancelamento de pedido**. Trecho do exemplo oficial do tópico `orders/create`, encurtado:

```json
{
  "id": 820982911946154508,
  "email": "jon@example.com",
  "phone": null,
  "name": "#9999",
  "order_status_url": "https://jsmith.myshopify.com/548380009/orders/123456abcd/authenticate?key=abcdefg",
  "financial_status": "voided",
  "fulfillment_status": null,
  "total_price": "404.95",
  "billing_address": {
    "name": "Steve Shipper",
    "phone": "555-555-SHIP"
  },
  "customer": {
    "first_name": "John",
    "last_name": "Smith",
    "email": "john@example.com",
    "phone": null
  },
  "line_items": [
    { "title": "Aviator sunglasses", "quantity": 1, "price": "89.99" }
  ]
}
```

| Dado | JSONPath | No exemplo |
|---|---|---|
| Telefone | `$.billing_address.phone` | `555-555-SHIP` |
| E-mail | `$.email` | `jon@example.com` |
| Nome | `$.billing_address.name` | `Steve Shipper` |
| Produto (o primeiro do pedido) | `$.line_items[0].title` | `Aviator sunglasses` |
| Status do pagamento | `$.financial_status` | `voided` |
| Status do envio | `$.fulfillment_status` | `null` |
| Número do pedido | `$.name` | `#9999` |
| Link de acompanhamento | `$.order_status_url` | o endereço da página do pedido |

O telefone depende de onde a sua loja pede o número: no endereço de cobrança, no de entrega (`$.shipping_address.phone`) ou no cliente (`$.customer.phone`). É um texto livre, digitado pelo cliente, e pode vir vazio: use o e-mail para identificar o contato quando o telefone não for confiável. A Shopify apaga o webhook quando o endereço responde com erro muitas vezes seguidas. Fontes: [Criar webhooks, na Central de Ajuda da Shopify](https://help.shopify.com/pt-BR/manual/fulfillment/setup/notifications/webhooks) e [tópicos de webhook da Shopify](https://shopify.dev/docs/api/webhooks/latest). A configuração na NexTags, passo a passo: [Shopify](https://help.nextags.com.br/integracoes/shopify/).

### Passo 4: Formulário do seu site

O navegador não deve mandar os dados direto para o link do webhook de entrada: o link ficaria no código da página, à vista de qualquer um. O formulário manda os dados para o seu servidor, e o servidor manda o JSON para a NexTags, com o link guardado na variável de ambiente `NEXTAGS_WEBHOOK_URL`.

O formulário:

```html
<form method="post" action="/lead">
  <input name="nome" placeholder="Seu nome" required>
  <input name="email" type="email" placeholder="Seu e-mail">
  <input name="telefone" type="tel" placeholder="WhatsApp com DDD" required>
  <button type="submit">Quero falar no WhatsApp</button>
</form>
```

O servidor, que recebe o formulário, deixa o telefone só com números, com o `55` na frente, e repassa:

**Repassar o formulário para o webhook de entrada**

```javascript
// servidor.mjs (Node 18 ou mais novo): node servidor.mjs
import http from 'node:http';

http.createServer(async (req, res) => {
  if (req.method !== 'POST' || req.url !== '/lead') {
    res.writeHead(404).end();
    return;
  }
  let corpo = '';
  for await (const parte of req) corpo += parte;
  const form = new URLSearchParams(corpo);

  const digitos = (form.get('telefone') || '').replace(/\D/g, '');
  const telefone = digitos.length <= 11 ? `55${digitos}` : digitos; // 55 + DDD + número

  const resposta = await fetch(process.env.NEXTAGS_WEBHOOK_URL, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      origem: 'formulario-site',
      lead: {
        nome: form.get('nome') || '',
        email: form.get('email') || '',
        telefone,
      },
    }),
  });
  if (resposta.ok) {
    res.writeHead(303, { Location: '/obrigado.html' }).end();
  } else {
    res.writeHead(502).end('Não deu certo. Tente de novo em alguns minutos.');
  }
}).listen(3000);
```
```python
# servidor.py (Flask): flask --app servidor run --port 3000
import os
import re

import requests
from flask import Flask, redirect, request

app = Flask(__name__)

@app.post("/lead")
def lead():
    digitos = re.sub(r"\D", "", request.form.get("telefone", ""))
    telefone = "55" + digitos if len(digitos) <= 11 else digitos  # 55 + DDD + número

    resposta = requests.post(
        os.environ["NEXTAGS_WEBHOOK_URL"],
        json={
            "origem": "formulario-site",
            "lead": {
                "nome": request.form.get("nome", ""),
                "email": request.form.get("email", ""),
                "telefone": telefone,
            },
        },
        timeout=30,
    )
    if resposta.ok:
        return redirect("/obrigado.html", code=303)
    return "Não deu certo. Tente de novo em alguns minutos.", 502
```
```php
<?php
// lead.php: no formulário, use action="/lead.php"
$digitos = preg_replace('/\D/', '', $_POST['telefone'] ?? '');
$telefone = strlen($digitos) <= 11 ? '55' . $digitos : $digitos; // 55 + DDD + número

$ch = curl_init(getenv('NEXTAGS_WEBHOOK_URL'));
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => [
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'origem' => 'formulario-site',
        'lead' => [
            'nome' => $_POST['nome'] ?? '',
            'email' => $_POST['email'] ?? '',
            'telefone' => $telefone,
        ],
    ]),
    CURLOPT_TIMEOUT => 30,
]);
curl_exec($ch);
$codigo = curl_getinfo($ch, CURLINFO_HTTP_CODE);

if ($codigo >= 200 && $codigo < 300) {
    header('Location: /obrigado.html', true, 303);
} else {
    http_response_code(502);
    echo 'Não deu certo. Tente de novo em alguns minutos.';
}
```

| Dado | JSONPath |
|---|---|
| Telefone | `$.lead.telefone` |
| E-mail | `$.lead.email` |
| Nome | `$.lead.nome` |
| Origem | `$.origem` |

No formulário, peça a permissão para mandar mensagens pelo WhatsApp, com um texto claro ao lado do botão. Veja [Permissão para mensagens (opt-in) e descadastro](https://help.nextags.com.br/tutoriais/canais/opt-in/).

## Pronto: como conferir

- Faça um envio de teste em cada plataforma: na Hotmart, pela aba **Minhas configurações** ou pelo reenvio no **Histórico**; na Kiwify, com **Testar Webhook**; na Shopify, com um pedido de teste. Depois do envio, o contato aparece em **Contatos**, com os campos preenchidos.
- Cole o JSON de um envio real em **Sample JSON**, clique em **Load sample JSON** e confira o `Result:` de cada caminho.
- No formulário, envie com o seu número: o fluxo chega no seu WhatsApp.

## Se não funcionou

### O contato foi criado com o telefone incompleto

O caminho do telefone pegou um número sem o código do país ou sem o DDD, como o `checkout_phone` do exemplo da Hotmart. Identifique o contato pelo e-mail ou monte o número completo num servidor seu antes de mandar para a NexTags.

### A plataforma desativou ou apagou o webhook

Hotmart e Shopify desativam ou apagam o webhook quando o endereço responde com erro. Confira se o webhook de entrada foi salvo e está **Ativo** e se o link está inteiro. Depois, reative ou recrie o webhook do lado da plataforma.

### O mesmo aviso iniciou o fluxo duas vezes

As plataformas podem mandar o mesmo evento mais de uma vez. No fluxo, aplique uma etiqueta e confira com uma condição antes de mandar a mensagem. Veja [Segurança, testes e novas tentativas](https://docs.nextags.com.br/webhooks/seguranca-e-testes/).

### O formulário não chega

Confira o log do seu servidor: a variável `NEXTAGS_WEBHOOK_URL` tem o link inteiro? O servidor recebeu a resposta da NexTags? Veja [Meu webhook de entrada não recebe os dados](https://help.nextags.com.br/perguntas/integracoes/webhook-nao-recebe/).

### Faça com a IA

Cole este pedido no ChatGPT ou no Claude:

```text
Vou ligar [Hotmart / Kiwify / Shopify / o formulário do meu site] a um webhook de entrada da NexTags. Leia este guia: https://docs.nextags.com.br/webhooks/exemplos-de-plataformas.md

Este é o JSON de um envio de teste, sem dados reais: [cole aqui]. Me diga os caminhos (JSONPath só com .chave, ["chave"] e [0]) do telefone, do e-mail, do nome, do produto e do status, os campos personalizados que devo criar e se o telefone já vem completo, com o código do país e o DDD.
```
