company logo

Central de ajuda

Acessar Zouti
SiteTermos de UsoPolítica de Penalidades
Todas as coleçõesQuero integrar e automatizarComo configurar Webhook

Como configurar Webhook

Um Webhook é essencial para integrar sistemas em tempo real, permitindo que eventos sejam acionados automaticamente e comunicados entre plataformas, garantindo agilidade e precisão nos processos.

Qual a função do Webhook?

Um Webhook é uma forma de a Zouti enviar notificações automáticas em tempo real para um sistema externo sempre que algo acontece na sua conta — uma venda, um pagamento, uma assinatura, um carrinho abandonado, etc. Em vez de você consultar a Zouti manualmente, a Zouti faz uma requisição HTTP POST para a URL que você configurar, com os dados do evento no corpo. Serve para integrar a Zouti com CRMs, ERPs, áreas de membros, ferramentas de automação e qualquer sistema próprio

Como configurar (passo a passo):

1. No painel, acesse o menu Integrações

2. Localize o card Webhooks (categoria "Plataforma externa") e clique em Acessar

3. Clique em Criar Webhook

4. Preencha os campos:

- Nome do Webhook — um nome para você identificar a integração

- URL — o endereço de destino. O prefixo https:// é adicionado automaticamente

(somente HTTPS é aceito)

- Seleção de produtos (opcional) — se nenhum produto for selecionado, o webhook

dispara para todos os produtos da conta; se selecionar produtos específicos, só

dispara para eles

- Seleção de eventos — marque quais eventos devem disparar o webhook

5. Clique em Criar Webhook para finalizar

6. Gerencie os webhooks pela listagem (nome, URL, status Ativo/Inativo, data de criação,

editar, testar e excluir)


Catálogo completo de eventos (26)

Os eventos abaixo são exatamente os que aparecem para o cliente na tela de criação/edição

do webhook, na ordem em que são exibidos. O "Evento técnico" é o valor enviado no

cabeçalho x-zouti-event-type e que identifica o evento na integração.

Pedidos:

Evento (como aparece no painel)

Evento técnico

Objeto enviado

Cliente iniciou o checkout mas não concluiu o pagamento

Carrinho abandonado

ABANDONED_CART_CREATED

AbandonedCart

Cliente iniciou o checkout mas não concluiu o pagamento

Pedido criado

ORDER_CREATED

Order

Um novo pedido é registrado

Pedido atualizado

ORDER_UPDATED

Order

Um pedido existente sofre alteração

Pedido pago

ORDER_PAID

Order

O pagamento do pedido é confirmado

Pedido estornado

ORDER_REFUNDED

Order

O pedido é reembolsado (status REFUNDED)

Pedido em chargeback

ORDER_DISPUTED

Order

Há uma contestação/chargeback (status DISPUTED)

Pedido cancelado

ORDER_CANCELED

Order

O pedido é cancelado

Pedido não pago

ORDER_UNPAID

Order

O pedido não foi pago (ex.: PIX/boleto expirado)

Pagamentos (PIX e Boleto):

Evento (como aparece no painel)

Evento técnico

Objeto enviado

Cliente iniciou o checkout mas não concluiu o pagamento

Pix criado

PIX_CREATED

Order

Um pagamento via PIX é gerado (aguardando pagamento) — inclui payment.pix.code

Boleto criado

BOLETO_CREATED

Order

Um boleto é gerado (aguardando pagamento) — inclui payment.boleto.number

Assinaturas:

Evento (como aparece no painel)

Evento técnico

Objeto enviado

Cliente iniciou o checkout mas não concluiu o pagamento

Assinatura criada

SUBSCRIPTION_CREATED

Subscription

Nova assinatura registrada (status INCOMPLETE)

Assinatura ativada

UBSCRIPTION_ACTIVATED

Subscription

Assinatura ativada (status ACTIVE)

Assinatura renovada

SUBSCRIPTION_RENEWED

Subscription

Assinatura renovada com sucesso

Assinatura cancelada

SUBSCRIPTION_CANCELED

Subscription

