Skava Skava / Wiki

Conectando Elementos Personalizados para desenvolvedores

Esta página é para desenvolvedores que conectam o backend de uma empresa ao Skava. A criação e a publicação de um elemento de API são abordadas em Elementos Personalizados: interfaces de API; aqui, cobrimos tudo o que precisa acontecer na outra ponta da linha.

A ideia em uma frase: o Skava não conhece o seu domínio. Ele conhece exatamente um formato, o cartão. Você decide o que ele diz, nós apenas verificamos forma, tamanho e segurança. Um pedido de materiais é um exemplo; a próxima empresa coleta feedback de usuários, a seguinte arquiva uma foto do canteiro de obras em seus próprios registros.

O fluxo de relance

  1. Um administrador da empresa cria um elemento de API no Skava: um formulário, além do endereço, método e token do seu backend.
  2. Alguém no chat preenche o formulário e o envia.
  3. O Skava chama o seu backend e envia os valores preenchidos em JSON.
  4. A sua resposta torna-se o cartão no chat.
  5. Opcionalmente, você reporta novos estados mais tarde através do callback. Cada relatório torna-se outro cartão; o anterior permanece.

Requisitos para o seu backend

  • HTTPS. Apenas https://, sem http, sem credenciais no endereço, no máximo 2000 caracteres.
  • Alcance público. O host deve resolver exclusivamente para IPs públicos. Localhost, redes privadas, link-local e metadados de nuvem são rejeitados, e isso é verificado em cada chamada.
  • Endereço fixo. O Skava resolve o host uma vez e fixa a conexão naquele IP. Uma mudança de DNS durante a chamada não tem efeito.
  • Sem redirecionamentos. Um 301 para o endereço "correto" conta como falha. Insira o endereço final imediatamente.
  • Tempo de resposta. O tempo limite é configurável por elemento e limitado a 30 segundos. Se precisar de mais tempo, responda imediatamente e reporte o resultado depois através do callback.
  • Tamanho da resposta. A Skava lê no máximo 256 KiB.
  • Content-Type. O corpo é analisado apenas com application/json.

A requisição que chega até você

O método é GET, POST, PUT ou PATCH, dependendo do elemento. Com POST, PUT e PATCH, os valores chegam como corpo JSON, e com GET como parâmetros de consulta.

A autenticação é um único cabeçalho cujo nome e prefixo de valor são configurados no elemento, geralmente Authorization com o prefixo Bearer . O token é armazenado criptografado do nosso lado. Os cabeçalhos host, content-length, content-type, cookie e accept-encoding não podem ser definidos.

O corpo é um objeto plano. As chaves são escolhidas por quem construiu o elemento; o aninhamento só aparece onde foi adicionada uma tabela ou um seletor de produto:

{"artikelnummer": "5100110", "menge": 20, "note": "Please deliver in the morning", "orderer": "Jonas Berger", "company": "Sanitar Berger GmbH", "project": "Spitalstrasse 11", "locale": "de", "callback_url": "https://chat.skava.io/api/v1/custom-elements/interactions/…", "callback_token": "…"}

Três chaves sempre vêm de nós, então não as use você mesmo:

  • locale: o código de idioma do usuário. Responda nesse idioma; nós não traduzimos seus textos.
  • callback_url e callback_token: o callback para esta interação específica, veja abaixo. Eles só estão presentes quando a chamada vem de um chat.

Campos de contexto, como nome, empresa, projeto ou subchat, são preenchidos pelo próprio servidor, derivados do canal em que o elemento foi executado. Um cliente adulterado não pode reivindicar um nome de projeto diferente ali.

A resposta: o formato do cartão

Responda com 2xx e um objeto card. É exatamente isso que se torna o cartão no chat:

{"card": {"v": 1, "title": "Order BST-10001", "state": "pending", "status_text": "Order received", "icon": "package", "fields": [{"label": "Order number", "value": "BST-10001"}, {"label": "Expected", "value": "14/08/2026"}]}}

  • v (obrigatório): o inteiro 1. Como texto ("1"), é rejeitado. Sem ele, a resposta não conta como cartão e o mapeamento de resposta configurado no elemento é aplicado.
  • title: o título do cartão.
  • state: apenas cor e tom do ícone, um de ok, pending, warn, error. Um valor desconhecido volta para ok e você recebe uma dica.
  • status_text: texto livre que não interpretamos. Fica no topo do cartão e também aparece na lista de chats e em uma notificação push.
  • fields: uma lista de label e value. No máximo 20 entradas, label 80 caracteres, value 200, title e status_text 120 cada. Valores que são longos demais são encurtados, não rejeitados: um pedido não deve falhar por um detalhe.
  • icon: veja abaixo.

