Documentação para Desenvolvedores

Conecte o seu próprio software à sua caixa de entrada SyBox

Envie mensagens do WhatsApp do seu próprio número, mostre os dados dos seus clientes ao lado de cada chat, registre casos, receba todos os eventos no seu próprio servidor e coloque um chat ao vivo no seu site. A rota de envio usa o formato da WhatsApp Cloud API, então um código escrito para a Meta só precisa de uma nova URL base e de uma chave do SyBox.

URL basehttps://api.sybox.io

Primeiros passos

Início Rápido

Três coisas e sua primeira mensagem estará a caminho: a URL base, uma chave de dispositivo e o endpoint de mensagens.

POST/v26.0/{phone-number-id}/messagesAuthorization: Bearer <DEVICE_KEY>

O segmento de versão é aceito em qualquer formato v<n> (v26.0, v1.0, …) — mantenha o que seu código atual usa. O {phone-number-id} é o ID do seu número de WhatsApp, exatamente como na Meta.

O {phone-number-id} aparece depois de id no cartão do número em Configurações › Mensagens › Canais. Uma chave de envio fica vinculada a um número e envia apenas a partir dele.

cURL
curl -X POST https://api.sybox.io/v26.0/PHONE_NUMBER_ID/messages \
  -H "Authorization: Bearer YOUR_DEVICE_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "messaging_product": "whatsapp",
    "to": "15551234567",
    "type": "text",
    "text": { "body": "Hello from SyBox" }
  }'

O cartão de cada chave em Configurações › Integrações › Chaves de API mostra quando ela foi usada pela última vez — a forma mais rápida de ver se as suas chamadas estão chegando.

Primeiros passos

Autenticação e chaves

Toda chamada leva uma chave no cabeçalho Authorization como token Bearer. Cada chave tem uma única função: uma chave criada para enviar não pode registrar um caso, e uma chave criada para registrar casos não pode enviar. Mantenha todas as chaves no seu servidor — a única exceção é a chave pública do Chat ao vivo, que foi feita para ficar nas suas páginas.

