## Overview

**Sales recovery** is the layer that makes sure a commerce event **always becomes a visible action**.
Previously the recovery card could die in silence: if the customer had no open conversation, or if the
message fell outside the WhatsApp window, nothing happened and nobody found out.

Now every lifecycle event — from Kiwify, Hotmart, Nuvemshop or the native gateway (Asaas / Mercado
Pago) — goes through three guarantees:

1. A **conversation resolver** decides where the card goes, using a **policy** you choose.
2. A **send-window guard** checks whether the channel accepts the message at that moment.
3. A **delivery outcome** is recorded on **every** exit path: `sent`, `skipped` or `failed`, always
   with a readable **reason**.

The practical result: you open the **Sales recovery** page and see how many opportunities were reached,
how many were not, and **exactly why** — instead of discovering weeks later that an entire cadence
never went out.

### When each stage fires

| Stage | Fires when | Actionable? |
|---|---|---|
| **Abandoned cart** | the customer built a cart/checkout and did not complete it | Yes |
| **Payment pending** | a PIX or boleto was generated and is still unpaid | Yes |
| **Payment declined** | the card was refused by the issuer or by anti-fraud | Yes |
| **Overdue** | the due date passed without payment | Yes |
| **Order placed** | the order was registered on the platform and remains pending | No (does not settle) |
| **Payment confirmed** | the payment was approved | No (settlement) |
| **Refunded** | the amount was returned to the customer | No |
| **Chargeback** | the customer disputed the charge with the issuer | No |
| **Subscription late** | the subscription renewal failed or is late | No |
| **Subscription canceled** | the subscription was terminated | No |

The four **actionable** stages are the ones that count toward the recovery rate. Refunds and chargebacks
never count as recovery — they are the opposite of it.

`due_soon` remains a recognized stored value for backwards compatibility, but no current connector or
native gateway produces it. It is therefore not offered in automatic recovery or the Follow-up picker.

## Prerequisites

- The **Sales recovery** feature (`commerce_recovery`) **enabled on the account**. It ships **OFF by
  default**; ask whoever administers the installation to turn it on.
- An **administrator** or **agent** profile on the account. Both can open the recovery page, change
  policies and resend cards — there is no separate per-module permission here.
- At least one **commerce source** connected (Kiwify, Hotmart, Nuvemshop) or a **native gateway**
  configured (Asaas / Mercado Pago), so that events arrive.
- To send outside the WhatsApp window: an **approved template** on the matching inbox.

With the feature off, the new page, the sidebar panel and the metrics stay hidden. Delivery itself
(conversation policy, recorded outcome) keeps working behind the scenes — it is behavior-preserving
infrastructure.

## Step by step

1. Open **Sales recovery** from the commerce module menu.
2. Check the **actionable stage funnel**: it uses the same four stages as attempted and recovered
   metrics; settlements, refunds and cancellations do not enter this funnel.
3. Look at the **delivery** block: `sent`, `skipped`, `failed` and `not attempted`.
4. Open the **reasons** list — it is ordered from most to least frequent. That is your fix list, in
   order of impact.
5. Click an event to see the card, the target conversation and the delivery history.
6. If the card did not go out for a reason you have already fixed (channel reconnected, template
   approved), use **Resend**. If you need to bypass the duplicate guard, tick **force**.
7. Adjust the **conversation policy** on the automation/macro action so the next event of the same type
   does not fall into the same reason.

## Settings & options

### The conversation policy (the most important choice)

When the card must be delivered, the platform needs to know **which conversation** to write into. You
have three options:

| Policy | What it does | When to use it |
|---|---|---|
| **Use an existing conversation** *(default)* | Delivers into the contact's most recent conversation. **Never creates** one. If there is none, the card is skipped with reason `no_conversation`. | The safe default — it is exactly today's behavior. Nothing changes for existing setups. |
| **Create one if needed** | Uses the existing conversation when there is one; **creates a new one** when there isn't. | When you want maximum reach and accept that a new conversation becomes visible to the customer. |
| **Only this conversation** | Delivers strictly into the conversation where the rule fired. Never looks elsewhere, never creates. | When the card only makes sense in the context of that specific conversation. |

> **Why "create one if needed" is opt-in:** creating a conversation is an action that is **visible to
> the customer** and to the team's queue. It shows up in the inbox, counts in reports and can trigger
> notifications. That is why Conversa Labs never does it on its own — you have to choose it.

### The WhatsApp 24-hour window (no half-truths)

WhatsApp only allows free-form messages within **24 hours** of the customer's last message. Outside
that window:

- **Without an approved template** → the card is **skipped**, with reason `whatsapp_window_closed`. It
  is **not delivered**. Conversa Labs would rather record the reason than queue a message WhatsApp is
  going to reject.