O que a Skava faz com seus textos antes que cheguem ao chat: quebras de linha e caracteres de controle são removidos (um caractere da direita para a esquerda poderia, caso contrário, inverter a exibição de um valor), crases são substituídas e qualquer coisa começando com [SKAVA: é neutralizada. A última impede que um valor do cartão seja lido como um elemento de chat diferente, por exemplo, uma solicitação de pagamento.

Links em campos, HTML e imagens não podem ser definidos. Um chat é um ambiente confiável, e um endereço clicável de um backend externo seria um convite para reconstruir uma página de login.

Os entradas do usuário pertencem ao servidor: eles aparecem no primeiro cartão e você não pode sobrescrevê-los. No chat, eles são o registro do que foi efetivamente enviado.

Ícones

Com icon, o cartão recebe sua própria marca no cabeçalho. Duas formas:

Um nome do conjunto incluído: package, package-check, package-open, box, boxes, truck, forklift, warehouse, settings, cog, gauge, wrench, hammer, drill, hard-hat, ruler, paint-roller, construction, clipboard-check, receipt, file-text, camera, clock, calendar-clock, circle-check, circle-alert, triangle-alert, send, mail-check, shopping-cart, credit-card, map-pin.

Ou seu próprio SVG como uma string. A partir dele, a Skava extrai apenas a geometria (path, circle, ellipse, rect, line, polyline, polygon com seus atributos numéricos) e constrói sua própria imagem. Scripts, estilos, referências externas, foreignObject e atributos de eventos são descartados; uma doctype ou uma entidade leva à rejeição; o arquivo pode ter no máximo 8 KiB e conter no máximo 16 formas. Cor, espessura do traço e tamanho são definidos pela Skava, para que um ícone não se disfarce de controle. Trabalhe com uma grade de 24 por 24.

Sem icon, a marca padrão permanece.

O callback: relatar estados posteriores

A chamada contém callback_url e callback_token. Use-os para relatar novos estados mais tarde:

POST <callback_url> com Authorization: Bearer <callback_token> e Content-Type: application/json, corpo de no máximo 32 KiB:

{"card": {"v": 1, "title": "Order BST-10001", "state": "pending", "status_text": "Shipped", "icon": "truck", "fields": [{"label": "Tracking number", "value": "DPD123456789"}]}, "seq": 3, "final": false}

Além do cartão, há três valores opcionais:

  • seq: seu contador próprio. Um relatório com valor menor ou igual é descartado para que dois relatórios não se sobreponham. Sem seq, o último a chegar prevalece.
  • final: encerra a interação. O token se torna inválido e nenhum outro cartão aparece. Também permitido na primeira resposta, para fluxos sem follow-ups.
  • notify: defina como false para publicar o cartão silenciosamente, sem contagem de não lidos e sem notificação. Para etapas intermediárias que não devem acordar ninguém. Sem isso, o cartão é uma mensagem perfeitamente normal.

Cada relatório se torna seu próprio cartão no chat, o anterior permanece. Assim fica legível qual estado foi reportado. Daí decorre uma recomendação: envie apenas o que mudou. Um cartão que repete número do pedido, itens e total pela quarta vez é apenas ruído para o leitor.

Dois limites: o mesmo relatório duas vezes não produz um segundo cartão, e uma interação pode publicar no máximo 50 cartões. Uma interação aceita relatórios por 90 dias.

Respostas às quais você deve reagir

  • 200 com {"result": "success", "updated": true, "seq": 3, "closed": false, "hints": []}. Leia as dicas: elas indicam o que foi encurtado ou descartado.
  • 401: token ou id de interação incorretos. Não repita a tentativa.
  • 410: interação encerrada ou expirada. Não repita a tentativa.
  • 422: cartão indisponível, com hints como motivo. Corrija primeiro.
  • 400 JSON inválido, 413 muito grande, 429 muitas requisições (tente novamente com backoff), 500 falha nossa, tente mais tarde.

Exemplo 1: um pedido com histórico de status

Etapa 1, a requisição para o seu backend:

POST https://api.example.com/v1/orders
Authorization: Bearer <your token>
{"artikelnummer": "5100110", "menge": 20, "orderer": "Jonas Berger", "company": "Sanitar Berger GmbH", "locale": "de", "callback_url": "https://chat.skava.io/api/v1/custom-elements/interactions/1111…", "callback_token": "secret"}

Etapa 2, a sua resposta imediata:

{"card": {"v": 1, "title": "Order BST-10001", "state": "pending", "status_text": "Order received", "icon": "package", "fields": [{"label": "Order number", "value": "BST-10001"}, {"label": "Expected", "value": "14/08/2026"}]}}

O chat agora exibe um cartão com um ícone de pacote, o status e as entradas do usuário.

Etapa 3, mais tarde durante a seleção:

POST <callback_url> to {"card": {"v": 1, "title": "Order BST-10001", "state": "pending", "status_text": "Being picked", "icon": "cog", "fields": []}, "seq": 2, "notify": false}

Um segundo cartão discreto, sem campos: apenas o status mudou.

Etapa 4, no envio:

POST <callback_url> to {"card": {"v": 1, "title": "Order BST-10001", "state": "pending", "status_text": "Shipped", "icon": "truck", "fields": [{"label": "Tracking number", "value": "DPD123456789"}, {"label": "Carrier", "value": "DPD"}]}, "seq": 3}

Este cartão pode acordar alguém, por isso não há notify: false.

Etapa 5, na entrega:

POST <callback_url> to {"card": {"v": 1, "title": "Order BST-10001", "state": "ok", "status_text": "Delivered", "icon": "package-check", "fields": []}, "seq": 4, "final": true}

Com final, a interação é encerrada e o token deixa de funcionar.

Exemplo 2: uma ação sem follow-ups

Nem todo fluxo tem histórico. Um elemento com um único campo que envia algo para o seu sistema precisa apenas de uma resposta:

{"card": {"v": 1, "title": "Filed", "state": "ok", "status_text": "Stored under project 4711", "icon": "clipboard-check", "fields": [{"label": "Case", "value": "4711"}]}, "final": true}

final: true é importante aqui: caso contrário, a interação permaneceria aberta por 90 dias com um token válido, mesmo que você nunca mais reporte nada.

Seletor de produtos do catálogo

Depois que a empresa carrega seu catálogo de artigos, o elemento pode conter o bloco seletor de produtos. O usuário monta um carrinho a partir dele, e você o recebe como uma lista sob a chave escolhida por quem criou o elemento:

{"items": [{"artikelnummer": "5100110", "menge": 20}, {"artikelnummer": "5100111", "menge": 2}], "note": "…"}

Como a chave é livre, procure a primeira lista que tenha esse formato, em vez de um nome fixo. Antes de enviar, o Skava verifica se cada número realmente existe no catálogo daquela empresa, com no máximo 50 itens. No cartão, os itens aparecem como uma lista com imagem do produto, nome e quantidade.

Testes

  • O Ping no editor de elementos envia um HEAD puro, sem token e sem dados. Responda com qualquer coisa; qualquer resposta HTTP conta como acessível.
  • A Requisição de teste dispara uma chamada real com valores de exemplo, mesmo enquanto o elemento ainda é um rascunho, e exibe a requisição, a resposta e as mensagens do validador do cartão.
  • Pré-visualização na aba ao lado: cole o JSON da resposta, verifique e veja o cartão finalizado com as dicas. A validação é feita no servidor com o mesmo código usado em produção.
  • Servidor de exemplo: um fornecedor de exemplo completo está em execução em api.skava.io e utiliza tudo o que foi descrito acima. O código-fonte está no repositório em example_order_server/, com cerca de 600 linhas de biblioteca padrão pura, feito para ser copiado.

O que mais você deve saber

  • O cartão é uma mensagem de chat perfeitamente normal. Ele aparece na busca, pode ser citado e permanece no histórico.
  • É enviado pelo remetente do sistema, não por uma conta da sua empresa. Ainda assim, aparece do lado de quem executou o elemento, e o título indica qual sistema está escrevendo.
  • Quem pode executá-lo é definido no elemento: apenas membros da empresa ou também pessoas externas que compartilham um chat com ele. Quando sua empresa sai do chat, a permissão termina automaticamente.
  • Um elemento de API com token expirado fica inativo: os aplicativos atuais o ocultam no menu e uma chamada enviada mesmo assim é rejeitada no servidor. Um administrador salva um novo token para ele, o que também funciona em uma interface liberada.

Relacionados

Criar e liberar: Elementos personalizados: interfaces de API. Documentos preenchíveis em vez de interfaces: Elementos personalizados: documentos.