HTTP
Authorization: Bearer YOUR_KEY
Content-Type: application/json
ChavePara que serve
Enviar pelo WhatsAppPOST /v{n}/{phone-number-id}/messages
Registar uma reclamaçãoPOST /v1/case
Iniciar uma automaçãoPOST /v1/automation
Ler e atualizar contatosPOST /v1/contacts/…
Receber de um programaPOST /v1/inbound
Chave pública · lcpk_<script … data-key="lcpk_…">
Chave de assinatura para usuários conectados · lcid_Usuários conectados: a chave de assinatura
Chave do servidor (para sua própria tela de chat) · lcsk_/v1/livechat/*
Chave de assinatura de respostas · lcwh_x-sybox-signature
Chave de assinaturaX-Hub-Signature-256

Primeiros passos

Obtendo uma chave de dispositivo

As chaves são criadas dentro do seu espaço de trabalho.

  1. Abra seu espaço de trabalho → Configurações → Chaves de API.
  2. Cada chave está vinculada a um número e pode ser revogada a qualquer momento.
  3. Seu token real do WhatsApp nunca sai do nosso servidor.
  4. O gateway vem desativado por padrão.

API do WhatsApp

Envie sua primeira mensagem

Uma mensagem em texto simples. O corpo é o payload padrão da Cloud API.

POST/v26.0/{phone-number-id}/messagesAuthorization: Bearer <DEVICE_KEY>
curl -X POST https://api.sybox.io/v26.0/PHONE_NUMBER_ID/messages \
  -H "Authorization: Bearer YOUR_DEVICE_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "messaging_product": "whatsapp",
    "to": "15551234567",
    "type": "text",
    "text": { "body": "Hello from SyBox" }
  }'

A Resposta

Você recebe de volta exatamente o que a Meta retorna, com o mesmo status HTTP.

200 OK · application/json
{
  "messaging_product": "whatsapp",
  "contacts": [{ "input": "15551234567", "wa_id": "15551234567" }],
  "messages": [{ "id": "wamid.HBgLMTU1NTEyMzQ1NjcVAgARGBI…" }]
}

API do WhatsApp

Qualquer tipo de mensagem funciona

Como o corpo é encaminhado sem alterações, todos os tipos de mensagem da Cloud API são suportados.

{
  "messaging_product": "whatsapp",
  "to": "15551234567",
  "type": "template",
  "template": {
    "name": "order_shipped",
    "language": { "code": "en_US" },
    "components": [{
      "type": "body",
      "parameters": [{ "type": "text", "text": "#10432" }]
    }]
  }
}

Texto livre só chega a um cliente até 24 horas após a última mensagem dele. Fora dessa janela, envie um modelo aprovado: o SyBox recusa o texto livre nesse caso com o código 131047 antes que ele chegue à Meta.

API do WhatsApp

Regras e limites das chaves

Cada chave de envio tem as próprias regras, definidas quando você a cria: texto livre, modelos ou ambos; mídia ou não; quais modelos; quais países de destino; os horários em que pode enviar; e um limite diário. Um envio que desrespeita uma delas é recusado pelo SyBox antes de chegar à Meta.

StatusQuando
404Uma resposta vazia: o Gateway de API está desativado, ou a chave não pertence a nenhum workspace. Confira o botão no topo de Configurações › Integrações › Chaves de API.
401A chave está ausente ou não é reconhecida.
403A chave não é uma chave de envio ou está enviando de um número ao qual não está vinculada.
403A mensagem desrespeita uma das regras da chave: texto livre, modelos, mídia, o nome do modelo, o país ou os horários.
403A Meta pausou o modelo ou o limitou por causa da classificação de qualidade.
400A janela de 24 horas está fechada (código 131047): envie um modelo.
400O corpo não é um JSON válido, ou o número de WhatsApp da chave não está mais conectado.
409A Meta bloqueou o envio deste número por enquanto.
429O limite diário da chave, ou o limite de mensagens do WhatsApp do número, foi atingido.
502Não foi possível acessar a Meta. Tente novamente.

A contagem diária recomeça à meia-noite UTC, e um envio que falha não é contado.

API do WhatsApp

Erros

Os erros vêm de dois lugares, e ambos usam o formato de erro da Meta, então um cliente da Cloud API já existente os lê sem nenhuma mudança. Um erro da Meta volta exatamente como a Meta o enviou, com o código de status da Meta. Um erro de uma das regras do próprio SyBox tem o type SyBoxGatewayError, e a sua message informa qual regra recusou a chamada.

{
  "error": {
    "message": "(#131030) Recipient phone number not in allowed list",
    "type": "OAuthException",
    "code": 131030
  }
}

Seu sistema no SyBox

Mostre seus dados ao lado do chat

Quando um agente abre uma conversa, o SyBox chama SEU endpoint e exibe o que você retornar ao lado do chat.

Adicione o seu endpoint em Configurações › Integrações › APIs de ERP. Toda chamada é um POST com a sua chave em Authorization e a requisição em um único campo, data, que contém uma string JSON — assim qualquer um dos lados pode adicionar campos depois sem quebrar o outro. Responda em até 15 segundos.

POST YOUR_ERP_URL
Authorization: Bearer YOUR_ERP_KEY
X-Sybox-Action: lookup
X-Sybox-Lang: en
X-Sybox-Theme: light
X-Sybox-Agent: 6f1c…
X-Sybox-Number: 104857600000000
Content-Type: application/json

{ "data": "{\"phone\":\"15551234567\",\"email\":\"customer@example.com\",\"ref\":\"\"}" }

Cada chamada também informa quem está perguntando: X-Sybox-Lang (o idioma do usuário — responda nele), X-Sybox-Theme (light ou dark, para uma resposta html), X-Sybox-Agent (o id do usuário) e X-Sybox-Number (a linha em que a conversa está).

Enviamos telefone e e-mail — responda com { renderAs, content }.

renderAs

Defina renderAs para informar ao SyBox como exibir seu conteúdo:

renderAsDescrição
tableLinhas e colunas. content é um array de objetos simples (ou { rows: [ … ] }); as chaves deles viram os cabeçalhos das colunas.
cards · kpiBlocos pequenos, como um saldo ou uma contagem de pedidos. content é um array de { label, value } (ou { cards: [ … ] }).
feed · list · threadUma linha do tempo de cartões. content é um array de { title, text, date, tags, media: [{ type, url, name }] }.
messageUm registro exibido como um único cartão no estilo de mensagem.
htmlO seu próprio HTML, como uma string em content. Apenas para marcação que você mesmo gera.
sectionsVários blocos em uma só resposta: content é { sections: [ { title, renderAs, content } ] }.
jsonO padrão quando renderAs é omitido: o SyBox mostra o seu content como JSON formatado.

Adicione sybox_ref a qualquer linha de tabela para torná-la clicável.

Busca de produtos (X-Sybox-Action: products)

O mesmo endpoint também pode responder a buscas de produtos. O usuário digita o que o cliente está procurando, o SyBox envia como "q", e sua resposta é exibida como cartões de produto ao lado da conversa — com um botão Enviar de um toque que insere o link do produto no campo de mensagem.

POST YOUR_ERP_URL
Authorization: Bearer YOUR_ERP_KEY
X-Sybox-Action: products

# the decoded "data":
{ "q": "wireless keyboard", "phone": "15551234567", "email": "customer@example.com", "ref": "" }
CampoDescrição
nameobrigatórioO único campo obrigatório. Um produto só com nome ainda vira um cartão limpo.
price · oldPrice · currencyNúmeros, não textos formatados. Envie oldPrice apenas quando houver um preço anterior real — o desconto é calculado a partir dos dois.
available · stockavailable é true/false; stock é uma contagem opcional exibida ao lado. Omita ambos se você não controla estoque — um campo ausente não desenha nada e nunca é lido como esgotado.
imageUma URL de imagem https direta. Imagens que falham dão lugar a um fundo neutro.
linkA URL da página do produto. Sem ela o cartão é somente leitura — Enviar só aparece quando há algo a enviar.
noteUma linha livre curta sob o preço — prazo de entrega, variante, condição.

Nada além do endpoint que você já construiu: mesma URL, mesma chave, mesmo envelope { "data": "…" }. Use X-Sybox-Action para distinguir uma busca de produto de uma consulta de cliente. Responda com content como um array (ou { items: [ … ] }).

Seu sistema no SyBox

Abra um chamado a partir do seu sistema

Seu sistema solicita ao SyBox a abertura de um registro unificado de atendimento.

POST/v1/caseAuthorization: Bearer <CASE_KEY>
curl -X POST https://api.sybox.io/v1/case \
  -H "Authorization: Bearer $SYBOX_CASE_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "customer_unique_id": "CUST-10432",
    "header": "Screen replacement not delivered",
    "description": "Paid on 12 Aug, promised in 3 days, still nothing.",
    "department_id": 5,
    "ext_ref": "TICKET-99817"
  }'

Os campos

CampoDescrição
customer_unique_idO seu próprio id para o cliente — a mesma chave que a sincronização de clientes usa. Envie phone quando você não tiver um id.
phoneO número de telefone do cliente, quando você não tiver um id.
header · descriptionPelo menos um é obrigatório. O cabeçalho é a linha que os usuários veem na lista.
department_idobrigatóriointegerObrigatório. O departamento em que o caso está registrado: o número exibido ao lado em Configurações › Departamentos (por exemplo #5).
ext_refSeu número de chamado.
sectionintegerDe 1 a 4: em qual aba de casos ele entra. Padrão: 1.
deadlinestringUma data de vencimento, YYYY-MM-DD.
notifybooleanPadrão true: uma nota com o número do caso aparece na conversa do cliente no SyBox. Nada é enviado ao cliente. Com false, a nota não é criada.
sourcestringO nome do programa exibido nessa nota. Padrão: ERP.

A resposta traz o número do caso, aquele que a sua equipe informa ao cliente. Uma nova tentativa com o mesmo ext_ref responde "duplicate": true com o caso que já existe, sem customer_id.

O cliente já precisa estar no SyBox. Quando o id não é encontrado, o SyBox faz uma sincronização de clientes com o seu sistema e procura de novo; se ainda assim não o encontrar, a resposta é 404 — nunca um caso para um cliente inventado.

Use uma chave do tipo 'case'.

Seu sistema no SyBox

Envie mensagens de outro programa

Para qualquer canal externo: notas do PDV, alertas de dispositivos ou registros legados.

POST/v1/inboundAuthorization: Bearer <INBOUND_KEY>

Chaves desse tipo não são mais criadas: uma chave Receber de um programa que já existe continua funcionando. Para uma nova integração, registre um caso — o SyBox escreve a nota na conversa para você.

cURL
curl -X POST https://api.sybox.io/v1/inbound \
  -H "Authorization: Bearer $SYBOX_INBOUND_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "phone": "15551234567",
    "text": "Order 4821 has left the warehouse.",
    "source": "Warehouse"
  }'
CampoDescrição
phoneobrigatóriostringO número de telefone do cliente, com o código do país.
textobrigatóriostringA mensagem.
sourcestringO nome do programa, exibido na mensagem.

A resposta é {"ok": 1, "id": …}, o id da nota na conversa.

Somente entrada por design. Esta rota escreve na conversa.

Seu sistema no SyBox

Contatos: ler e atualizar

Com uma chave do tipo Ler e atualizar contatos, um programa pode encontrar um contato, lê-lo e alterar seu nome, e-mail, campos de contato e etiquetas. Cada chamada é um POST com um corpo JSON.

A chave age em nome da pessoa que a criou: ela encontra apenas os contatos que essa pessoa pode ver, e somente se essa pessoa puder abrir a lista de contatos e ver os números. Para alterar qualquer coisa, essa pessoa precisa ter permissão para editar contatos. Uma chave cujo criador for desativado deixa de funcionar.

POST/v1/contacts/searchAuthorization: Bearer <CONTACTS_KEY>

Encontra contatos cujo nome, telefone ou e-mail contenha q. limit é 20 por padrão, no máximo 50.

POST/v1/contacts/get

Um contato, por phone ou por key (o mesmo contact.key que um webhook envia).

POST/v1/contacts/update

Altera apenas o que você envia: name, email e fields (campos de contato por id ou por nome, com seus valores; um valor vazio limpa o campo).

POST/v1/contacts/labels

Adiciona e remove etiquetas por id ou por nome: add e remove são listas.

curl -X POST https://api.sybox.io/v1/contacts/update \
  -H "Authorization: Bearer $SYBOX_CONTACTS_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "phone": "201112223344",
    "name": "Sara Ali",
    "fields": { "city": "Alexandria" }
  }'

# Find:   POST /v1/contacts/search  {"q": "sara", "limit": 20}
# Read:   POST /v1/contacts/get     {"phone": "201112223344"}
# Labels: POST /v1/contacts/labels  {"phone": "201112223344", "add": ["VIP"], "remove": [7]}

Cada chamada responde com o contato (search: uma lista deles): key, name, phone, email, channel, labels e fields.

Eventos

Webhooks: eventos no seu servidor

Adicione o seu endpoint em Configurações › Integrações › Webhooks, escolha os eventos e os números, e o SyBox envia cada evento para ele via POST assim que acontece. Um evento do WhatsApp chega no próprio formato de webhook da Meta, então um handler escrito para a Meta funciona sem mudanças.

EventoDescrição
messageMensagem recebidaUma mensagem de um cliente.
statusEstado da mensagemEnviada, entregue, lida ou com falha — para uma mensagem que você enviou.
reactionReaçãoUm cliente reagiu a uma mensagem.
doneConversa marcada como concluídaUma conversa foi marcada como concluída: por uma pessoa, por uma automação ou automaticamente após o silêncio do cliente.
labelEtiqueta adicionada ou removidaUma etiqueta foi adicionada a uma conversa ou removida dela.
contactContato criado ou atualizadoUm contato foi criado ou seu nome, e-mail ou campos de contato foram alterados.
dealNegócio fechadoUm negócio fechado foi registrado em uma conversa.
caseCaso de CRM aberto ou fechadoUm caso de CRM foi aberto ou fechado (resolvido, não resolvido ou cancelado).
Requisição · SyBox → você
POST YOUR_WEBHOOK_URL
Content-Type: application/json
X-Hub-Signature-256: sha256=5d1f0c…
x-sybox-signature: sha256=5d1f0c…
x-sybox-event: message
x-sybox-timestamp: 1761400000

{
  "object": "whatsapp_business_account",
  "entry": [{
    "id": "WABA_ID",
    "changes": [{
      "field": "messages",
      "value": {
        "messaging_product": "whatsapp",
        "metadata": { "display_phone_number": "15550001111", "phone_number_id": "PHONE_NUMBER_ID" },
        "contacts": [{ "profile": { "name": "Sara" }, "wa_id": "15551234567" }],
        "messages": [{
          "from": "15551234567",
          "id": "wamid.HBgLMTU1NTEyMzQ1NjcVAgASGBQ…",
          "timestamp": "1761400000",
          "type": "text",
          "text": { "body": "Is my order shipped?" }
        }]
      }
    }]
  }]
}

Mídia. O link da própria Meta precisa de um token da Meta para abrir, então o SyBox o substitui por um link assinado para a sua própria cópia do arquivo, válido por 24 horas. Uma mensagem de voz também pode trazer as palavras em sybox.transcription, quando o webhook as solicita.

Outros canais — Messenger, Instagram, Telegram e Chat ao vivo — chegam no formato próprio do SyBox, apenas para o evento de mensagem:

JSON
{
  "object": "sybox",
  "event": "message",
  "channel": "telegram",
  "line": "8123456789",
  "workspace": "yourworkspace",
  "contact": { "key": "tg:6423115118", "name": "Sara" },
  "message": {
    "id": "812345",
    "timestamp": 1761400000,
    "type": "image",
    "text": "",
    "caption": "The broken part",
    "media": { "url": "https://api.sybox.io/…", "mime": "image/jpeg" }
  }
}

Os eventos de conversa chegam no formato próprio do SyBox, para todos os canais. event informa exatamente o que aconteceu:

Evento<code>event</code>
Conversa marcada como concluídaconversation.done
Etiqueta adicionada ou removidalabel.added · label.removed
Contato criado ou atualizadocontact.created · contact.updated
Negócio fechadodeal.closed
Caso de CRM aberto ou fechadocase.opened · case.closed
Evento de testetest
{
  "object": "sybox",
  "event": "conversation.done",
  "channel": "whatsapp",
  "line": "201001234567",
  "workspace": "yourworkspace",
  "timestamp": 1761400000,
  "contact": {
    "key": "201112223344",
    "name": "Sara",
    "phone": "201112223344",
    "email": "",
    "channel": "whatsapp",
    "labels": [{ "id": 3, "name": "VIP" }],
    "fields": [{ "id": 2, "key": "city", "name": "City", "value": "Cairo" }]
  },
  "data": { "by": "Omar", "note": "Refund sent" }
}

Chave de assinatura

CabeçalhoDescrição
X-Hub-Signature-256sha256= e o HMAC-SHA256 em hexadecimal do corpo bruto, com o segredo de assinatura do webhook como chave — o mesmo cabeçalho e o mesmo método da Meta.
x-sybox-signatureO mesmo valor, para que um endpoint que também recebe as chamadas da própria Meta consiga distinguir as nossas.
x-sybox-eventO que aconteceu: message, status, reaction, um dos eventos de conversa abaixo (conversation.done, label.added…) ou test.
x-sybox-timestampQuando foi enviado, em segundos Unix.
x-sybox-signature-rsaUma segunda assinatura: rsa-sha256= e o RSA-SHA256 (PKCS#1 v1.5) em base64 de x-sybox-timestamp, um ponto e o corpo bruto.
x-sybox-key-idQual das nossas chaves a gerou. A chave pública está em https://api.sybox.io/.well-known/sybox-webhook-key.

Verifique a assinatura nos bytes brutos, antes de interpretá-los, e compare em tempo constante:

const crypto = require('crypto');

// express.raw: the signature is over the bytes as sent, so read them before any JSON parser.
app.post('/sybox/webhook', express.raw({ type: 'application/json' }), (req, res) => {
  const sent = Buffer.from(req.get('X-Hub-Signature-256') || '');
  const want = Buffer.from('sha256=' + crypto
    .createHmac('sha256', process.env.SYBOX_WEBHOOK_SECRET)
    .update(req.body)
    .digest('hex'));
  if (sent.length !== want.length || !crypto.timingSafeEqual(sent, want)) return res.sendStatus(401);

  res.sendStatus(200);                       // answer first, then do the work
  const event = JSON.parse(req.body);
  const kind = req.get('x-sybox-event');     // message | status | reaction
});

Prefere não guardar um segredo compartilhado no seu servidor? Verifique x-sybox-signature-rsa com a nossa chave pública. Em qualquer caso, recuse um timestamp com mais de cinco minutos.

Responda com qualquer 2xx em até 15 segundos. Qualquer outra coisa — um erro, um tempo esgotado, um redirecionamento — é tentada novamente após 1, 2, 4, 8, 16 e 32 minutos e depois descartada. Um evento pode chegar mais de uma vez: use o id da mensagem para ignorar uma repetição. O endereço precisa ser público e https.

Um webhook que falha 20 vezes seguidas, por mais de uma hora, é desativado automaticamente e o administrador do espaço de trabalho é avisado. Os eventos pendentes são mantidos por 24 horas: ative-o novamente para enviá-los.

Para testar, pressione Enviar evento de teste no cartão do webhook. Entregas, no mesmo cartão, lista as últimas 50 entregas com a resposta do seu servidor e permite enviar uma novamente.

Chat ao vivo

Chat ao vivo

Coloque um chat no seu site: os visitantes escrevem lá, e a sua equipe responde no SyBox. Adicione o site em Configurações › Mensagens › Canais, no cartão Chat ao vivo; a janela que se abre, Código para o seu site, mostra o código e as chaves abaixo. As três chaves secretas são exibidas apenas uma vez.

ChaveComeça comPara que serve
Chave públicalcpk_Vai nas suas páginas. Pode ser publicada com segurança: ela apenas identifica o site, e o chat só aparece nos seus Endereços do site.
Chave de assinatura para usuários conectadoslcid_Somente no seu servidor. Assina cada usuário conectado, para que ninguém possa escrever como outra pessoa.
Chave do servidor (para sua própria tela de chat)lcsk_Somente no seu servidor. Apenas para um site que cria a própria tela de chat em vez de usar o chat pronto.
Chave de assinatura de respostaslcwh_Somente no seu servidor. Comprova que uma resposta enviada ao seu servidor veio do SyBox.

O chat pronto precisa apenas do código. A chave de assinatura é para um site com contas de usuário; a chave do servidor e a chave de assinatura de respostas, apenas para um site com a própria tela de chat.

Desativar um site oculta o chat na hora. As chamadas do seu servidor continuam sendo aceitas e armazenadas.

Adicione o chat ao seu site

Cole o código uma vez em todas as páginas, logo antes da tag de fechamento do body. O chat só aparece nos endereços em Endereços do site, e a cor, a posição, o título e a mensagem de boas-vindas são definidos no SyBox, não no código.

HTML
<script async src="https://api.sybox.io/lc/w.js" data-key="lcpk_YOUR_PUBLIC_KEY"></script>

WordPress: baixe o nosso plugin na mesma janela. Shopify: no app Shopify do SyBox, ative Chat ao vivo nesta loja e depois SyBox Live Chat em Incorporações de app (App embeds) — um cliente conectado é reconhecido sem que você precise fazer mais nada.

Usuários conectados: a chave de assinatura

Quando um usuário está conectado ao seu site, o seu servidor informa ao chat quem ele é com um token curto — um JWT, HS256 — assinado com a chave de assinatura. Assim o usuário tem uma única conversa em seu nome, em todos os dispositivos, e ninguém consegue abri-la digitando o id de outra pessoa.

  1. Depois do login, o seu servidor monta o token com as claims abaixo.
  2. A página o passa para o chat como identity, antes do código do chat.
  3. Depois de um login sem recarregar a página, chame SyBoxChat('identify', token).
CampoDescrição
subobrigatóriostringO id do seu usuário, com até 120 caracteres. Ele não pode começar com v_.
expobrigatórionumberValidade, em segundos Unix — no máximo um dia à frente. Dez minutos é o ideal: o token só é lido quando o chat abre.
namestringO nome exibido na conversa.
emailstringO endereço de e-mail do usuário.
phonestringO número de telefone do usuário.
picturestringUm endereço https da foto do usuário, com até 500 caracteres. O SyBox guarda a própria cópia e a busca novamente no próximo login quando o endereço muda.
function b64url(string $s): string { return rtrim(strtr(base64_encode($s), '+/', '-_'), '='); }

$header  = b64url(json_encode(['alg' => 'HS256', 'typ' => 'JWT']));
$payload = b64url(json_encode([
    'sub'   => (string) $user->id,
    'name'  => $user->name,
    'email' => $user->email,
    'exp'   => time() + 600,          // ten minutes
]));
$signature = b64url(hash_hmac('sha256', "$header.$payload", getenv('SYBOX_LC_SIGNING_KEY'), true));
$token = "$header.$payload.$signature";
HTML
<script>
  window.SyBoxChatConfig = { identity: "TOKEN_FROM_YOUR_SERVER", locale: "en" };
</script>
<script async src="https://api.sybox.io/lc/w.js" data-key="lcpk_YOUR_PUBLIC_KEY"></script>

Gere o token somente no seu servidor. Uma chave de assinatura em uma página da web permite que qualquer pessoa escreva como qualquer um dos seus usuários. E nunca coloque um id de usuário puro na página no lugar do token: isso permitiria que qualquer pessoa escolhesse de quem é a conversa que vai ler.

Com Apenas usuários conectados ao meu site ativado, um visitante sem token não vê o chat.

Um visitante que conversou antes de fazer login recebe uma única pergunta, no mesmo navegador, se quer continuar aquela conversa com a conta dele. Você não precisa fazer nada para isso.

Controle o chat a partir da sua página

O código do chat adiciona uma função à sua página, SyBoxChat:

JavaScript
SyBoxChat('open');                       // open the chat
SyBoxChat('close');                      // close it
SyBoxChat('identify', token);            // after a sign-in without a page reload
SyBoxChat('locale', 'fr');               // the chat's language
SyBoxChat('on', 'message', function (m) {
  // a reply arrived
});
SyBoxChat('on', 'open', function () { /* the chat opened */ });
SyBoxChat('on', 'close', function () { /* the chat closed */ });

