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

# Webhooks dos seus sistemas

> CRM, ERP e help desk entram pelo webhook genérico, com mapeamento versionado e autenticação.

O seu CRM, ERP, help desk, cobrança e sistema de pedidos já emitem um evento quando algo muda: um pedido é criado, uma fatura é contestada, um ticket reabre, um pagamento é recusado. A Niadra recebe esses eventos por um webhook genérico, guarda o conteúdo bruto e aplica um mapeamento versionado que extrai o tipo, o objeto, o id do cliente naquele sistema, os campos e o horário. Nenhum modelo de linguagem lê um evento de sistema, e você não escreve código no sistema que envia.

Este guia liga um ERP para que o `invoice.credited` da fatura 0823 chegue à memória da Marina Souza às 14h06, ao lado da ação que o agente de cobrança registrou.

## Como um evento de sistema vira memória

1. O ERP envia o JSON dele para `POST /v1/ingest/webhook/{source_id}`.
2. A Niadra autentica a requisição com o método declarado para aquela fonte e grava o conteúdo bruto antes de responder.
3. O mapeamento versionado da fonte gera o evento: `canonical_type`, o objeto, o `system_id` do cliente, os campos e o `occurred_at`.
4. O objeto ganha linha do tempo e estado derivado, com `as_of` e referência ao registro de origem. Pendências ligadas a ele podem fechar.
5. A camada ao vivo tem o evento em menos de um segundo; o contexto recompilado, em menos de dez.

O valor oficial fica no ERP. A memória guarda o que os agentes precisam lembrar e aponta para a origem.

## Passo a passo

### 1. Crie uma fonte para o sistema

Cada sistema é uma fonte, com finalidade e audiência próprias. Crie no Console ou pela [API de controle](/api/control/sources-create). Anote o `source_id`: ele é o último trecho do endereço do webhook.

```text theme={null}
https://acme-prod.us-east-1.api.niadra.com/v1/ingest/webhook/0192f7b0-3c2d-7e41-9a55-6b1d0e8f2a13
```

### 2. Escolha como o sistema se autentica

A autenticação é obrigatória e declarada por fonte, no mapeamento. Sem ela, quem descobrisse o endereço poderia injetar histórico falso, uma ação que fecha promessa ou uma fatura paga.

| Método      | Como funciona                                                                                                                           | Quando usar                             |
| ----------- | --------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------- |
| `hmac`      | O sistema assina o corpo; você declara o cabeçalho, o algoritmo, o texto assinado e o segredo. Carimbo com mais de 5 minutos é recusado | O sistema suporta webhook assinado      |
| `bearer`    | Um token fixo em `Authorization`                                                                                                        | O sistema deixa configurar um cabeçalho |
| `url_token` | Um token secreto no endereço                                                                                                            | O sistema só aceita uma URL             |
| `mtls`      | Certificado de cliente                                                                                                                  | O sistema suporta TLS mútuo             |

O segredo é gravado direto no cofre da sua célula e nunca mais aparece. Requisição que falha na autenticação recebe 401 e entra na cobertura da fonte, e um sistema mal configurado aparece antes de alguém sentir falta dos eventos dele. Quando o sistema de origem pede um desafio de verificação por `GET` antes de começar a enviar, a Niadra responde.

### 3. Escreva o mapeamento

O mapeamento transforma o conteúdo que o seu sistema já envia em eventos, com expressões no estilo JMESPath. Este é o conteúdo do ERP:

```json Conteúdo do ERP theme={null}
{
  "event": "invoice.credited",
  "invoice": "0823",
  "customer_id": "48213",
  "amount": 40.00,
  "currency": "USD",
  "at": "2026-09-22T17:06:21Z"
}
```

E este é um mapeamento para ele:

```yaml Mapeamento theme={null}
version: 3
auth:
  method: hmac
  header: X-ERP-Signature
  algorithm: sha256
  signed: "{timestamp}.{body}"
  tolerance_seconds: 300
types:
  - when: "event == 'invoice.credited'"
    canonical_type: invoice.credited
    object: { type: invoice, namespace: erp, id: "invoice" }
    subject: { type: system_id, scope: crm, value: "customer_id" }
    occurred_at: "at"
    fields:
      amount: "amount"
      currency: "currency"
  - when: "event == 'invoice.disputed'"
    canonical_type: invoice.disputed
    object: { type: invoice, namespace: erp, id: "invoice" }
    subject: { type: system_id, scope: crm, value: "customer_id" }
    occurred_at: "at"
```

Só tipos mapeados entram. Esse filtro na borda protege a memória do volume de um ERP. Um tipo não mapeado fica 7 dias em armazenamento frio, para você mapear depois e reprocessar, e nunca entra na memória. Como o conteúdo bruto é sempre guardado, um mapeamento melhor pode ser aplicado a eventos que já chegaram.

