> ## Documentation Index
> Fetch the complete documentation index at: https://docs.goatpay.com.br/llms.txt
> Use this file to discover all available pages before exploring further.

# Recuperador de vendas

> Tutorial: buscar cobranças pendentes, extrair dados do cliente do link de pagamento e montar fluxos de recuperação

Tutorial para montar um **recuperador de vendas** (carrinho abandonado, PIX não pago, boleto vencido) usando a API pública v1. Você vai listar cobranças pendentes, pegar nome, e-mail e telefone do comprador e disparar follow-up no seu CRM, WhatsApp ou e-mail transacional.

## Visão geral

```mermaid theme={null}
sequenceDiagram
  participant Job as Seu job (cron)
  participant GoatPay
  participant CRM as CRM / WhatsApp

  Job->>GoatPay: GET /account/transactions?status=PENDING
  GoatPay-->>Job: items com payer (email, phone, name)
  Job->>Job: Filtra quem tem contato e ainda não foi recuperado
  Job->>CRM: Dispara mensagem personalizada
  Note over Job,CRM: Webhook payment.paid remove da fila
```

O extrato da conta expõe o objeto `payer` com os dados preenchidos no checkout do **link de pagamento** — os mesmos que você vê no extrato da dashboard.

| Campo em `payer` | Uso na recuperação             |
| ---------------- | ------------------------------ |
| `name`           | Personalizar mensagem          |
| `email`          | E-mail transacional            |
| `phone`          | WhatsApp / SMS                 |
| `document`       | Identificar cliente recorrente |

<Note>
  Após o pagamento PIX confirmado, `name` e `document` passam a refletir o comprovante bancário. `email` e `phone` continuam vindo do checkout do link quando disponíveis.
</Note>

## Permissões necessárias

| Permissão              | Para quê                                                  |
| ---------------------- | --------------------------------------------------------- |
| `account/transactions` | Listar cobranças e ler `payer`                            |
| `webhooks/create`      | Opcional — parar recuperação quando `payment.paid` chegar |

Chave com preset **read** já inclui `account/transactions`. Detalhes: [Permissões da API key](/pages/guides/api-permissions).

## 1. Listar cobranças candidatas à recuperação

O endpoint principal é o [extrato da conta](/api-reference/endpoint/account/transactions). Filtre entradas pendentes criadas nas últimas horas:

```bash theme={null}
curl -G 'https://api.goatpay.com.br/v1/account/transactions' \
  -H 'X-API-Key: gp_live_SUA_CHAVE' \
  --data-urlencode 'status=PENDING' \
  --data-urlencode 'type=entrada' \
  --data-urlencode 'method=PIX' \
  --data-urlencode 'page=1' \
  --data-urlencode 'pageSize=50' \
  --data-urlencode 'dateFrom=2026-06-24T00:00:00.000Z'
```

### Filtros úteis

| Query                              | Recuperação de…                 |
| ---------------------------------- | ------------------------------- |
| `status=PENDING`                   | PIX/boleto ainda não pagos      |
| `status=CANCELED` + janela curta   | QR PIX expirado (reenviar link) |
| `type=entrada`                     | Só recebimentos (ignora saques) |
| `method=PIX` / `Boleto` / `Cartão` | Canal específico                |
| `externalReference=pedido-42`      | Pedido pontual no seu sistema   |
| `merchantSubaccountId=clx_sub`     | Extrato de uma subconta         |

Paginação: incremente `page` até `page > pages`. Máximo `pageSize=100`.

## 2. Ler os dados do cliente em cada item

Exemplo de item retornado (campos relevantes):

```json theme={null}
{
  "id": "clx_pix_in",
  "type": "PIX_IN",
  "status": "PENDING",
  "amount": 97.0,
  "description": "Curso Avançado",
  "externalReference": "pedido-1042",
  "qrcodeUrl": "https://pay.goatpay.com.br/p/clx_pix_in",
  "expiresAt": "2026-06-24T23:59:59.000Z",
  "createdAt": "2026-06-24T18:00:00.000Z",
  "payer": {
    "name": "Maria Souza",
    "document": "52998224725",
    "email": "maria@email.com",
    "phone": "11999998888"
  }
}
```

Regras práticas:

* **Sem `payer` ou sem contato** — cobrança criada direto na API sem checkout de link; não dá para recuperar por e-mail/WhatsApp via extrato.
* **`payer.email` ou `payer.phone`** — suficiente para disparar follow-up.
* **`externalReference`** — chave para cruzar com pedido no seu banco.
* **`id`** — chave única da transação GoatPay (use para deduplicar).
* **`qrcodeUrl`** — link do checkout para reenviar na mensagem.

[Documentação completa do extrato](/api-reference/endpoint/account/transactions)

## 3. Script de exemplo (Node.js)

Job agendado (cron a cada 15–30 min) que monta a fila de recuperação:

