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

# Webhooks

> Receba notificações em tempo real sobre eventos da sua loja.

## O que são Webhooks?

Webhooks permitem que sua aplicação receba notificações automáticas quando eventos importantes acontecem na sua loja, como um pedido aprovado, reembolsado ou criado.

Ao invés de fazer polling na API para verificar mudanças, os webhooks enviam uma requisição HTTP POST para a URL que você configurar.

## Eventos disponíveis

| Evento | Descrição |
| - | - |
| `ORDER_CREATED` | Pedido criado (checkout iniciado) |
| `ORDER_UPDATED` | Detalhes do pedido foram atualizados (cliente, status, campos de checkout, escolhas do produto, etc.) |
| `ORDER_APPROVED` | Pedido aprovado/pago |
| `ORDER_REJECTED` | Pedido rejeitado |
| `ORDER_ABANDONED` | Pedido abandonado |
| `ORDER_REFUNDED` | Pedido reembolsado |
| `ORDER_CHARGEDBACK` | Pedido com chargeback |
| `PACKAGE_CREATED` | Produto criado |
| `PACKAGE_UPDATED` | Produto alterado |
| `PACKAGE_DELETED` | Produto deletado |
| `LICENSE_KEY_UPDATED` | License keys de um produto foram adicionadas ou removidas |
| `FEEDBACK_CREATED` | Nova avaliação recebida em um pedido |
| `CHAT_MESSAGE_CREATED` | O cliente enviou uma mensagem no chat do pedido |

<Note>
  O evento `ORDER_UPDATED` é disparado sempre que um administrador edita o pedido pelo painel. Caso a atualização também resulte em uma mudança de status para `APPROVED` ou `REFUNDED`, os eventos correspondentes (`ORDER_APPROVED` / `ORDER_REFUNDED`) também são disparados. Assine apenas os que fizerem sentido para o seu fluxo.
</Note>

## Formato do payload

Todos os webhooks seguem um formato padronizado:

```json theme={null}
{
  "id": "abc123xyz",
  "event": "ORDER_APPROVED",
  "date": "2026-02-20T15:30:00.000Z",
  "data": {
    // Conteúdo do evento (ex: dados do pedido)
  }
}
```

| Campo | Tipo | Descrição |
| - | - | - |
| `id` | `string` | Identificador único do evento |
| `event` | `string` | Tipo do evento |
| `date` | `string` | Data/hora do evento (ISO 8601) |
| `data` | `object` | Payload do evento |

O conteúdo de `data` varia conforme o grupo do evento. Veja abaixo o formato de cada um:

<AccordionGroup>
  <Accordion title="Eventos de pedido (ORDER_*)">
    Todos os eventos `ORDER_*` (`ORDER_CREATED`, `ORDER_UPDATED`, `ORDER_APPROVED`, `ORDER_REJECTED`, `ORDER_ABANDONED`, `ORDER_REFUNDED`, `ORDER_CHARGEDBACK`) compartilham o mesmo formato: o campo `data` contém os mesmos dados retornados pela [API de detalhes do pedido](/api-reference/endpoint/app/orders/get), incluindo pacotes, variáveis, entregas e outros detalhes.

    ```json theme={null}
    {
      "id": "abc123xyz",
      "event": "ORDER_APPROVED",
      "date": "2026-02-20T15:30:00.000Z",
      "data": {
        // Dados do pedido (mesmo objeto da API de detalhes do pedido)
      }
    }
    ```
  </Accordion>

  <Accordion title="PACKAGE_CREATED e PACKAGE_DELETED">
    Trazem o produto no campo `data.package`:

    ```json theme={null}
    {
      "id": "abc123xyz",
      "event": "PACKAGE_CREATED",
      "date": "2026-02-20T15:30:00.000Z",
      "data": {
        "package": {
          // Dados do produto
        }
      }
    }
    ```
  </Accordion>

  <Accordion title="PACKAGE_UPDATED">
    Traz o estado do produto **antes** e **depois** da edição, para que você compare o que mudou:

    ```json theme={null}
    {
      "id": "abc123xyz",
      "event": "PACKAGE_UPDATED",
      "date": "2026-02-20T15:30:00.000Z",
      "data": {
        "before": {
          // Estado do produto antes da edição
        },
        "after": {
          // Estado do produto após a edição
        }
      }
    }
    ```
  </Accordion>

  <Accordion title="LICENSE_KEY_UPDATED">
    Traz o produto afetado em `data.package` e as chaves que foram adicionadas e removidas naquela edição:

    ```json theme={null}
    {
      "id": "abc123xyz",
      "event": "LICENSE_KEY_UPDATED",
      "date": "2026-02-20T15:30:00.000Z",
      "data": {
        "package": {
          // Dados do produto
        },
        "added_keys": ["CHAVE-NOVA-1", "CHAVE-NOVA-2"],
        "removed_keys": ["CHAVE-ANTIGA-1"]
      }
    }
    ```
  </Accordion>

  <Accordion title="FEEDBACK_CREATED">
    Disparado quando o cliente envia uma avaliação do pedido. Traz a avaliação em `data.feedback`, junto com a identificação do pedido avaliado:

    ```json theme={null}
    {
      "id": "abc123xyz",
      "event": "FEEDBACK_CREATED",
      "date": "2026-02-20T15:30:00.000Z",
      "data": {
        "feedback": {
          "id": 1,
          "rating": 5,
          "message": "Entrega rápida, recomendo!",
          "is_public": true,
          "created_at": "2026-02-20T15:30:00.000-03:00",
          "order": {
            "internal_id": "1b2fe2a9697a0ac07ebd933309b4f9a8d1120c06",
            "client_name": "João da Silva",
            "client_email": "joao@email.com",
            "client_discord": null
          }
        }
      }
    }
    ```

    <Note>
      `is_public` reflete a configuração de publicação automática da loja no momento do envio. Avaliações que entram como privadas só aparecem na loja depois de publicadas, pelo painel ou pelo endpoint `PATCH /app/feedback/{feedback-id}`.
    </Note>
  </Accordion>

  <Accordion title="CHAT_MESSAGE_CREATED">
    Disparado quando o **cliente** envia uma mensagem no chat do pedido. Mensagens da loja não disparam o evento, inclusive as que a sua própria integração enviar: assim o seu sistema não recebe de volta o que ele mesmo acabou de mandar.

    ```json theme={null}
    {
      "id": "abc123xyz",
      "event": "CHAT_MESSAGE_CREATED",
      "date": "2026-02-20T15:30:00.000Z",
      "data": {
        "chat": {
          "channel_id": "66b2f4c1d1a7c9f2b3a04e11",
          "type": "order",
          "status": "active",
          "order_id": "1b2fe2a9697a0ac07ebd933309b4f9a8d1120c06"
        },
        "message": {
          "message": "Comprei mas ainda não recebi",
          "attachments": [],
          "user_type": "buyer",
          "timestamp": "2026-02-20T15:30:00.000Z"
        },
        "order": {
          "internal_id": "1b2fe2a9697a0ac07ebd933309b4f9a8d1120c06",
          "client_name": "João da Silva",
          "client_email": "joao@email.com",
          "client_identifier": "joaosilva"
        }
      }
    }
    ```

    Para responder, use o endpoint `POST /app/order/{order-id}/chat/messages` com o `internal_id` que vem em `data.order`.
  </Accordion>