- **With an approved template** → delivery **degrades to the single template message**. You reach the
  contact, but **not** with the full rich card: only what the approved template allows.

**WhatsApp Web has no window.** WhatsApp Web inboxes deliver normally at any time — the 24-hour
restriction belongs to the official WhatsApp Business API, not to the platform.

**Exception: hybrid pair.** If you run a hybrid pair with Cloud as primary and out-of-window routing to
WhatsApp Web, the send goes out in full as a Web session message — it is neither converted to a template
nor skipped. Do not expect `whatsapp_window_closed` in that setup.

### Other channels

The card always carries the **payment link in the message body**, never only as an attachment. This is
deliberate: **LINE, TikTok and X (Twitter)** drop or reject attachments. If the link travelled only in
the attachment, the customer would receive a message missing the one thing that matters.

### Card delivery and the "not attempted" queue

The panel shows the **delivery split** — sent, skipped, failed and **not attempted**. The
"not attempted" bucket is the one that never got a card at all: no rule ever acted on that event. It
is no longer a dead number: you can **filter the timeline by it** and **queue the pending ones** in
bounded batches, oldest first, up to 50 at a time.

The action returns **accepted/queued**, not a delivery total. Processing happens in the background and
the actual `sent`, `skipped` or `failed` outcomes appear later in the timeline. It never opens a new
conversation: an event with nowhere to deliver is recorded as skipped with the corresponding reason.
Imported or gateway-adopted history is always excluded from this queue.

> **Why "Recoveries attempted" can read 0 with a full list.** The count only considers actionable
> events **whose card was recorded as sent**. If no card was ever sent, the denominator is zero — the
> page is not broken, it is telling you nobody has been reached yet.

### Automatic recovery by stage (default off)

Under **Messages → Automatic recovery by stage**, enable only the live stages you want Conversa Labs to
queue automatically. Every switch starts **off**. The immediate lifecycle event queues the card, and a
five-minute backstop repairs a missed queue handoff. Both paths re-check the switch before delivery,
reuse an existing conversation, respect the WhatsApp 24-hour window, and defer when the connection's
safe send rate is full.

Imported and adopted charges are history: they stay visible for audit/reporting with the
**Historical — sending blocked** badge, but are excluded from every customer send. Automatic recovery,
manual backlog drains, the backstop, Follow-up, forced resend, automations and Maestro cannot bypass
this guard.

### The order of the card's messages

The card is a sequence: summary → pay button → PIX copy-and-paste → QR code → boleto → digitable
line. That order is now **guaranteed on delivery** — each message used to be sent on its own and they
could arrive shuffled (the raw PIX code reaching the customer before the message telling them to copy
it).

Under **Messages → Delivery** you set the **pause between the card's messages**. Leave it blank to use
the channel default: on phone-linked WhatsApp (WazMeow) it is 1 second, to space the burst out and not
look like an automated blast; on other channels there is no pause.

### Opening the conversation and resending