// Before the chat's code, every setting is optional:
window.SyBoxChatConfig = {
  identity: 'TOKEN_FROM_YOUR_SERVER',    // a signed-in user (see above)
  name: 'Sara', email: 'sara@example.com', // a visitor without an account: fills the form for them
  locale: 'ar',
  serviceWorker: 'auto'                   // 'auto' | '/your-sw.js' | 'site' | 'off'
};

Notificações depois que o seu site é fechado

Enquanto uma página do seu site está aberta, uma resposta aparece como notificação automaticamente. Para alcançar um visitante depois que o seu site é fechado, os navegadores exigem um service worker no seu próprio domínio: sirva esta única linha como /sybox-lc-sw.js na raiz do seu site, como application/javascript.

/sybox-lc-sw.js
try { importScripts('https://api.sybox.io/lc/sw.js'); } catch (e) {}

Escolha o modo no SyBox (Notificações com o site fechado) ou na página com serviceWorker: "auto" (o arquivo acima, o padrão), um caminho próprio, "site" (coloque a mesma linha no início do seu próprio service worker) ou "off".

O chat nunca substitui um service worker que o seu site já tenha, e o arquivo não tem handler de fetch, então nunca vê uma requisição do seu site. O plugin do WordPress serve o arquivo para você. O Safari do iPhone não mostra notificações de um site comum.