Assinatura cancelada (status CANCELED)

Assinatura atrasada

SUBSCRIPTION_LATE_RENEWAL_WARNING

Subscription

A renovação da assinatura está atrasada

Parcelamento Inteligente:

Evento (como aparece no painel)

Evento técnico

Objeto enviado

Cliente iniciou o checkout mas não concluiu o pagamento

Parcelamento inteligente pago

SMART_INSTALLMENT_PAID

SmartInstallment

Uma parcela do parcelamento inteligente é paga

Parcelamento inteligente atrasado

SMART_INSTALLMENT_LATE_RENEWAL

SmartInstallment

Uma parcela está atrasada (cobrança falhou)

Cobranças:

Evento (como aparece no painel)

Evento técnico

Objeto enviado

Cliente iniciou o checkout mas não concluiu o pagamento

Cobrança Pendente

PAYMENT_PENDING

Payment

Uma cobrança está aguardando pagamento

Cobrança Aprovada

PAYMENT_PAID

Payment

Uma cobrança é confirmada

Cobrança Reembolsada

PAYMENT_REFUNDED

Payment

Uma cobrança é reembolsada

Cobrança Contestada

PAYMENT_DISPUTED

Payment

Uma cobrança é contestada pelo cliente

Cobrança Expirada

PAYMENT_UNPAID

Payment

Uma cobrança expira sem pagamento

Cobrança Recusada

PAYMENT_DECLINED

Payment

Uma cobrança é recusada

Solicitações de reembolso?

Evento (como aparece no painel)

Evento técnico

Objeto enviado

Cliente iniciou o checkout mas não concluiu o pagamento

Solicitação de reembolso criada

REFUND_REQUEST_CREATED

RefundRequest

O cliente solicita um reembolso

Solicitação de reembolso aprovada

REFUND_REQUEST_APPROVED

RefundRequest

A solicitação de reembolso é aprovada

Solicitação de reembolso recusada

REFUND_REQUEST_REFUSED

RefundRequest

A solicitação de reembolso é recusada

Observação de status

  • Order.status: AWAITING_PAYMENT, PAID, UNPAID, REFUNDED, DISPUTED, CANCELED

  • Payment.status: PENDING, PAID, REFUNDED, PARTIALLY_REFUNDED, DISPUTED, UNPAID, DECLINED

  • Subscription.status: INCOMPLETE, ACTIVE, CANCELED, TRIAL, PAST_DUE

  • Métodos de pagamento: Cartão de crédito CREDIT_CARD), PIX PIX), Boleto BOLETO)

  • RefundRequest.status: PENDING, APPROVED, REFUSED

Diferença entre ORDER_* e PAYMENT_*

o Pedido Order) é a compra do ponto de vista comercial (itens, cliente, valor total); a Cobrança Payment) é a transação financeira em si. Um mesmo pedido pode ter mais de uma cobrança (ex.: pagamento dividido / split payment, ou uma nova tentativa de cobrança). Use os eventos PAYMENT_* quando precisar acompanhar o fluxo financeiro transação a transação; use ORDER_* quando o foco for o pedido/venda


Carrinho abandonado — como funciona

Um carrinho abandonado é gerado quando um cliente inicia o checkout, não conclui o

pagamento e a sessão de checkout expira. Nesse momento a Zouti dispara o evento

ABANDONED_CART_CREATED (objeto AbandonedCart).

Quando o evento é (e não é) disparado:

O carrinho abandonado só é criado — e o webhook só dispara — se:

  • A sessão de checkout expirou sem o pagamento ter sido concluído; e

  • O cliente informou um e-mail durante o checkout.

O evento NÃO é disparado quando:

  • O checkout não capturou o e-mail do cliente (sem e-mail não há como criar o carrinho/remarketing);

  • Já existe um pedido pago para o mesmo e-mail + oferta nas últimas 24 horas (o cliente já comprou);

  • Já existe um carrinho abandonado ativo para o mesmo e-mail + oferta (evita duplicatas).


Etapas do carrinho( Step):

Step

Significado

