# Helpdesk

Receba pedidos de clientes por um formulário público, por um link ou por um widget no seu site. Cada pedido vira um card no board **Helpdesk** do projeto. O cliente acompanha o andamento por um link, sem criar conta, e a equipe responde direto pelo card.

> Versão em Markdown puro deste guia: [https://app.krakendock.com/docs/helpdesk.md?lang=pt-BR](https://app.krakendock.com/docs/helpdesk.md?lang=pt-BR). Use-a para colar num assistente de IA ou na documentação interna do seu time.

## Visão geral

| Peça           | Para quem                 | Onde                                             |
| -------------- | ------------------------- | ------------------------------------------------ |
| Formulário     | o cliente (solicitante)   | `https://app.krakendock.com/f/SEU-SLUG`, num iframe ou no widget |
| Board Helpdesk | a equipe                  | um board do projeto, visível só para membros     |
| Acompanhamento | o cliente                 | `https://app.krakendock.com/t/…`, link enviado por e-mail        |
| Configurações  | quem administra o projeto | Configurações do projeto → **Helpdesk**          |

O fluxo de um chamado:

1. O cliente envia o formulário, com anexos e os campos extras que você escolher.
2. O pedido vira um card na coluna **Novo** do board Helpdesk, com os dados do solicitante.
3. O cliente recebe um e-mail de confirmação com o link de acompanhamento.
4. A equipe responde pelo card. Cada resposta ao solicitante vai por e-mail e aparece no link de acompanhamento. As notas internas ficam só com a equipe.
5. O cliente pode responder pelo link. Se o chamado estava aguardando o cliente ou já tinha sido resolvido, a resposta reabre o atendimento.

## Configurar em 5 minutos

Você precisa da permissão de **gerenciar o projeto**.

1. Abra o projeto e vá em **Configurações → Helpdesk**. A opção fica no grupo **Integrações**.
2. Clique em **Novo formulário**. Preencha o **Nome** (uso interno) e o **Título da página** (o que o cliente vê).
3. Mantenha o formulário **Ativo** e salve. Ao ativar o primeiro formulário, o KrakenDock cria o board **Helpdesk** com quatro colunas:

   | Coluna                 | Papel                             | O cliente vê    |
   | ---------------------- | --------------------------------- | --------------- |
   | Novo                   | `new`                             | Recebido        |
   | Em atendimento         | `in_progress`                     | Em atendimento  |
   | Aguardando solicitante | `waiting`                         | Aguardando você |
   | Resolvido              | `resolved` (coluna de concluídos) | Resolvido       |

4. Na janela que aparece depois de salvar, copie o **link público**, o **iframe** ou o **botão flutuante** (widget). Veja [Divulgar o formulário](#divulgar-o-formulario).
5. Faça um pedido de teste. Ele aparece em segundos no board Helpdesk.

Pode renomear as colunas à vontade: cada uma guarda o seu papel. Uma coluna sem papel conta como **Resolvido** se for de concluídos e como **Em atendimento** nos outros casos. Os cards não passam do board Helpdesk para os outros boards do projeto, nem o contrário.

## Opções do formulário

Cada projeto pode ter vários formulários (por exemplo, "Suporte" e "Financeiro"). Todos entram no mesmo board Helpdesk.

### Geral

- **Nome**: até 80 caracteres, só para a equipe.
- **Título da página**: até 120 caracteres, aparece no topo do formulário.
- **Ativo**: um formulário inativo deixa de ser encontrado e não aceita pedidos.
- **Tipo do card**: Tarefa, Bug ou História.
- **Coluna de entrada**: por padrão, a coluna **Novo**.

### Textos

- **Introdução**: até 2.000 caracteres, em Markdown, mostrada acima dos campos. Os links abrem em nova aba.
- **Mensagem de sucesso**: até 1.000 caracteres, mostrada depois do envio.
- **Texto de consentimento**: até 1.000 caracteres. Sem texto, vale o padrão: "Concordo que os dados enviados sejam usados para responder a este pedido."
- **Consentimento coletado pelo sistema integrado**: veja [Identidade assinada](#identidade-assinada-login-do-seu-sistema).

### Campos

- Os campos fixos são **nome**, **e-mail**, **assunto** (até 255 caracteres) e **descrição** (até 20.000 caracteres, em Markdown).
- **Telefone do solicitante**: Não pedir, Opcional ou Obrigatório. Aceita de 8 a 15 dígitos.
- **Campos extras**: até 20 campos customizados do projeto, cada um com rótulo, ajuda e a opção de ser obrigatório. Os tipos aceitos são texto, número, data, seleção, seleção múltipla, caixa de seleção e URL. Os campos customizados são criados nas configurações do projeto, em **Campos** ([guia de campos e templates](https://app.krakendock.com/docs/fields-templates)). O plano Free permite 3 por projeto, e os planos pagos, 50.

### Anexos

- **Permitir anexos**: ligado por padrão. O tamanho e a quantidade de arquivos dependem do plano (veja [Limites por plano](#limites-por-plano)).
- Executáveis, scripts e arquivos vazios são recusados.

### Incorporação

- **Endereço da página** (slug): de 3 a 48 caracteres, com letras minúsculas, números e hífen, sem começar nem terminar com hífen. O slug é único em todo o KrakenDock. Trocar o slug quebra o link antigo.
- **Origens permitidas**: até 20 sites que podem mostrar o formulário num iframe ou no widget, no formato `https://app.suaempresa.com` (sem caminho). `http` só é aceito para `localhost`, e domínios com acento vão em punycode. Sem nenhuma origem, o formulário só funciona pelo link.

### Aparência

- **Cor de destaque**: `#rrggbb`, usada em botões, links e foco. As configurações avisam quando a cor tem pouco contraste.
- O logo é o avatar do projeto.

## Divulgar o formulário

### Link

O jeito mais simples: mande o link por e-mail, coloque num botão do site ou na assinatura.

```text
https://app.krakendock.com/f/SEU-SLUG
```

### Iframe

Mostra o formulário dentro de uma página do seu site. A origem do site precisa estar em **Origens permitidas**.

```html
<iframe
  id="kraken-form"
  src="https://app.krakendock.com/f/SEU-SLUG?embed=1"
  title="Fale com o suporte"
  style="width:100%;min-height:640px;border:0"
  loading="lazy"
></iframe>
```

Para combinar com o seu site, acrescente à URL do iframe os parâmetros abaixo. Eles só valem junto com `embed=1`; valores inválidos são ignorados.

| Parâmetro | Valores                     | Padrão                                     |
| --------- | --------------------------- | ------------------------------------------ |
| `theme`   | `light`, `dark` ou `system` | o tema do sistema operacional do visitante |
| `lang`    | `pt-BR` ou `en`             | o idioma do navegador                      |

Exemplo: `https://app.krakendock.com/f/SEU-SLUG?embed=1&theme=light&lang=pt-BR`. Sem eles, o formulário não sabe o tema nem o idioma que o visitante escolheu no Kraken: um iframe em outro site não recebe esses cookies.

O formulário avisa a altura do conteúdo por `postMessage`. Para o iframe crescer junto e não mostrar barra de rolagem, acrescente:

```html
<script>
  window.addEventListener('message', function (event) {
    var frame = document.getElementById('kraken-form');
    if (event.origin !== 'https://app.krakendock.com' || event.source !== frame.contentWindow) return;
    if (event.data && event.data.type === 'kraken-intake:resize') {
      frame.style.height = event.data.height + 'px';
    }
  });
</script>
```

### Widget (botão flutuante)

Um botão no canto da página abre o formulário num painel no estilo chat. Em telas de até 639 px, o painel ocupa a tela inteira. O painel não bloqueia a página, e o rascunho continua lá se o cliente fechar e abrir de novo. A origem do site precisa estar em **Origens permitidas**.

```html
<script
  src="https://app.krakendock.com/intake.js"
  data-form="SEU-SLUG"
  data-label="Suporte"
  data-close-label="Fechar"
  data-color="#4f46e5"
  async
></script>
```

Os textos padrão dos botões são em português. Num site em outro idioma, defina `data-label` e `data-close-label`. Para o formulário combinar com o site, use `data-theme` e `data-lang`: o painel não recebe os cookies do Kraken, então sem eles segue o tema do sistema operacional e o idioma do navegador do visitante.

| Atributo           | Obrigatório | O que faz                                                                                        |
| ------------------ | ----------- | ------------------------------------------------------------------------------------------------ |
| `data-form`        | sim         | slug do formulário                                                                               |
| `data-label`       | não         | texto do botão (padrão: "Suporte")                                                               |
| `data-close-label` | não         | nome acessível do botão de fechar (padrão: "Fechar")                                             |
| `data-position`    | não         | `right` (padrão) ou `left`                                                                       |
| `data-color`       | não         | cor do botão, `#rgb` ou `#rrggbb` (padrão: `#4f46e5`). A cor do texto é escolhida pelo contraste |
| `data-identity`    | não         | token de identidade assinada (veja abaixo)                                                       |
| `data-theme`       | não         | tema do formulário: `light`, `dark` ou `system` (padrão: o do sistema operacional do visitante)  |
| `data-lang`        | não         | idioma do formulário: `pt-BR` ou `en` (padrão: o do navegador)                                   |

## API do widget

Depois que o `intake.js` carrega, a página ganha o objeto `window.KrakenIntake`:

| Função                       | O que faz                                                                                               |
| ---------------------------- | ------------------------------------------------------------------------------------------------------- |
| `open(slug?)`                | abre o painel, opcionalmente com outro formulário                                                       |
| `close()`                    | fecha o painel                                                                                          |
| `toggle()`                   | abre ou fecha                                                                                           |
| `identify(token)`            | informa a identidade assinada do usuário logado; `identify(null)` esquece só a identidade               |
| `prefill(values)`            | pré-preenche o formulário; `prefill(null)` esquece                                                      |
| `onIdentityExpired(handler)` | registra a função que busca um token novo quando o atual expira                                         |
| `reset()`                    | fecha o painel e descarta rascunho, identidade, pré-preenchimento e `onIdentityExpired` (use no logout) |

Exemplo: abrir o suporte a partir de um link do seu menu.

```html
<a href="#" onclick="window.KrakenIntake.open(); return false;">Precisa de ajuda?</a>
```

A tecla `Esc` também fecha o painel.

## Pré-preenchimento

Sugere valores que o cliente ainda pode editar. Não comprova quem é o usuário (para isso, use a [identidade assinada](#identidade-assinada-login-do-seu-sistema)). Funciona em todos os planos.

Pelo widget:

```js
window.KrakenIntake.prefill({
  name: 'Ana Souza',
  email: 'ana@cliente.com',
  phone: '+55 11 91234-5678',
  subject: 'Problema no pedido 1234',
  description: 'Descreva o que aconteceu…',
  fields: { 'ID-DO-CAMPO': 'valor' },
});
```

- Cada texto aceita até 20.000 caracteres, e `fields` aceita até 50 campos.
- As chaves de `fields` são os ids dos campos extras, e cada valor segue o tipo do campo:

| Tipo do campo    | Valor esperado                | Exemplo              |
| ---------------- | ----------------------------- | -------------------- |
| texto, URL       | texto                         | `'Pedido 1234'`      |
| número           | número ou texto numérico      | `42` ou `'42'`       |
| data             | texto no formato `AAAA-MM-DD` | `'2026-10-19'`       |
| seleção          | id da opção (não o rótulo)    | `'8f0c…'`            |
| seleção múltipla | lista de ids de opções        | `['8f0c…', '1a2b…']` |
| caixa de seleção | booleano                      | `true`               |

- Número, seleção, seleção múltipla e caixa de seleção fora do formato, ids de campo desconhecidos e opções que não existem no campo são **ignorados sem aviso**.
- Texto, URL e data são usados como vieram: confira o formato antes de enviar. Uma URL sem `https://` bloqueia o envio até o cliente corrigir, e uma data fora de `AAAA-MM-DD` faz o envio falhar.
- Os ids estão na configuração pública do formulário: o id do campo em `data.fields[].field_id` e os das opções em `data.fields[].options[].id`.

```bash
curl https://app.krakendock.com/api/intake/SEU-SLUG
```

Pelo link (fragmento `#`), só os campos fixos:

```text
https://app.krakendock.com/f/SEU-SLUG#name=Ana%20Souza&email=ana%40cliente.com&subject=Pedido%201234
```

- As chaves aceitas são `name`, `email`, `phone`, `subject` e `description`.
- Os valores vão codificados para URL.
- O fragmento é lido uma vez e apagado da barra de endereço. Ele só preenche campos vazios.

## Identidade assinada (login do seu sistema)

Quando o cliente já está logado no seu sistema, o widget pode abrir com o nome, o e-mail e o telefone dele preenchidos e travados. Nesse caso o envio:

- não pede captcha;
- marca o chamado como **Verificado**;
- libera a aba [Meus chamados](#meus-chamados).

A identidade assinada está disponível nos planos **Pro** e **Business**.

### 1. Gere a chave do projeto

Em **Configurações → Helpdesk → Integração com seu sistema**, clique em **Gerar chave**.

- A chave começa com `khd_` e aparece **uma única vez**. Guarde-a num cofre de segredos do **servidor**. Ela nunca pode ir para o navegador.
- **Trocar chave** invalida a anterior na hora. **Remover** desliga a identidade assinada.

### 2. Gere o token no seu servidor

O token é um JWT **HS256** assinado com a chave inteira, **incluindo o prefixo `khd_`**.

| Claim   | Obrigatório | Regra                                                            |
| ------- | ----------- | ---------------------------------------------------------------- |
| `sub`   | sim         | id do usuário no seu sistema, como **texto**, até 128 caracteres |
| `name`  | sim         | até 120 caracteres                                               |
| `email` | sim         | e-mail válido, até 254 caracteres                                |
| `phone` | não         | de 8 a 15 dígitos; aceita `+`, espaço, `-`, `.`, `(` e `)`       |
| `exp`   | sim         | no máximo 24 h no futuro (recomendado: 1 h)                      |

Node ([jsonwebtoken](https://www.npmjs.com/package/jsonwebtoken)):

```js
import jwt from 'jsonwebtoken';

const token = jwt.sign(
  {
    sub: String(user.id),
    name: user.name,
    email: user.email,
    ...(user.phone ? { phone: user.phone } : {}),
  },
  process.env.KRAKEN_IDENTITY_KEY,
  { algorithm: 'HS256', expiresIn: '1h' },
);
```

PHP ([firebase/php-jwt](https://github.com/firebase/php-jwt)):

```php
use Firebase\JWT\JWT;

$claims = [
    'sub' => (string) $user->id,
    'name' => $user->name,
    'email' => $user->email,
    'exp' => time() + 3600,
];
if ($user->phone) {
    $claims['phone'] = $user->phone;
}

$token = JWT::encode($claims, getenv('KRAKEN_IDENTITY_KEY'), 'HS256');
```

Python ([PyJWT](https://pyjwt.readthedocs.io/)):

```python
import os
from datetime import datetime, timedelta, timezone

import jwt

claims = {
    "sub": str(user.id),
    "name": user.name,
    "email": user.email,
    "exp": datetime.now(timezone.utc) + timedelta(hours=1),
}
if user.phone:
    claims["phone"] = user.phone

token = jwt.encode(claims, os.environ["KRAKEN_IDENTITY_KEY"], algorithm="HS256")
```

Go ([golang-jwt](https://github.com/golang-jwt/jwt)):

```go
import (
	"os"
	"time"

	"github.com/golang-jwt/jwt/v5"
)

claims := jwt.MapClaims{
	"sub":   userID, // string
	"name":  user.Name,
	"email": user.Email,
	"exp":   time.Now().Add(time.Hour).Unix(),
}
if user.Phone != "" {
	claims["phone"] = user.Phone
}

token, err := jwt.NewWithClaims(jwt.SigningMethodHS256, claims).
	SignedString([]byte(os.Getenv("KRAKEN_IDENTITY_KEY")))
```

### 3. Entregue o token ao widget

Na página do usuário logado:

```html
<script src="https://app.krakendock.com/intake.js" data-form="SEU-SLUG" data-identity="TOKEN" async></script>
```

Ou depois que o script carregar (por exemplo, numa aplicação de página única):

```js
window.KrakenIntake.identify(token);
// no logout:
window.KrakenIntake.reset();
```

No logout, prefira `reset()` a `identify(null)`: além de esquecer a identidade, ele descarta o rascunho do formulário (assunto, descrição, anexos e campos pré-preenchidos), o pré-preenchimento e a função registrada em `onIdentityExpired`. Uma renovação de token que ainda esteja em andamento vai até o fim (a função do seu site roda e a requisição acontece), mas o token que ela devolver é descartado. Assim, a próxima pessoa que usar a mesma aba começa com o formulário limpo. O `reset()` vale para todos os widgets da página, mesmo que haja mais de um formulário. O botão continua na página; depois do `reset()`, chame `identify(token)` e `prefill(values)` de novo para o próximo usuário.

Para renovar o token quando ele expira com o widget aberto, registre uma função que busque um token novo no seu backend:

```js
window.KrakenIntake.onIdentityExpired(async () => {
  const response = await fetch('/kraken-token'); // rota do seu backend que gera o JWT
  if (!response.ok) return null; // sem token: o formulário volta a pedir os dados
  return response.text();
});
```

- O widget chama essa função no máximo uma vez a cada 50 segundos.
- Sem a função, o formulário volta a pedir os dados e mantém o que já foi digitado.

**Regras importantes:**

- A identidade só é aceita pelo widget (ou por um iframe, com o [protocolo de mensagens](#protocolo-de-mensagens)), vindo de uma **origem permitida**.
- `#identity=` no link é ignorado, para ninguém conseguir mandar um link que abra chamados no nome de outra pessoa.
- Nunca coloque o token na query string.
- Não há proteção contra reuso: o token vale até expirar. Por isso, use validades curtas.
- Com **Consentimento coletado pelo sistema integrado** ligado no formulário, o usuário identificado não vê a caixa de consentimento. O consentimento fica registrado como coletado pela integração.

### Erros da identidade

Uma identidade recusada não trava o formulário: ele volta ao modo normal e registra o motivo no console do navegador, por exemplo `[Kraken] Identidade assinada recusada (signature): o formulário segue sem identificação.` A API responde `422 INTAKE_IDENTITY_INVALID` com o motivo em `fields.identity`:

| Motivo      | Quando acontece                                                                                           |
| ----------- | --------------------------------------------------------------------------------------------------------- |
| `malformed` | não é um JWT, passa de 4 KB ou tem claim com tipo errado (por exemplo, `sub` numérico)                    |
| `signature` | outro algoritmo, assinado com outra chave ou sem o prefixo `khd_`                                         |
| `expired`   | passou do `exp` (há uma folga de 30 s)                                                                    |
| `claims`    | falta `sub`, `name`, `email` ou `exp`, `exp` passa de 24 h, `iat` está no futuro ou o telefone é inválido |
| `disabled`  | o projeto não tem chave                                                                                   |

Num plano sem a identidade assinada, a resposta é `403 PLAN_FEATURE_REQUIRED`.

Pelo widget ou por um iframe, `disabled` e o `403` não chegam a aparecer. Se o projeto não tem chave, ou se o plano não inclui o recurso, o formulário nem consulta a API: ele só registra no console `[Kraken] Identidade assinada ignorada: o formulário não aceita identidade (chave do projeto ausente ou plano sem o recurso).` Um token com mais de 4.096 caracteres é descartado pelo `intake.js` sem aviso.

## Meus chamados

Com a identidade assinada, o widget mostra as abas **Novo chamado** e **Meus chamados**. Na segunda, o usuário vê os últimos 50 pedidos verificados dele no projeto (do mesmo `sub`), do mais novo para o mais antigo, e abre cada conversa sem depender do e-mail. Quando é a mesma pessoa, as respostas enviadas por ali não pedem captcha.

## O que o cliente vê

### Acompanhamento

Depois do envio, o cliente vê o número do pedido e o link de acompanhamento, que também chega por e-mail. A página `https://app.krakendock.com/t/…` mostra:

- as etapas **Recebido → Em atendimento → Aguardando você → Resolvido**;
- a conversa: a descrição é a primeira mensagem, e depois vêm as respostas do cliente e as da equipe marcadas para o solicitante;
- uma caixa de resposta, com até 10.000 caracteres e anexos;
- os arquivos e os detalhes do pedido;
- o bloco **Seus dados**, para baixar ou excluir os dados.

O link de acompanhamento é pessoal: quem tem o link vê o pedido. Ele não é indexado por buscadores.

### E-mails ao solicitante

| Quando                                      | Assunto                              |
| ------------------------------------------- | ------------------------------------ |
| O pedido é recebido                         | Recebemos seu chamado `KEY-N`        |
| A equipe responde ao solicitante            | Nova resposta no seu chamado `KEY-N` |
| O status visível muda (menos para Recebido) | Seu chamado `KEY-N` foi atualizado   |

- As respostas do próprio cliente não geram e-mail.
- **Enviar e aguardar** manda só o e-mail da resposta, sem um segundo e-mail de status.
- Nos planos pagos, os e-mails e as páginas saem sem a marca KrakenDock.

## Atender um chamado (equipe)

Abra o card no board Helpdesk.

- **Solicitante**: mostra nome, e-mail, telefone, o id no seu sistema (com identidade assinada), o formulário, a data de abertura, o consentimento e o selo **Verificado**. Quem gerencia o projeto também vê as ações **Bloquear e-mail**, **Bloquear IP** e **Anonimizar solicitante**.
- **Conversa**: o fio com o cliente. Responda em **Responder ao solicitante**:
  - **Enviar** manda a resposta por e-mail e a mostra no link de acompanhamento.
  - **Enviar e aguardar** faz o mesmo e move o card para **Aguardando solicitante**.
  - Imagens coladas no editor não aparecem para o cliente. Para mandar arquivos, use anexos.
- **Botões de status**, conforme a coluna em que o card está:

  | Status atual           | Botões                         |
  | ---------------------- | ------------------------------ |
  | Novo                   | Iniciar atendimento, Resolver  |
  | Em atendimento         | Aguardar solicitante, Resolver |
  | Aguardando solicitante | Retomar atendimento, Resolver  |
  | Resolvido              | Reabrir                        |

- **Notas internas**: os comentários comuns do card são internos (selo **Interno**) e nunca chegam ao cliente. O **Histórico** do card mostra as notas internas e a atividade, sem as mensagens da conversa.
- Se o cliente responder enquanto o card está em **Aguardando solicitante** ou **Resolvido**, o card volta para **Em atendimento** sozinho.
- Um card arquivado, ou com comentários travados, não recebe novas respostas do cliente.

## Proteção contra abuso

- **Captcha** ([Cloudflare Turnstile](https://www.cloudflare.com/products/turnstile/)): só aparece quando o Cloudflare pede uma interação. Não é pedido para usuários com identidade assinada.
- **Campo isca** (honeypot): robôs que preenchem campos ocultos são recusados.
- **Limites de envio** por IP, por e-mail e por link de acompanhamento. Quem passa do limite recebe `429 RATE_LIMITED`.
- **Bloqueios**: em **Configurações → Helpdesk → Bloqueios**, ou pelo painel do solicitante no card, bloqueie um e-mail ou um IP, com um motivo opcional. O bloqueio vale para todos os formulários do projeto (`403 INTAKE_BLOCKED`).
- O board Helpdesk é visível só para os membros do projeto, mesmo num projeto público.

## LGPD e dados do solicitante

- O formulário pede o consentimento do solicitante (ou o registra como coletado pela integração, se o formulário estiver configurado assim).
- Pelo link de acompanhamento, o próprio solicitante pode:
  - **Baixar meus dados**: um JSON com os dados pessoais, as mensagens visíveis e a lista de arquivos. As notas internas nunca entram.
  - **Excluir meus dados**: apaga nome, e-mail, telefone, IP, id externo e a cópia do assunto e da descrição. O link para de funcionar, mas o card continua com a equipe.
- A equipe pode **Anonimizar solicitante** pelo card, com o mesmo efeito. A ação é irreversível.

## Limites por plano

|                                                       | Free  | Pro        | Business   |
| ----------------------------------------------------- | ----- | ---------- | ---------- |
| Formulários por projeto                               | 3     | ilimitados | ilimitados |
| Chamados por mês (soma de todos os projetos da conta) | 50    | ilimitados | ilimitados |
| Tamanho por arquivo                                   | 5 MiB | 25 MiB     | 50 MiB     |
| Arquivos por pedido                                   | 3     | 10         | 20         |
| Sem a marca KrakenDock                                | —     | sim        | sim        |
| Identidade assinada e Meus chamados                   | —     | sim        | sim        |
| Pré-preenchimento, iframe e widget                    | sim   | sim        | sim        |

- O uso do mês aparece em **Configurações → Helpdesk → Uso do helpdesk**.
- Excluir um card não devolve a cota.
- Os anexos também contam no armazenamento da conta.

Veja os planos em [https://app.krakendock.com/pricing](https://app.krakendock.com/pricing).

## Integrar com outros sistemas

| Quero…                                               | Use                                                                                                                                                                                                                                              |
| ---------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| receber pedidos de um site ou app                    | [link, iframe ou widget](#divulgar-o-formulario)                                                                                                                                                                                                 |
| identificar o usuário logado                         | [identidade assinada](#identidade-assinada-login-do-seu-sistema)                                                                                                                                                                                 |
| sugerir dados que o cliente pode editar              | [pré-preenchimento](#pre-preenchimento)                                                                                                                                                                                                          |
| avisar outro sistema quando um chamado chega ou muda | webhooks do projeto (`card.created`, `card.moved`, `comment.created`…), nas configurações do projeto, em **Webhooks**                                                                                                                            |
| deixar um assistente de IA ler e responder chamados  | o servidor MCP do KrakenDock, com um token com permissão de escrita, criado nas configurações da sua conta em **Tokens de acesso (MCP)**: `get_card` traz a conversa, e `add_comment` com `visibility: requester` responde ao cliente por e-mail |

Os webhooks dos cards do Helpdesk não levam nome, e-mail nem IP do solicitante.

### Protocolo de mensagens

O widget e o formulário conversam por `postMessage`. Se você usar um **iframe** próprio (`?embed=1`) em vez do widget, pode usar as mesmas mensagens:

| Direção             | Mensagem                                                                                        |
| ------------------- | ----------------------------------------------------------------------------------------------- |
| formulário → página | `{ type: 'kraken-intake:ready' }` a cada carga: a hora de mandar identidade e pré-preenchimento |
| formulário → página | `{ type: 'kraken-intake:resize', height }` quando a altura muda                                 |
| formulário → página | `{ type: 'kraken-intake:close' }` quando o cliente aperta `Esc`                                 |
| formulário → página | `{ type: 'kraken-intake:identity-expired', generation }` quando a identidade expira             |
| página → formulário | `{ type: 'kraken-intake:identity', token }` (`null` esquece)                                    |
| página → formulário | `{ type: 'kraken-intake:prefill', values }`                                                     |

Regras do protocolo:

- O formulário só aceita mensagens da janela que o contém (`window.parent`) e de uma origem permitida.
- Mande as mensagens com `targetOrigin` igual a `https://app.krakendock.com`.

```js
var frame = document.getElementById('kraken-form');
window.addEventListener('message', function (event) {
  if (event.origin !== 'https://app.krakendock.com' || event.source !== frame.contentWindow) return;
  if (event.data && event.data.type === 'kraken-intake:ready') {
    frame.contentWindow.postMessage({ type: 'kraken-intake:identity', token: TOKEN }, 'https://app.krakendock.com');
  }
});
```

## Solução de problemas

| Sintoma                                                                          | Causa provável                                                                                                                                                         |
| -------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| O iframe ou o widget aparece em branco, ou o navegador diz que recusou a conexão | a origem do site não está em **Origens permitidas** (o formato é `https://dominio`, sem barra no fim)                                                                  |
| "Formulário não encontrado"                                                      | o slug está errado, o formulário está inativo ou o board Helpdesk foi excluído                                                                                         |
| Console: "Identidade assinada ignorada"                                          | o projeto não tem chave (gere em **Integração com seu sistema**) ou o plano não inclui a identidade assinada                                                           |
| A identidade é ignorada                                                          | veja o motivo no console do navegador e na tabela [Erros da identidade](#erros-da-identidade). O mais comum é assinar sem o prefixo `khd_` ou mandar `sub` como número |
| A identidade funciona no widget, mas não no link                                 | é o esperado: o link aceita só pré-preenchimento                                                                                                                       |
| O cliente não recebeu o e-mail                                                   | confira a caixa de spam. O link de acompanhamento também aparece na tela de sucesso                                                                                    |
| "Este pedido não recebe mais respostas."                                         | o card foi arquivado ou teve os comentários travados                                                                                                                   |
| Envio recusado com `429`                                                         | limite de envios por IP, e-mail ou link. Espere alguns minutos                                                                                                         |
| O limite de 50 chamados acabou                                                   | no plano Free, o limite é por conta e por mês. Os planos Pro e Business não têm limite                                                                                 |

Ainda com dúvidas? Fale com a gente em [https://app.krakendock.com/help](https://app.krakendock.com/help).