A sua própria tela de chat: a chave do servidor

Um site ou app com a própria tela de chat se comunica com o SyBox a partir do seu servidor, em vez de usar o chat pronto. Toda chamada leva Authorization: Bearer lcsk_…. O seu servidor identifica o usuário pelo seu próprio id, e é confiável para isso, porque guarda a chave.

ChamadaDescrição
POST /v1/livechat/messagesO seu usuário escreve. client_id torna uma nova tentativa segura: o mesmo id é guardado uma única vez ("duplicate": 1).
POST /v1/livechat/uploadUm arquivo, como dados de formulário multipart: file, user_id, client_id. Até 16 MB: imagens, voz, vídeo, PDF, texto e documentos do Office.
GET /v1/livechat/messages?user_id=&since=&before=&limit=A conversa: as mensagens depois de since, e agents_read_id, a mais recente das mensagens do seu usuário que um agente leu.
POST /v1/livechat/readO seu usuário leu as respostas até up_to.
POST /v1/livechat/editO seu usuário edita a própria mensagem, em até 15 minutos.
POST /v1/livechat/deleteO seu usuário apaga a própria mensagem para todos, em até 24 horas.
POST /v1/livechat/reactUma reação em qualquer mensagem; um emoji vazio a remove.
POST /v1/livechat/typingO seu usuário está digitando: envie on: 1 a cada poucos segundos e on: 0 quando ele parar.
curl -X POST https://api.sybox.io/v1/livechat/messages \
  -H "Authorization: Bearer $SYBOX_LC_SERVER_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "user":    { "id": "u42", "name": "Sara Ali", "email": "sara@example.com", "locale": "ar" },
    "message": { "client_id": "a1b2c3", "text": "Hi, is my order on its way?", "reply_to": "" }
  }'