PERSONAL_DATA

Cliente preencheu apenas os dados pessoais

SHIPPING

Cliente avançou até a etapa de frete/entrega (produto físico)

PAYMENT

Cliente chegou à etapa de pagamento

AWAITING_PAYMENT

Cliente gerou um PIX e não pagou (aguardando pagamento)

REFUSED

O pagamento do cliente foi recusado

Observação técnica: na busca/filtragem, PAYMENT e AWAITING_PAYMENT são tratados como o mesmo grupo de "etapa de pagamento".

O payload completo de exemplo do objeto AbandonedCart está no apêndice técnico.


Como testar um webhook

A plataforma tem a função Testar Webhook, que envia um disparo de exemplo sem criar dados reais:

1. Na listagem de webhooks, clique em Testar Webhook

2. Escolha qual webhook deseja testar

3. Escolha o evento a simular (só aparecem os eventos configurados naquele webhook)

4. Clique em Enviar webhook teste. O disparo de teste é assinado com o mesmo segredo do webhook, ou seja, seu servidor valida exatamente como uma entrega real.

O disparo de teste é assinado com o mesmo segredo do webhook, ou seja, seu servidor valida exatamente como uma entrega real. Cada tipo de evento envia um exemplo do objeto correspondente (Pedido, Cobrança, Assinatura, etc.).


Inativação automática e reativação

  • Um webhook é inativado automaticamente após 10 falhas consecutivas de conexão.

  • O motivo fica registrado como CONSECUTIVE_FAILURES.

  • Quando isso acontece, um ícone de alerta aparece na listagem com a explicação.

  • O cliente pode reativar manualmente o webhook depois de corrigir o destino.

  • Webhooks também podem ser ativados/inativados manualmente pelo switch da listagem.

  • Webhook inativado não recebe disparos.


Política de retentativa (retry)

Apenas respostas HTTP 2xx são consideradas sucesso.

  • O servidor de destino deve responder em até 30 segundos (timeout).

  • Em caso de falha, a Zouti retenta automaticamente com backoff exponencial(intervalo crescente entre tentativas, com no máximo ~12h entre uma e outra).

  • As retentativas continuam por até 4 dias após o evento original. Depois disso a entrega é descartada.


Apêndice técnico — para desenvolvedores

Cabeçalhos enviados em cada disparo:

content-type: application/json
user-agent: Zouti-Webhook/1.0
x-zouti-webhook-id: web_xxx
x-zouti-webhook-delivery-id: webd_xxx
x-zouti-object-id: ord_xxx        (ID do objeto — pedido, assinatura, etc.)
x-zouti-object-name: Order        (tipo do objeto: Order | Subscription | AbandonedCart | Payment | SmartInstallment | RefundRequest)
x-zouti-event-id: evt_xxx
x-zouti-event-type: ORDER_PAID    (o evento técnico da tabela acima)
x-zouti-signature: t=1717000000000,v1=<hmac_sha256>

Nos eventos de Cobrança PAYMENT_*), x-zouti-object-name é Payment e x-zouti-object-id é o ID da cobrança pmt_xxx).

Verificação de assinatura:

Cada disparo vem assinado por HMAC-SHA256 usando o segredo do webhook. O formato é:

[
t=<timestamp_em_ms>,v1=<hash_hex>


Onde `v1` é o HMAC-SHA256 do **corpo bruto** (raw body) da requisição usando o segredo
como chave. Exemplo de verificação em Node.js:

 javascript
const crypto = require('crypto');

function verifyWebhookSignature(rawBody, signatureHeader, secret) {
  const [tPart, v1Part] = signatureHeader.split(',');
  const receivedHash = v1Part.split('=')[1];

  const expectedHash = crypto
    .createHmac('sha256', secret)
    .update(rawBody)
    .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(receivedHash),
    Buffer.from(expectedHash),
  );
}

> Dica: valide sempre o corpo bruto (antes de qualquer parse/JSON),caso contrário o hash não confere. O segredo pode ser rotacionado pelo painel; após arotação há um período de carência em que a assinatura antiga ainda é aceita.