</AccordionGroup>

## Respondendo o cliente pelo chat

Os webhooks entregam o que acontece na loja, e a API do chat é o caminho de volta: com os dois, a sua automação conversa com o cliente sem ninguém abrir o painel.

<Steps>
  <Step title="Assine CHAT_MESSAGE_CREATED">
    Cadastre um webhook com esse evento para receber as mensagens que o cliente enviar.
  </Step>

  <Step title="Responda pela API">
    Chame `POST /v1/app/order/{order-id}/chat/messages` com o `internal_id` do pedido. A chave de API precisa do escopo `chat:write`.

    ```bash theme={null}
    curl -X POST https://api.centralcart.io/v1/app/order/SEU_INTERNAL_ID/chat/messages \
      -H "Authorization: Bearer SUA_CHAVE" \
      -H "Content-Type: application/json" \
      -d '{"message": "Seu item já foi entregue, qualquer coisa é só chamar aqui."}'
    ```
  </Step>

  <Step title="Acompanhe pelo painel">
    As mensagens enviadas pela API aparecem no chat do painel, e o atendente pode assumir a conversa a qualquer momento.
  </Step>
</Steps>

<Note>
  A mensagem chega na hora para quem está com a página do pedido aberta. Se o cliente já tiver saído, ele recebe um e-mail avisando que a loja respondeu, no máximo um a cada seis horas por conversa.
</Note>

<Warning>
  Só dá para escrever em pedido que já tem chat. O chat nasce na aprovação do pedido, quando algum produto comprado está configurado para entrega por chat; nos demais, o endpoint responde `404`.
</Warning>

## Segurança (HMAC-SHA256)

Cada webhook possui um **secret** único gerado na criação. Todas as requisições são assinadas com HMAC-SHA256 para garantir autenticidade.

### Headers de segurança

| Header | Descrição |
| - | - |
| `x-centralcart-signature` | Assinatura HMAC-SHA256 em hexadecimal |
| `x-centralcart-timestamp` | Timestamp Unix do momento do envio |

### Verificando a assinatura

Para verificar a autenticidade do webhook, recalcule a assinatura usando o secret do webhook:

```javascript theme={null}
const crypto = require('crypto');

function verifyWebhook(payload, signature, timestamp, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(`${timestamp}.${JSON.stringify(payload)}`)
    .digest('hex');

  return signature === expected;
}

// No seu endpoint:
app.post('/webhook', (req, res) => {
  const signature = req.headers['x-centralcart-signature'];
  const timestamp = req.headers['x-centralcart-timestamp'];

  if (!verifyWebhook(req.body, signature, timestamp, 'seu_secret')) {
    return res.status(401).send('Assinatura inválida');
  }

  // Processar o evento
  const { event, data } = req.body;
  console.log(`Evento: ${event}`, data);

  res.status(200).send('OK');
});
```

## Configuração

Webhooks podem ser configurados em **Configurações > Webhooks** no painel da CentralCart, ou via API.

## Boas práticas

<CardGroup cols={2}>
  <Card title="Responda rápido" icon="bolt">
    Retorne um status 2xx o mais rápido possível. Processe o evento de forma assíncrona se necessário.
  </Card>

  <Card title="Idempotência" icon="rotate">
    Use o campo `id` do payload para evitar processar o mesmo evento duas vezes.
  </Card>

  <Card title="Verifique a assinatura" icon="shield-check">
    Sempre valide o header `x-centralcart-signature` antes de processar o evento.
  </Card>

  <Card title="Timeout" icon="clock">
    Requisições têm timeout de 10 segundos. Se seu servidor não responder a tempo, o envio será considerado como falha.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.