```typescript theme={null}
const API_KEY = process.env.GOATPAY_API_KEY!;
const BASE = "https://api.goatpay.com.br/v1";

type Tx = {
  id: string;
  status: string;
  amount: number;
  description: string | null;
  externalReference: string | null;
  qrcodeUrl?: string;
  expiresAt?: string | null;
  createdAt: string;
  payer?: {
    name?: string | null;
    document?: string | null;
    email?: string | null;
    phone?: string | null;
  };
};

async function listPendingPix(sinceIso: string): Promise<Tx[]> {
  const items: Tx[] = [];
  let page = 1;

  while (true) {
    const qs = new URLSearchParams({
      status: "PENDING",
      type: "entrada",
      method: "PIX",
      page: String(page),
      pageSize: "100",
      dateFrom: sinceIso,
    });

    const res = await fetch(`${BASE}/account/transactions?${qs}`, {
      headers: { "X-API-Key": API_KEY },
    });
    const body = await res.json();
    if (!body.success) throw new Error(body.message);

    items.push(...body.data.items);
    if (page >= body.data.pages) break;
    page += 1;
  }

  return items;
}

function isRecoverable(tx: Tx): boolean {
  const email = tx.payer?.email?.trim();
  const phone = tx.payer?.phone?.trim();
  return Boolean(email || phone);
}

async function main() {
  const since = new Date(Date.now() - 48 * 60 * 60 * 1000).toISOString();
  const pending = await listPendingPix(since);

  for (const tx of pending.filter(isRecoverable)) {
    // Evite reenviar: consulte seu banco se já recuperou este tx.id
    const contact = tx.payer!.email?.trim() || tx.payer!.phone!.trim();
    console.log("Recuperar", {
      transactionId: tx.id,
      reference: tx.externalReference,
      contact,
      amount: tx.amount,
      checkoutUrl: tx.qrcodeUrl,
    });
    // await sendWhatsApp(...) ou await sendEmail(...)
  }
}

main().catch(console.error);
```

<Warning>
  Respeite o [rate limit](/api-reference/rate-limiting) (100 req/min). Prefira uma listagem paginada a cada 15–30 min em vez de polling contínuo.
</Warning>

## 4. Parar a recuperação quando pagar

### Opção A — Webhook (recomendado)

Cadastre `payment.paid` e `payment_link.paid`. Ao receber o evento, marque `transactionId` ou `externalReference` como pago no seu sistema e não envie mais mensagens.

```bash theme={null}
curl -X POST https://api.goatpay.com.br/v1/webhooks/create \
  -H "X-API-Key: gp_live_SUA_CHAVE" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://api.suaempresa.com/goatpay/webhook",
    "events": ["payment.paid", "payment.pix.expired", "payment_link.paid"]
  }'
```

| Evento                | Ação no recuperador                      |
| --------------------- | ---------------------------------------- |
| `payment.paid`        | Remover da fila / marcar como convertido |
| `payment_link.paid`   | Mesmo, para checkout via link            |
| `payment.pix.expired` | Oferecer novo link ou encerrar sequência |

[Webhooks na prática](/pages/guides/webhooks-pratica)

### Opção B — Reconsultar o extrato

No próximo ciclo do job, itens pagos saem do filtro `status=PENDING`. Mais simples, porém com atraso de até um ciclo do cron.

## 5. PIX expirado — segunda chance

QR expirado fica com `status=CANCELED`. Busque com janela recente:

```bash theme={null}
curl -G 'https://api.goatpay.com.br/v1/account/transactions' \
  -H 'X-API-Key: gp_live_SUA_CHAVE' \
  --data-urlencode 'status=CANCELED' \
  --data-urlencode 'type=entrada' \
  --data-urlencode 'method=PIX' \
  --data-urlencode 'dateFrom=2026-06-23T00:00:00.000Z'
```

Se `payer` ainda tiver contato, envie mensagem com um **novo link de pagamento** ([criar link](/api-reference/endpoint/payment-links/create) ou nova cobrança PIX) em vez do `qrcodeUrl` antigo.

## 6. Links de pagamento vs cobrança direta

| Origem da cobrança                      | Dados do cliente no extrato                                            |
| --------------------------------------- | ---------------------------------------------------------------------- |
| Link de pagamento (checkout GoatPay)    | `payer` com nome, documento, e-mail e telefone do formulário           |
| `POST /payment-pix/create` sem checkout | Geralmente sem `payer` até o PIX ser pago (só nome/doc do comprovante) |

Para recuperação rica em contato, **venda pelo link de pagamento** ou garanta que o checkout colete e-mail/telefone antes de gerar a cobrança.

Consulta pontual de sessão: [GET /payment-links/sessions/get](/api-reference/endpoint/payment-links/sessions-get).

## 7. Boas práticas

### Deduplicação

Guarde `transactionId` (campo `id`) ou `externalReference` com timestamp do último contato. Não envie a mesma sequência duas vezes.

### Janela de recuperação

| Tentativa | Sugestão                      |
| --------- | ----------------------------- |
| 1ª        | 30–60 min após `createdAt`    |
| 2ª        | 6–12 h (antes de `expiresAt`) |
| 3ª        | Após expiração, com novo link |

### LGPD e opt-out

Use os dados apenas para concluir a compra iniciada. Ofereça descadastro e não compartilhe contatos com terceiros sem base legal.

### Subcontas

Se cada lojista tem subconta, filtre `merchantSubaccountId` no extrato para recuperar só as vendas daquele parceiro.

## Erros frequentes

| Situação          | Causa                           | Solução                                        |
| ----------------- | ------------------------------- | ---------------------------------------------- |
| `payer` ausente   | Cobrança sem checkout de link   | Vender via link ou coletar contato no seu site |
| 403               | Chave sem permissão             | Adicione `account/transactions`                |
| Lista vazia       | Filtro de data/status restrito  | Amplie `dateFrom` ou remova `method`           |
| Contato duplicado | Mesmo cliente, várias cobranças | Agrupe por `payer.email` ou `payer.phone`      |

Mais ajuda: [Troubleshooting](/pages/guides/troubleshooting) · [Extrato — referência](/api-reference/endpoint/account/transactions)