Valores monetários:

Todos os valores vêm em centavos (ex.: amount: 9790) e também com a versão em reais

no campo correspondente *_in_brl (ex.: amount_in_brl: 97.90).

Exceção — objeto Cobrança Payment): neste objeto os valores do nível raiz amount, fee, interest_amount, interest_transfer_amount, discount_amount, amount_paid, amount_refunded) vêm **apenas em centavos**, sem o companheiro *_in_brl. A versão em reais aparece somente **dentro de line_items[].amount_in_brl**. O objeto Payment também **não** traz um campo net_amount no nível raiz.


Exemplos de payload (corpo enviado):

Estes são exatamente os payloads usados na função "Testar Webhook" — representam o formato real de cada tipo de objeto. Campos podem variar conforme o método de pagamento e o tipo de produto.

Pedido Order)** — eventos ORDER_*, PIX_CREATED, BOLETO_CREATED:

```json
{
  "id": "ord_eloz1kotrd7jtghi5oa3vl",
  "account_id": "acc_grlw5o8dp8rv2drenaio84",
  "status": "PAID",
  "payment_type": "UNIQUE",
  "customer_id": "cus_8h2k1l0trd7jtghi5oa3vl",
  "provider": "ZOUTI",
  "order_session_id": "os_3n9x1k0trd7jtghi5oa3vl",
  "checkout_id": "chk_5k2j1h0trd7jtghi5oa3vl",
  "is_split_payment": false,
  "amount_subtotal": 11970,
  "amount_subtotal_in_brl": 119.7,
  "amount_total": 11970,
  "amount_total_in_brl": 119.7,
  "currency": "BRL",
  "paid_at": "2024-12-16T19:50:17.044Z",
  "items": [
    {
      "amount": 11970,
      "amount_in_brl": 119.7,
      "full_amount": 11970,
      "full_amount_in_brl": 119.7,
      "description": "Curso completo de Desenvolvimento Web Full Stack",
      "image_url": "https://zouti-core-media-public.s3.amazonaws.com/media/accounts/acc_grlw5o8dp8rv2drenaio84/products/images/icon.jpg",
      "name": "Curso de Desenvolvimento Web",
      "product_id": "prod_eji9ptlqrlqk35etn3zfyi",
      "quantity": 1,
      "type": "SKU"
    }
  ],
  "customer": {
    "document": "12345678909",
    "email": "[email protected]",
    "name": "Maria Silva",
    "phone": "5511987654321"
  },
  "payment": {
    "method": "CREDIT_CARD",
    "status": "PAID",
    "amount": 11970,
    "amount_in_brl": 119.7,
    "fee": 390,
    "fee_in_brl": 3.9,
    "net_amount": 11100,
    "net_amount_in_brl": 111.0,
    "interest_amount": 970,
    "interest_amount_in_brl": 9.7,
    "interest_transfer_amount": 480,
    "interest_transfer_amount_in_brl": 4.8,
    "discount_amount": 500,
    "discount_amount_in_brl": 5.0,
    "amount_refunded": 0,
    "installments": 12
  },
  "utm_data": {
    "utm_campaign": "black_friday_2024",
    "utm_source": "google",
    "utm_medium": "cpc",
    "utm_content": "banner_promocional",
    "utm_term": "curso programacao"
  },
  "shipping_address": {
    "id": "adr_2n8x1k0trd7jtghi5oa3vl",
    "line1": "Av. Paulista, 1578",
    "line2": "Apto 502",
    "line3": "Bloco B",
    "neighborhood": "Bela Vista",
    "city": "São Paulo",
    "state": "SP",
    "country": "Brasil",
    "postal_code": "01310200"
  },
  "created_at": "2024-12-16T19:50:17.044Z",
  "updated_at": "2024-12-16T19:50:17.044Z"
}

Detalhes do objeto Order:

is_split_payment está sempre presente; quando true, o objeto também traz

split_payments[] com o rateio.

Em *PIX_CREATED** o payment traz "pix": { "code": "00020126..." } e o pedido fica com status: "AWAITING_PAYMENT". Em *BOLETO_CREATED**, traz "boleto": { "number": "34191..." }.

shipping_address só vem em produto físico.

O objeto customer do pedido traz name, email, phone e document (**não** traz instagram).


Cobrança Payment)** — eventos PAYMENT_PENDING, PAYMENT_PAID, PAYMENT_REFUNDED, PAYMENT_DISPUTED, PAYMENT_UNPAID, PAYMENT_DECLINED:


```json
{
  "id": "pmt_eloz1kotrd7jtghi5oa3vl",
  "status": "PAID",
  "method": "CREDIT_CARD",
  "decline_reason": "Não autorizado pelo emissor",
  "failure_reason": "GENERIC_DECLINE",
  "installments": 12,
  "order_id": "ord_eloz1kotrd7jtghi5oa3vl",
  "subscription_id": "sub_2n8x1k0trd7jtghi5oa3vl",
  "smart_installment_id": "smi_9f3x1k0trd7jtghi5oa3vl",
  "account_id": "acc_grlw5o8dp8rv2drenaio84",
  "interest_transfer_amount": 480,
  "amount": 11970,
  "interest_amount": 970,
  "fee": 390,
  "discount_amount": 500,
  "amount_paid": 11970,
  "amount_refunded": 11970,
  "refund_id": "ref_7k2j1h0trd7jtghi5oa3vl",
  "metadata": {
    "invoices": [
      {
        "invoice_id": "inv_a1b2c3d4",
        "credential_type": "ENOTAS",
        "credential_id": "cred_xyz789"
      }
    ]
  },
  "customer": {
    "name": "Maria Silva",
    "email": "[email protected]",
    "document": "12345678909",
    "phone": "5511987654321"
  },
  "splits": [
    {
      "id": "spl_1a2b3c4d",
      "percentage": "20.00",
      "amount": 2394,
      "amount_refunded": 2394,
      "invoice_mode": "PARTNER",
      "invited_account_id": "acc_partner7k2j1h0trd7jt"
    }
  ],
  "shipping_address": {
    "line1": "Av. Paulista, 1578",
    "line2": "Apto 502",
    "line3": "Bloco B",
    "neighborhood": "Bela Vista",
    "city": "São Paulo",
    "state": "SP",
    "country": "Brasil",
    "postal_code": "01310200"
  },
  "line_items": [
    {
      "name": "Curso de Desenvolvimento Web",
      "description": "Curso completo de Desenvolvimento Web Full Stack",
      "type": "SKU",
      "quantity": 1,
      "product_id": "prod_eji9ptlqrlqk35etn3zfyi",
      "amount": 11970,
      "amount_in_brl": 119.7,
      "image": "https://zouti-core-media-public.s3.amazonaws.com/media/.../icon.jpg"
    }
  ],
  "created_at": "2024-12-16T19:50:17.044Z",
  "updated_at": "2024-12-16T19:50:17.044Z",
  "paid_at": "2024-12-16T19:50:17.044Z",
  "unpaid_at": "2024-12-16T20:10:00.000Z",
  "refunded_at": "2024-12-17T10:00:00.000Z"
}