Every live row has **Open conversation** (jumps straight to that customer's thread) and **Resend card**.
The resend targets the conversation by its public identifier — it can never land on the wrong
customer. If the event has no conversation yet, the dialog says so before you confirm that one will be
opened with the customer. Historical rows do not show resend, and the API also refuses it even with
**force**.

## Use cases

- **A pending PIX that went cold**: the customer generated the PIX yesterday and vanished. The card
  resends the code into the existing conversation, without creating new noise.
- **A wave of card declines**: an issuer knocked down several transactions. You filter by
  `payment_declined`, see they were all skipped with `channel_unavailable`, reconnect the channel and
  resend in bulk.
- **An abandoned cart from someone who never talked to you**: a new contact, no conversation. With the
  "create one if needed" policy, the card opens the conversation and starts the support thread.
- **Cadence audit**: the reasons list shows 60% of sends died on `whatsapp_window_closed` — the clear
  signal that this cadence needs an approved template.

## Tips, limits & best practices

### The delivery outcomes and what to do about each

Every event ends in one of these states: **sent**, **skipped**, **failed** — or **not attempted**, when
no rule ever acted on it.

| Reason | What it means | What to do |
|---|---|---|
| `no_contact` | The event arrived with no identifiable contact (the source platform sent no usable phone/email). | Check the identification mapping on the commerce source. With no contact there is nobody to send to. |
| `no_conversation` | The contact exists, but there is no conversation to receive the card and the policy is "use an existing conversation". | If you want to reach these cases, switch the policy to **create one if needed**. |
| `no_channel_inbox` | There is no inbox for the channel the action asked for. | Connect that channel's inbox, or point the action at an inbox that exists. |
| `whatsapp_window_closed` | Outside the 24-hour window and without an approved template. | Attach an **approved template** to the action. Or move the cadence inside the window. |
| `throttled` | The channel's send limit was reached at that moment. | Space the cadence out. Large bursts on WhatsApp also increase the risk of a block. |
| `channel_unavailable` | The channel is disconnected, expired or unavailable. | Reconnect the inbox and resend the affected events. |
| `sequence_not_published` | The Follow-up sequence is still a draft. | Publish the sequence. Drafts never send — that is intentional. |
| `already_sent` | The duplicate guard blocked it: this event already had a card recorded as sent. | Nothing, in most cases. If you really must send again, use **Resend** with **force**. |

### Integrating with external systems

Every delivery outcome — sent, skipped or failed — is also emitted as the `commerce_card_delivery`
account webhook event, carrying the canonical reason. That is how an external system (n8n, a CRM)
reacts without polling: open a task when the reason is `no_conversation`, say, or try another channel
when it is `whatsapp_window_closed`. Enable it under **Settings → Integrations → Webhooks**.

### The duplicate guard and explicit resend

A single event creates and dispatches its card locally **once**. If an automation and a macro both try
to send the same card, the second is skipped with `already_sent` — that is the local duplicate guard.
Final provider delivery still has to be checked in the conversation/channel delivery state.

**Resending** is always explicit and human: you open the event and click **Resend**. It preserves the
record of the first send (original date and message) and only increments the resend counter — history
is never erased. To cross the guard on purpose, tick **force**.

### How to read the recovery rate (honestly)

The recovery rate is the **share of actionable attempts recorded as sent and assigned to a later
settlement for the same contact and the same order**.

Precisely:

- **Denominator**: actionable events (abandoned cart, pending, declined, overdue) **whose card was
  recorded as sent**.
- **Numerator**: later settlements with the **same contact, source and external order/charge id**.
  Paying a different order does not recover the first one.
- A settlement counts **once**. If one order received several actionable cards, it is assigned
  deterministically to the latest attempt recorded as sent before settlement. **Order placed never
  settles revenue**: only `payment_confirmed` enters the numerator.
- Events whose card was never recorded as sent are excluded from **both sides**. The `sent` state
  confirms local card creation and dispatch; it is not yet a final provider delivery receipt.
- When **nothing** was attempted in the period, the rate shows as **—**, not as 0%. Zero percent would
  mean "we tried and failed"; the dash means "there was no attempt".

> **This is correlation, not causation.** The metric says "the customer paid after we reached out", not
> "the customer paid **because** we reached out". Some of those people would have paid anyway. Use the
> number to compare cadences against each other and to track a trend — do not present it as revenue
> attributed to a campaign.

**Recovered revenue uses the settlement's value and currency**, not the value shown on the card.
Totals are displayed separately per currency — BRL and USD are never added together or labelled as
if everything were BRL. Values remain in each currency's **major unit**, with no hidden conversion.
When the source did not report a currency, the interface states that absence explicitly.

## Troubleshooting

- **"Not attempted" on many events**: no rule is acting on that stage. Create an automation or a
  Follow-up sequence for the stage in question.
- **Everything skipped with `no_conversation`**: your base is contacts with no open conversation and the
  policy is the default. Switch to **create one if needed** — remembering the new conversation is
  visible to the customer.
- **Everything skipped with `whatsapp_window_closed`**: the cadence is running outside the 24-hour
  window. Approve a template and attach it to the action, or move the trigger earlier.
- **Card delivered, but "poor"**: you are outside the window **with** a template. That is the correct
  behavior — WhatsApp only accepts the approved template in that situation.
- **Intermittent `channel_unavailable`**: the inbox is dropping. Check the channel connection before
  resending in bulk, otherwise the resends fail for the same reason.
- **The customer received it twice**: check whether an automation **and** a Follow-up sequence both
  cover the same stage, or whether someone used **force** on a resend.
- **The rate shows "—"**: no recovery card was recorded as sent in the filtered period. Widen the
  period or check the reasons list.
- **The page does not appear**: the `commerce_recovery` feature is off on the account, or your user
  is neither an administrator nor an agent on it.

## See also

- [E-commerce lifecycle: Kiwify/Hotmart/Nuvemshop/Shopify webhooks](/hc/ajuda/articles/catalog-commerce-commerce-lifecycle-en)
- [Catalog & Commerce overview](/hc/ajuda/articles/catalog-commerce-overview-en)
- [Send a product and receive orders in the conversation](/hc/ajuda/articles/catalog-commerce-enviar-produto-pedido-na-conversa-en)