Como incorporar o AnnA Chat com um usuário corporativo V2
Este guia mostra como incorporar o AnnA Chat para um usuário corporativo autenticado usando a API V2. O navegador recebe somente a URL gerada do AnnA Chat. Mantenha o hash da empresa, as chaves de criptografia e descriptografia, os dados do usuário e todas as chamadas da API V2 no seu backend.
Antes de começar
Seção intitulada “Antes de começar”Você precisa das seguintes informações do seu ambiente AnnA:
- O hash da empresa.
- As chaves de criptografia e descriptografia do usuário corporativo.
- O ID do usuário corporativo.
- A URL base do seu ambiente AnnA.
A integração V2 usa criptografia 3DES no modo CBC. Consulte Criptografia para ver os requisitos de criptografia e os métodos auxiliares usados nos exemplos.
Fluxo de integração
Seção intitulada “Fluxo de integração”- Seu backend envia uma requisição
GENERATE_USER_HASHcriptografada paraaannacorporateuser.aspx. - Seu backend define
GET_ANNA_CHAT_LINKcomoSpara que a AnnA retorne os links do chat. - Seu backend descriptografa a resposta e lê a propriedade
AnnAChatURL. - Seu código no cliente usa essa URL gerada como origem do iframe.
A URL gerada pode expirar. Gere-a no servidor para o usuário conectado e não coloque o hash da empresa ou as chaves de criptografia no código do navegador.
Resposta da AnnA
Seção intitulada “Resposta da AnnA”Depois de descriptografar a resposta, analise o JSON retornado pela AnnA. A propriedade AnnAChatURL é a URL que deve ser usada no iframe.
{ "Status": "OK", "Message": "User Hash generated successfully", "Hash": "USER_HASH", "ChatURL": "CHAT_URL_WITH_USER_HASH", "EmbeddedURL": "EMBEDDED_URL_WITH_USER_HASH", "AnnAChatURL": "ANNACHAT_URL_FOR_IFRAME", "Expires": "EXPIRATION_DATETIME"}Se a resposta não indicar sucesso, trate o valor de Message no backend e não envie uma URL inválida ao navegador.
Exemplo completo
Seção intitulada “Exemplo completo”Substitua ANNACHAT_URL_FROM_BACKEND pelo valor de AnnAChatURL retornado pelo seu backend. O botão cria a janela do chat somente depois que o usuário clica nele.
<!doctype html><html lang="pt-BR"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Demo do AnnA Chat incorporado</title> </head> <body> <h1>Site do cliente corporativo</h1> <p>O widget autenticado do AnnA Chat aparece no canto inferior direito.</p>
<script> (function () { const ANNA_URL = "ANNACHAT_URL_FROM_BACKEND"; // Use o valor AnnAChatURL gerado pelo backend const CHAT_W = 400, CHAT_H = 600, BTN_SIZE = 60; const sideOffset = "clamp(16px, 2.2vw, 30px)"; const bottomOffset = "clamp(16px, 2.2vw, 30px)";
const btn = document.createElement("div"); btn.id = "anna-launcher"; Object.assign(btn.style, { position: "fixed", bottom: bottomOffset, right: sideOffset, width: BTN_SIZE + "px", height: BTN_SIZE + "px", borderRadius: "50%", cursor: "pointer", zIndex: "9999", background: "#7c3aed", display: "flex", alignItems: "center", justifyContent: "center", boxShadow: "0 4px 12px rgba(0,0,0,0.25)", transition: "transform 0.2s", }); btn.innerHTML = '<svg width="28" height="28" fill="#fff" viewBox="0 0 24 24"><path d="M20 2H4a2 2 0 0 0-2 2v18l4-4h14a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2z"/></svg>'; btn.onmouseenter = function () { btn.style.transform = "scale(1.1)"; }; btn.onmouseleave = function () { btn.style.transform = "scale(1)"; };
const chat = document.createElement("div"); chat.id = "anna-chat"; Object.assign(chat.style, { position: "fixed", bottom: `calc(${bottomOffset} + ${BTN_SIZE}px + 10px)`, right: sideOffset, width: `min(${CHAT_W}px, calc(100vw - 32px))`, height: CHAT_H + "px", maxHeight: `min(${CHAT_H}px, calc(100vh - 116px))`, borderRadius: "12px", overflow: "hidden", boxShadow: "0 8px 30px rgba(0,0,0,0.3)", display: "none", zIndex: "9998", }); chat.innerHTML = '<iframe src="' + ANNA_URL + '" style="width:100%;height:100%;border:none" allow="camera *; microphone *; geolocation *"></iframe>';
btn.addEventListener("click", function () { var open = chat.style.display === "none"; chat.style.display = open ? "block" : "none"; });
document.body.appendChild(chat); document.body.appendChild(btn); })(); </script> </body></html>Gerar a URL do chat no backend
Seção intitulada “Gerar a URL do chat no backend”Envie a requisição para YOUR_ANNA_URL/aannacorporateuser.aspx com ACTION=GENERATE_USER_HASH e GET_ANNA_CHAT_LINK=S. Criptografe os campos exigidos pela API V2 usando a chave de criptografia e o IV da requisição. Descriptografe o payload retornado com o IV da resposta e leia AnnAChatURL no JSON.
Os auxiliares Encrypt, Decrypt, GenerateIV e DecryptAnnAResponse dos exemplos representam os métodos 3DES descritos em Criptografia. Eles devem ser executados no backend.
var requestIv = GenerateIV();var form = new NameValueCollection{ ["HASH"] = "YOUR_COMPANY_HASH", ["ANNAEXEC"] = requestIv, ["ACTION"] = Encrypt("GENERATE_USER_HASH", "ENCRYPTION_KEY", requestIv), ["USER_ID"] = Encrypt("USER_ID", "ENCRYPTION_KEY", requestIv), ["START_SERVICE"] = Encrypt("", "ENCRYPTION_KEY", requestIv), ["GET_ANNA_CHAT_LINK"] = "S"};
using (var client = new WebClient()){ client.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded"; var raw = Encoding.UTF8.GetString(client.UploadValues( "https://YOUR_ANNA_URL/aannacorporateuser.aspx", "POST", form)); var json = DecryptAnnAResponse(raw, requestIv, "ENCRYPTION_KEY", "DECRYPTION_KEY"); var response = JObject.Parse(json); if ((string)response["Status"] != "OK") throw new InvalidOperationException((string)response["Message"]); var annaChatUrl = (string)response["AnnAChatURL"];}using var http = new HttpClient();var requestIv = GenerateIV();var form = new Dictionary<string, string>{ ["HASH"] = "YOUR_COMPANY_HASH", ["ANNAEXEC"] = requestIv, ["ACTION"] = Encrypt("GENERATE_USER_HASH", "ENCRYPTION_KEY", requestIv), ["USER_ID"] = Encrypt("USER_ID", "ENCRYPTION_KEY", requestIv), ["START_SERVICE"] = Encrypt("", "ENCRYPTION_KEY", requestIv), ["GET_ANNA_CHAT_LINK"] = "S"};var result = await http.PostAsync( "https://YOUR_ANNA_URL/aannacorporateuser.aspx", new FormUrlEncodedContent(form));var json = DecryptAnnAResponse(await result.Content.ReadAsStringAsync(), requestIv, "ENCRYPTION_KEY", "DECRYPTION_KEY");using var response = JsonDocument.Parse(json);var annaChatUrl = response.RootElement.GetProperty("AnnAChatURL").GetString();var requestIv = generateInitializationVector();var form = "HASH=" + encode("YOUR_COMPANY_HASH") + "&ANNAEXEC=" + encode(requestIv) + "&ACTION=" + encode(encrypt3DES("GENERATE_USER_HASH", "ENCRYPTION_KEY", requestIv)) + "&USER_ID=" + encode(encrypt3DES("USER_ID", "ENCRYPTION_KEY", requestIv)) + "&START_SERVICE=" + encode(encrypt3DES("", "ENCRYPTION_KEY", requestIv)) + "&GET_ANNA_CHAT_LINK=S";var request = HttpRequest.newBuilder() .uri(URI.create("https://YOUR_ANNA_URL/aannacorporateuser.aspx")) .header("Content-Type", "application/x-www-form-urlencoded") .POST(HttpRequest.BodyPublishers.ofString(form)).build();var result = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());var json = decryptAnnAResponse(result.body(), requestIv, "ENCRYPTION_KEY", "DECRYPTION_KEY");var annaChatUrl = new ObjectMapper().readTree(json).get("AnnAChatURL").asText();<?php$requestIv = generateIV();$fields = [ "HASH" => "YOUR_COMPANY_HASH", "ANNAEXEC" => $requestIv, "ACTION" => encrypt3DES("GENERATE_USER_HASH", "ENCRYPTION_KEY", $requestIv), "USER_ID" => encrypt3DES("USER_ID", "ENCRYPTION_KEY", $requestIv), "START_SERVICE" => encrypt3DES("", "ENCRYPTION_KEY", $requestIv), "GET_ANNA_CHAT_LINK" => "S",];$curl = curl_init("https://YOUR_ANNA_URL/aannacorporateuser.aspx");curl_setopt_array($curl, [CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_POSTFIELDS => http_build_query($fields)]);$raw = curl_exec($curl);curl_close($curl);$response = json_decode(decryptAnnAResponse($raw, $requestIv, "ENCRYPTION_KEY", "DECRYPTION_KEY"), true, 512, JSON_THROW_ON_ERROR);if (($response["Status"] ?? "") !== "OK") throw new RuntimeException($response["Message"] ?? "AnnA request failed");echo $response["AnnAChatURL"] . PHP_EOL;&requestIv = GenerateIV()&body = !"HASH=" + UrlEncode(!"YOUR_COMPANY_HASH")&body += !"&ANNAEXEC=" + UrlEncode(&requestIv)&body += !"&ACTION=" + UrlEncode(Encrypt(!"GENERATE_USER_HASH", !"ENCRYPTION_KEY", &requestIv))&body += !"&USER_ID=" + UrlEncode(Encrypt(!"USER_ID", !"ENCRYPTION_KEY", &requestIv))&body += !"&START_SERVICE=" + UrlEncode(Encrypt(!"", !"ENCRYPTION_KEY", &requestIv))&body += !"&GET_ANNA_CHAT_LINK=S"&httpClient.Host = !"YOUR_ANNA_URL"&httpClient.Execute(!"POST", !"/aannacorporateuser.aspx", &body)&jsonText = DecryptAnnAResponse(&httpClient.ToString(), &requestIv, !"ENCRYPTION_KEY", !"DECRYPTION_KEY")&response.FromJson(&jsonText)&annaChatUrl = &response.AnnAChatURLimport jsonimport requests
request_iv = generate_iv()form = { "HASH": "YOUR_COMPANY_HASH", "ANNAEXEC": request_iv, "ACTION": encrypt_3des("GENERATE_USER_HASH", "ENCRYPTION_KEY", request_iv), "USER_ID": encrypt_3des("USER_ID", "ENCRYPTION_KEY", request_iv), "START_SERVICE": encrypt_3des("", "ENCRYPTION_KEY", request_iv), "GET_ANNA_CHAT_LINK": "S",}result = requests.post("https://YOUR_ANNA_URL/aannacorporateuser.aspx", data=form, timeout=30)result.raise_for_status()json_text = decrypt_anna_response(result.text, request_iv, "ENCRYPTION_KEY", "DECRYPTION_KEY")response = json.loads(json_text)if response.get("Status") != "OK": raise RuntimeError(response.get("Message", "AnnA request failed"))anna_chat_url = response["AnnAChatURL"]print(anna_chat_url)Use o valor retornado em AnnAChatURL como ANNACHAT_URL_FROM_BACKEND no exemplo do cliente. Não retorne o hash da empresa, as chaves de criptografia ou o hash descriptografado do usuário ao navegador.
Veja também
Seção intitulada “Veja também”- Como acessar — como o link corporativo se comporta para quem o utiliza.
- Requisitos e limites — requisitos de navegador e permissões.