O objeto Payment mantém a mesma estrutura em todos os eventos PAYMENT_*; muda o status e alguns campos de data/valor:

Evento

status

Campos que mudam

PAYMENT_PENDING

PENDING

paid_at: null (PIX/boleto ainda aguardando pagamento)

PAYMENT_PAID

PAID

paid_at preenchido; amount_paid = valor pago

PAYMENT_DECLINED

DECLINED

inclui decline_reason (motivo mapeado do adquirente) e, quando houver, failure_reason

PAYMENT_UNPAID |

UNPAID

unpaid_at preenchido (PIX/boleto expirado)

PAYMENT_REFUNDED

REFUNDED ou PARTIALLY_REFUNDED |

refunded_at preenchido; amount_refunded > 0 |

PAYMENT_DISPUTED

DISPUTED

chargeback aberto para a cobrança

Detalhes do objeto Payment:

O exemplo acima está com todos os campos preenchidos. Na prática, os campos condicionais só aparecem no contexto certo: decline_reasonfailure_reason em recusa; subscription_id em cobrança de assinatura; smart_installment_id em parcela de parcelamento inteligente; refund_id e refunded_at em estorno; paid_atunpaid_at conforme o pagamento foi confirmado ou expirou.

splits traz o rateio de coprodução quando existe.

