Digital products and creators

Hotmart on WhatsApp: welcome, boleto and abandoned cart with a webhook

Hotmart notifies your system by webhook on every sales event. In version 2.0.0, the envelope has id, creation_date, event, version and data, and the security token (hottok) arrives in the X-HOTMART-HOTTOK header. ZapZap has Hotmart in the Recuperar vendas (Recover sales) assistant, under Fluxos (Flows): it generates the webhook URL and the message flow, and validates the hottok when you provide it.

Updated on

Why connect

A creator who sells on Hotmart lives on three messages: the welcome when the purchase is approved, the reminder for someone who printed the boleto and did not pay, and the nudge for someone who filled in the checkout and left. Hotmart has an event for all three (PURCHASE_APPROVED, PURCHASE_BILLET_PRINTED and PURCHASE_OUT_OF_SHOPPING_CART), but there is a phone catch that decides whether the flow fires or not, explained below. Message only buyers or leads who left their contact with you, and give them a way to stop receiving messages. ZapZap connects numbers through an unofficial, managed channel. It costs R$15 per active number per month, prepaid, with a welcome credit when you create the account, subject to the current campaign.

Step by step

  1. 1

    Create the webhook setting in Hotmart on 2.0.0

    In Hotmart, open Tools and then Webhook and create a setting. Choose version 2.0.0 (1.0.0 is discontinued and only people who already had a setting on it can create new ones), select the product and the events, and paste the URL. Hotmart keeps the event history for up to 60 days, which helps when resending a test.

  2. 2

    Generate the URL in ZapZap and pick the goal

    In Fluxos, click Recuperar vendas, choose Hotmart, the goal and the number. The URL, in the format https://api.zapzapapi.com/api/webhooks/flow/{secret}, is the one that goes into Hotmart. The flow comes out on and linked to the chosen number, with starter texts that use {nome} and {produto}.

  3. 3

    Enter the hottok to validate the origin

    The hottok is a unique token per account, under Tools > Webhook > Authentication. Hotmart sends it in the X-HOTMART-HOTTOK header of every request and recommends validating it before processing. Save it in the assistant and ZapZap starts rejecting with 401 any event whose hottok does not match. To change the token you have to contact Hotmart support.

  4. 4

    Sort out the phone before the first send

    On the abandoned cart, data.buyer.phone has the phone with the country code. On purchase events, data.buyer.checkout_phone has the checkout phone and, for a Brazilian buyer, the area code comes separately in data.buyer.checkout_phone_code. ZapZap only accepts as a phone a value of 10 to 13 digits; a 9-digit number without the area code is not detected and the flow answers triggered: 0. Run a test and check the detected field in the webhook editor.

  5. 5

    Test, read the history and adjust

    Fire a test from Hotmart, see the received sample in ZapZap and the event history in Hotmart. If the phone does not arrive complete, the path is an endpoint of yours: you concatenate area code and number, and call the ZapZap API directly, as in the example below.

Example

// When the phone arrives without the area code: your endpoint joins them and sends through ZapZap
import express from 'express';
const app = express();

app.post('/hotmart', express.json(), async (req, res) => {
  if (req.get('X-HOTMART-HOTTOK') !== process.env.HOTMART_HOTTOK) return res.sendStatus(401);
  const { id, event, data } = req.body;
  res.sendStatus(200);
  if (event !== 'PURCHASE_APPROVED') return;
  if (await alreadyProcessed(id)) return; // your function: UNIQUE on the event id

  const b = data.buyer;
  const phone = String((b.checkout_phone_code || '') + (b.checkout_phone || '')).replace(/\D/g, '');
  if (phone.length < 10) return;

  await fetch('https://api.zapzapapi.com/api/v1/' + process.env.ZAPZAP_INSTANCE + '/send/text', {
    method: 'POST',
    headers: {
      'x-api-key': process.env.ZAPZAP_API_KEY,
      'x-api-secret': process.env.ZAPZAP_API_SECRET,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      number: phone.startsWith('55') ? phone : '55' + phone,
      text: 'Hi, ' + b.first_name + '! Your purchase of ' + data.product.name + ' was approved. Any questions, just reply here.',
    }),
  });
});

Illustrative. The exact fields and endpoints are in the documentation.

2.0.0 events that matter and where the phone is

The names below are from the official 2.0.0 documentation. The purchase.status field accompanies the event and helps filter, for example WAITING_PAYMENT or PRINTED_BILLET.