<Tip>
  O assistente de configuração escreve a primeira versão para você. Peça por [`POST /v1/assist`](/api/assist) (`task: "webhook_mapping"` e o `source_id`, como pessoa com o papel `integration`): ele propõe o mapeamento, valida contra os eventos de amostra do seu espaço e lista em `problems` o que ficou sem mapear. A proposta vira um diff na API de controle, e uma pessoa aprova. Acompanhe a execução por [`GET /v1/assist/{run_id}`](/api/assist-run) e liste as anteriores por [`GET /v1/assist`](/api/assist-runs).
</Tip>

### 4. Proponha o mapeamento como mudança versionada

Configuração nunca é gravada no lugar. Uma mudança de mapeamento é um diff na API de controle, com o `document` novo inteiro do tipo e um `reason`, aprovado por uma pessoa; a célula recebe a mudança por um snapshot assinado. [`GET /v1/config/types`](/api/control/config-types) lista os tipos e os papéis que podem mudar cada um, e [`GET /v1/config/mappings`](/api/control/config-document) devolve o documento vigente, para você partir dele. Toda versão fica no [histórico](/api/control/config-history) e pode ser [desfeita](/api/control/config-diff-rollback).

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://control.api.niadra.com/v1/config/diffs" \
    -H "Authorization: Bearer $NIADRA_CONTROL_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
      "space_id": "0192f6e1-8b7a-7c20-b3d4-2a9e5f1c6d08",
      "type": "mappings",
      "document": { "sources": { "0192f7b0-3c2d-7e41-9a55-6b1d0e8f2a13": { "version": 3, "types": ["invoice.credited", "invoice.disputed"] } } },
      "reason": "Map ERP credits and disputes"
    }'
  ```
</CodeGroup>

Veja [Propor mudança de configuração](/api/control/config-diffs) e [Aprovar mudança](/api/control/config-diff-approve).

### 5. Aponte o sistema para o endereço

Configure o webhook no seu ERP com o endereço do passo 1 e o segredo do passo 2. A partir daí, toda requisição responde no formato do lote: `accepted`, `duplicates` e `errors` por evento, com 200 quando tudo entrou e 207 quando algo foi recusado:

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://acme-prod.us-east-1.api.niadra.com/v1/ingest/webhook/0192f7b0-3c2d-7e41-9a55-6b1d0e8f2a13" \
    -H "X-ERP-Signature: t=1758560781,v1=5f1c9e..." \
    -H "Content-Type: application/json" \
    -d '{ "event": "invoice.credited", "invoice": "0823", "customer_id": "48213", "amount": 40.00, "currency": "USD", "at": "2026-09-22T17:06:21Z" }'
  ```
</CodeGroup>

```json Resposta theme={null}
{ "accepted": 1, "duplicates": 0, "errors": [] }
```

### 6. Confira o que chegou

Leia o objeto para ver o estado derivado e a linha do tempo. O crédito aparece com o evento do ERP e a ação do agente de cobrança num registro só: a ação ficou `declared` às 14h06 e virou `confirmed` quando o `invoice.credited` chegou.

<CodeGroup>
  ```bash cURL theme={null}
  curl "https://acme-prod.us-east-1.api.niadra.com/v1/objects/invoice/erp/0823/timeline" \
    -H "Authorization: Bearer $NIADRA_API_KEY"
  ```
</CodeGroup>

## Texto livre de dentro de um sistema

A descrição de um ticket ou o corpo de um e-mail não é evento estruturado. Mande como `message` num canal próprio (`ticket`, `email`) e ele passa pela extração normal, como uma conversa. Texto livre de ticket e e-mail é cobrado como conversa; eventos de sistema mapeados não são cobrados.

## Sistemas sem webhook

Para sistemas que só exportam arquivos, transforme a exportação em JSONL, com um item de lote por linha, e mande para [`POST /v1/ingest/files`](/api/ingest-files); cada linha é validada como um item de `POST /v1/batch`. Para semear identidade a partir de uma exportação do CRM, mande em CSV. Para sistemas que o seu time já integra por código, mande eventos de sistema pelo SDK ou por [`POST /v1/batch`](/api/batch), com `kind: "system_event"` e `canonical_type`.

## Próximos passos

<CardGroup cols={2}>
  <Card title="Sistemas, objetos e ações" href="/concepts/systems">
    objetos, estado derivado e como as ações fecham pendências.
  </Card>

  <Card title="Agentes internos" href="/guides/internal-agents">
    o agente de cobrança que registrou o crédito.
  </Card>

  <Card title="Receber webhook de sistema" href="/api/ingest-webhook">
    a referência do endpoint.
  </Card>

  <Card title="Gatilhos e webhooks" href="/concepts/triggers-and-webhooks">
    o caminho inverso, da Niadra para os seus sistemas.
  </Card>
</CardGroup>