shipping_address só vem em produto físico.

Os valores são em centavos; a versão em reais aparece só em line_items[].amount_in_brl (veja "Valores monetários" acima).

O objeto Payment não expõe dados internos de gateway/roteamento (ex.: adquirente, subconta, dados do cartão).


Assinatura Subscription)** — eventos SUBSCRIPTION_*:


```json
{
  "id": "sub_2n8x1k0trd7jtghi5oa3vl",
  "account_id": "acc_grlw5o8dp8rv2drenaio84",
  "order_id": "ord_eloz1kotrd7jtghi5oa3vl",
  "status": "ACTIVE",
  "customer": {
    "id": "cus_8h2k1l0trd7jtghi5oa3vl",
    "name": "João Silva",
    "email": "[email protected]",
    "document": "11122233344",
    "phone": "5511988776655"
  },
  "plan": {
    "id": "prod_offer_plan_9f3x1k0trd7jt",
    "name": "Anual",
    "amount": 119700,
    "currency": "BRL",
    "interval": "YEARLY",
    "max_cycles": 12
  },
  "payment_method": "CREDIT_CARD",
  "current_period_start": "2025-05-01T00:00:00.000Z",
  "current_period_end": "2026-05-01T00:00:00.000Z",
  "next_payment_date": "2026-05-01T00:00:00.000Z",
  "installments": 12,
  "line_items": [
    {
      "name": "Assinatura Anual",
      "description": "Plano anual do curso",
      "type": "SKU",
      "quantity": 1,
      "product_id": "prod_eji9ptlqrlqk35etn3zfyi",
      "amount": 119700,
      "amount_in_brl": 1197.0
    }
  ],
  "cancel_at_period_end": false,
  "billing_cycle_count": 1,
  "created_at": "2025-05-01T00:00:00.000Z",
  "updated_at": "2025-05-01T00:00:00.000Z"
}

Detalhes do objeto Subscription:

line_items[] está sempre presente.

O plan traz id, name, amount, currency, interval (e, quando aplicável, max_cyclestrial). Não há amount_in_brl dentro de plan. O plan.id tem o prefixo prod_offer_plan_....

current_period_end, next_payment_date, canceled_at e installments só aparecem quando fazem sentido para o status da assinatura.


Carrinho abandonado AbandonedCart)** — evento ABANDONED_CART_CREATED:

```json
{
  "id": "ab_c_5k2j1h0trd7jtghi5oa3vl",
  "step": "PAYMENT",
  "total_amount": 14990,
  "total_amount_in_brl": 149.9,
  "order_session_id": "os_3n9x1k0trd7jtghi5oa3vl",
  "url": "https://pay.zouti.com.br/infoproduct_cart_token/ab_c_5k2j1h0trd7jtghi5oa3vl",
  "ip_address": "179.108.44.10",
  "currency": "BRL",
  "customer": {
    "name": "Lucas Oliveira",
    "email": "[email protected]",
    "document": "98765432100",
    "phone": "5511999887766",
    "instagram": "lucas.oliveira"
  },
  "metadata": {
    "theme": "ZOUTI",
    "payment_method": "CREDIT_CARD",
    "checkout_type": "INFOPRODUCT"
  },
  "items": [
    {
      "type": "SKU",
      "product_id": "prod_eji9ptlqrlqk35etn3zfyi",
      "variant_id": "var_1a2b3c4d5e",
      "name": "Curso de Desenvolvimento Web",
      "description": "Curso completo de Desenvolvimento Web",
      "amount": 14990,
      "amount_in_brl": 149.9,
      "quantity": 1,
      "image_url": "https://zouti-core-media-public.s3.amazonaws.com/media/.../icon.jpg"
    }
  ],
  "utm_data": {
    "source": "facebook",
    "medium": "social",
    "campaign": "remarketing_junho",
    "content": "story_01",
    "term": "curso web"
  },
  "account_id": "acc_grlw5o8dp8rv2drenaio84",
  "checkout_id": "chk_5k2j1h0trd7jtghi5oa3vl",
  "created_at": "2025-05-12T19:30:41.459Z",
  "updated_at": "2025-05-12T19:30:41.459Z"
}