Uma mensagem, no histórico e nas respostas:

JSON
{
  "id": 990,
  "guid": "b81d…",
  "dir": "out",                       // "in" = your user wrote it, "out" = your team
  "type": "image",                    // text | image | audio | video | file
  "text": "Here is the tracking page",
  "media": { "url": "https://api.sybox.io/…", "mime": "image/png", "name": "tracking.png", "w": 1080, "h": 720 },
                                       // a voice note or a video also has "secs"
  "status": 3,                         // on your user's messages: 1 received, 3 read by an agent
  "reply_to": "7c9e…",
  "client": "a1b2c3",                  // on your user's messages: the client_id you sent
  "react_us": "",                      // your team's reaction on it
  "react_me": "👍",                    // your user's reaction on it
  "at": "2026-10-25T09:41:07Z",
  "edited": 0
}

O histórico de um usuário que nunca escreveu responde 404 unknown_user: mostre uma conversa vazia.

Os links de mídia são assinados e funcionam por uma hora; peça novamente para obter um novo. O SyBox nunca busca um arquivo a partir de um endereço que você envia: faça o upload dele. Até 120 chamadas por minuto por site.

Respostas no seu servidor: a chave de assinatura de respostas

Informe o Endereço do seu servidor para respostas no site. Quando a sua equipe responde, edita, apaga ou lê, o SyBox envia o evento para lá via POST, assinado com a chave de assinatura de respostas.