GoalEventPhone and useful data
WelcomePURCHASE_APPROVEDdata.buyer.checkout_phone and checkout_phone_code, data.buyer.first_name, data.product.name, purchase.price.value
Unpaid boletoPURCHASE_BILLET_PRINTEDdata.purchase.payment.billet_url and billet_barcode when the payment is by boleto
Abandoned cartPURCHASE_OUT_OF_SHOPPING_CARTdata.buyer.phone (with country code), data.buyer.name, data.product.name, data.offer.code
Delay and cancellationPURCHASE_DELAYED, PURCHASE_CANCELED, PURCHASE_REFUNDEDUseful for subscriptions; check the purchase.status of each one

What the documentation says and what you need to test

The abandoned cart event is generated when the person fills in a name or email on the payment page and leaves; Hotmart runs this check every 30 minutes, so the message does not arrive the second the customer closes the tab. Factor in that delay when writing the text and choosing when to send the second reminder.

For Pix, the documentation lists the fields pix_code, pix_qrcode and pix_expiration_date inside purchase.payment, but the event list has no dedicated name for Pix generated. Test in your account which event arrives when someone picks Pix and does not pay, before promising that message in your flow.

An affiliate product requires the producer to release the buyer's data; without that, the phone does not arrive.

Security, duplicates and what Hotmart does with a URL that errors

  • hottok: validate it on every request. It does not sign the body, it is a fixed token; treat it as a secret and do not write it to logs.
  • Duplicates: every event has a unique id. Store it and ignore repeats. ZapZap, for its part, does not fire the same flow twice for the same phone within 10 minutes.
  • Dates: creation_date and approved_date come in milliseconds since 1970 (UTC). Convert before comparing with local time.
  • URL with errors: the Hotmart help center says the setting is deactivated if the registered URL returns an error. Check the status of your setting after a deploy.
  • ZapZap limit: 120 requests per minute per webhook; above that the response is 429.

When NOT to use the ZapZap assistant

Do not use the assistant if the checkout phone arrives without the area code in your product and you cannot or do not want to change the checkout to require the full number: in that case the field is not detected. Also do not use it to message your entire base of old buyers, who were never told they would receive WhatsApp: that is a campaign, not a notification, and it requires consent. For your own rules (querying your members area, generating an access link), prefer an endpoint of yours, using the example above.

Sources and date checked

Event names, payload fields, the X-HOTMART-HOTTOK header, version 2.0.0, the 30-minute cart rule and the 60-day history were checked on 29 Oct 2026 in the official Hotmart documentation (developers.hotmart.com), on the pages Request events and Cart abandonment event for version 2.0.0 and Using Webhooks, and in the Hotmart help center. ZapZap's behavior comes from the product code in production.

Frequently asked questions

Where does Hotmart send the hottok in version 2.0.0?

In the X-HOTMART-HOTTOK HTTP header of every request. The documentation recommends validating it before processing. In the discontinued version 1.0.0, the hottok came as a body field.

Why does the flow not fire on PURCHASE_APPROVED?

The most likely reason is the phone. In data.buyer.checkout_phone a Brazilian buyer's number may come without the area code, which sits in checkout_phone_code. ZapZap only accepts a phone of 10 to 13 digits, so the flow answers triggered: 0. Test and, if that is the case, join the two fields in an endpoint of yours.

How long after does the abandoned cart event arrive?

Hotmart checks carts every 30 minutes. Sending starts when the person fills in a name or email on the payment page. Plan the message for that rhythm and avoid writing as if the customer had just left.

Is there a Pix generated event?

The version 2.0.0 event list we checked has no dedicated name for Pix generated. The payload has pix_code, pix_qrcode and pix_expiration_date in purchase.payment. Test in your account which event arrives when someone picks Pix and does not pay.

Can I use version 1.0.0 of the webhook?

Hotmart itself says 1.0.0 is discontinued and that only people who already had a setting on it can create new ones. For a new integration, use 2.0.0. The envelope changes: fields like email and phone_number leave the first level and move inside data.buyer.

Does Hotmart resend the event if my server fails?

The documentation we consulted does not detail the retry policy, but events have a unique id and stay in the history for up to 60 days. Treat each id as an idempotency key and watch the status of the setting, because the help center says it is deactivated if the URL returns an error.

Can I message everyone who ever bought?

Not through this path. Notifying about a current purchase is one thing; a campaign to the old base is another, and it requires consent and care with pace. ZapZap is an unofficial channel and does not remove the blocking risk.

Start now

Create your account, connect a number in minutes and test the API with warm-up and anti-ban. R$15 per active number/month, prepaid, no lock-in.