Detalhes do objeto AbandonedCart:

O id tem o prefixo ab_c_....

Atenção às chaves de UTM: neste objeto o utm_data usa source, medium,

campaign, content, term (**sem** o prefixo utm_). Já no objeto Order as chaves são utm_source, utm_medium, etc.

ip_address, checkout_id e utm_data só aparecem quando disponíveis.

metadata.payment_method só existe se o cliente chegou a escolher um método.

O step indica em que etapa o cliente parou: PERSONAL_DATA, SHIPPING, PAYMENT, AWAITING_PAYMENT ou REFUSED.


Parcelamento inteligente SmartInstallment)** — eventos SMART_INSTALLMENT_*:

```json
{
  "id": "smi_9f3x1k0trd7jtghi5oa3vl",
  "status": "PAID",
  "method": "CREDIT_CARD",
  "order_id": "ord_eloz1kotrd7jtghi5oa3vl",
  "account_id": "acc_grlw5o8dp8rv2drenaio84",
  "order_session_id": "os_3n9x1k0trd7jtghi5oa3vl",
  "amount": 9975,
  "amount_in_brl": 99.75,
  "installment_number": 1,
  "total_installments": 12,
  "payment_id": "pmt_eloz1kotrd7jtghi5oa3vl",
  "due_date": "2025-01-15T00:00:00.000Z",
  "currency": "BRL",
  "interest_amount": 0,
  "interest_amount_in_brl": 0,
  "discount_amount": 0,
  "discount_amount_in_brl": 0,
  "paid_at": "2025-01-10T10:30:00.000Z",
  "card": {
    "brand": "VISA",
    "first_digits": "411111",
    "last_digits": "1111",
    "holder_name": "João Silva"
  },
  "customer": {
    "id": "cus_8h2k1l0trd7jtghi5oa3vl",
    "name": "João Silva",
    "email": "[email protected]",
    "document": "11122233344",
    "phone": "5511988776655"
  },
  "products": [
    {
      "name": "Curso de Desenvolvimento Web",
      "amount": 9975,
      "amount_in_brl": 99.75,
      "quantity": 1,
      "product_id": "prod_eji9ptlqrlqk35etn3zfyi"
    }
  ],
  "created_at": "2025-01-01T00:00:00.000Z",
  "updated_at": "2025-01-01T00:00:00.000Z"
}

Detalhes do objeto SmartInstallment:

O id tem o prefixo smi_....

products[] está sempre presente.

card inclui first_digits além de last_digits; só aparece em cartão. Para outros métodos podem vir pixboleto.

paid_at fica vazio no evento SMART_INSTALLMENT_LATE_RENEWAL.


Solicitação de reembolso RefundRequest)** — eventos REFUND_REQUEST_*:

```json
{
  "id": "rrq_5k2j1h0trd7jtghi5oa3vl",
  "account_id": "acc_grlw5o8dp8rv2drenaio84",
  "order_id": "ord_eloz1kotrd7jtghi5oa3vl",
  "payment_id": "pmt_eloz1kotrd7jtghi5oa3vl",
  "status": "APPROVED",
  "reason": "Não recebi o produto",
  "amount": 9790,
  "accepted_at": "2025-05-01T01:00:00.000Z",
  "created_at": "2025-05-01T00:00:00.000Z",
  "updated_at": "2025-05-01T01:00:00.000Z",
  "customer": {
    "id": "cus_8h2k1l0trd7jtghi5oa3vl",
    "name": "Maria Silva",
    "email": "[email protected]",
    "document": "12345678909",
    "phone": "5511987654321",
    "timezone": "America/Sao_Paulo"
  },
  "order": {
    "id": "ord_eloz1kotrd7jtghi5oa3vl",
    "status": "PAID",
    "amount_subtotal": 9790,
    "amount_total": 9790,
    "currency": "BRL",
    "paid_at": "2025-04-20T14:00:00.000Z",
    "created_at": "2025-04-20T13:55:00.000Z",
    "updated_at": "2025-04-20T14:00:00.000Z"
  },
  "payment": {
    "id": "pmt_eloz1kotrd7jtghi5oa3vl",
    "status": "PAID",
    "method": "CREDIT_CARD",
    "amount": 9790,
    "amount_paid": 9790,
    "amount_refunded": 0,
    "interest_amount": 0,
    "fee": 290,
    "installments": 1,
    "paid_at": "2025-04-20T14:00:00.000Z"
  },
  "card": {
    "id": "card_5k2j1h0trd7jtghi5oa3vl",
    "brand": "VISA",
    "last_digits": "1111",
    "holder_name": "Maria Silva",
    "type": "CREDIT",
    "category": "STANDARD",
    "country": "BR"
  },
  "products": [
    {
      "product_id": "prod_eji9ptlqrlqk35etn3zfyi",
      "name": "Curso de Desenvolvimento Web",
      "description": "Curso completo de Desenvolvimento Web Full Stack",
      "quantity": 1,
      "unit_price": 9790,
      "sub_total": 9790,
      "image_url": "https://zouti-core-media-public.s3.amazonaws.com/media/.../icon.jpg"
    }
  ]
}