CabeçalhoDescrição
x-sybox-signaturet=TIMESTAMP,v1=SIGNATURE — TIMESTAMP em segundos Unix, SIGNATURE o HMAC-SHA256 em hexadecimal de TIMESTAMP.BODY (o body bruto), com a chave de assinatura de respostas como chave.
x-sybox-eventmessage.created, message.updated, message.deleted ou messages.read.
x-sybox-deliveryO mesmo em todas as novas tentativas de um evento: use-o para ignorar uma repetição.

O corpo contém event, line_id, user_id e message — ou message_id para uma exclusão, e read_id para messages.read: as mensagens do seu usuário foram lidas até esse id.

const crypto = require('crypto');

app.post('/sybox/livechat', express.raw({ type: 'application/json' }), (req, res) => {
  const parts = Object.fromEntries((req.get('x-sybox-signature') || '').split(',').map(p => p.split('=')));
  const t = Number(parts.t);
  if (!t || Math.abs(Date.now() / 1000 - t) > 300) return res.sendStatus(401);   // older than five minutes

  const want = Buffer.from(crypto.createHmac('sha256', process.env.SYBOX_LC_REPLY_KEY)
    .update(t + '.').update(req.body).digest('hex'));
  const sent = Buffer.from(parts.v1 || '');
  if (sent.length !== want.length || !crypto.timingSafeEqual(sent, want)) return res.sendStatus(401);

  res.sendStatus(200);
  const delivery = req.get('x-sybox-delivery');   // seen it already? ignore
  const evt = JSON.parse(req.body);               // { event, line_id, user_id, message | message_id | read_id }
});