Detalhes do objeto RefundRequest:

O id tem o prefixo rrq_....

products[] está sempre presente.

accepted_at aparece em REFUND_REQUEST_APPROVED; rejection_reason e failure_reason em REFUND_REQUEST_REFUSED. Campos sem valor são omitidos do corpo.

cardpixboleto aparecem conforme o método de pagamento original.


Regras de negócio

  • A URL do webhook deve usar HTTPS (o https:// é adicionado automaticamente).

  • Se nenhum produto for selecionado, o webhook vale para todos os produtos da conta.

  • Cada webhook pode ter vários eventos associados ao mesmo tempo.

  • É possível ter mais de um webhook para a mesma URL, cada um com eventos diferentes.

  • Apenas respostas HTTP 2xx são consideradas sucesso; o destino deve responder em até 30 segundos.

  • Em caso de falha de conexão/timeout/4xx, há retentativa automática com backoff exponencial.

  • Após 10 falhas consecutivas de entrega, o webhook é inativado automaticamente(motivo CONSECUTIVE_FAILURES) e precisa ser reativado manualmente.

  • O cliente pode ativar/inativar manualmente pelo switch da listagem; webhook inativado não recebe disparos


Limitações conhecidas:

  • Somente URLs com protocolo HTTPS são suportadas.

  • Não há reenvio manual de disparos que falharam (apenas a política de retentativa interna).

  • Webhooks inativados por falhas consecutivas precisam ser reativados manualmente.

  • Não é possível visualizar o histórico completo de disparos de um webhook pela interface.


FAQ

Posso criar mais de um webhook para a mesma URL? Sim, cada um com eventos diferentes.

O que acontece se meu servidor estiver fora do ar? A Zouti retenta por até 4 dias. Após 10 falhas consecutivas, o webhook é inativado automaticamente e precisa ser reativado manualmente.

Como sei se está funcionando? Use a função **Testar Webhook** para enviar um disparo de teste.

Qual a diferença entre os eventos de Pedido e de Cobrança? O Pedido Order) representa a venda; a Cobrança Payment) representa a transação financeira. Um pedido pode ter mais de uma cobrança (ex.: pagamento dividido). Use PAYMENT_* para acompanhar o fluxo financeiro transação a transação.

O https:// é obrigatório? Sim — e é adicionado automaticamente, não precisa digitar.

Esta resposta foi útil?
😞
😐
😁