Verifique a assinatura no corpo bruto, recuse um t com mais de cinco minutos e responda com 2xx rapidamente. Qualquer outra coisa é tentada novamente após 10 s, 30 s, 2 min, 10 min e 30 min e depois descartada. O SyBox chama apenas endereços públicos e nunca segue um redirecionamento.

Códigos de motivo

Toda resposta do Chat ao vivo é JSON — {"ok": 1, …}, ou {"ok": 0, "error": "CODE"} com um código em vez de uma frase:

CódigoStatusDescrição
unauthorized401A chave do servidor está errada ou foi substituída.
invalid_json invalid_payload invalid_user_id400A requisição não está no formato esperado.
empty_message no_file empty_file400Nenhum texto e nenhum arquivo.
too_long400O texto editado passa de 4.096 caracteres.
not_an_emoji400emoji não é um emoji.
not_found404Essa mensagem não existe, ou não é deste usuário.
too_late409O prazo para editar ou excluir já passou.
file_type_not_allowed400Este tipo de arquivo não é aceito.
file_too_large413O arquivo tem mais de 16 MB.
blocked403A sua equipe bloqueou este usuário.
unknown_user404Ainda não há conversa para este id de usuário.
rate_limited429Chamadas demais: diminua o ritmo e tente novamente.
maintenance503O SyBox está sendo atualizado: tente novamente após Retry-After segundos.
server_error500Algo falhou do nosso lado.

Substituir uma chave

Perdeu uma chave ou acha que ela vazou? No cartão do site, clique em Nova chave de assinatura, Nova chave do servidor ou Nova chave de assinatura de respostas. Uma nova chave do servidor mantém a antiga funcionando por um dia, para que você faça a troca sem interrupção; as outras chaves param na hora.