Documentação

API e Webhooks

Tudo que você precisa para integrar, sem precisar de conta para ler. Cada cliente tem o próprio endereço de API, e a especificação OpenAPI fica no endereço dele.

1. Qual é o meu endereço

Não existe um host único de API. Cada conta é servida no próprio subdomínio, e ele já identifica o cliente: não há parâmetro de conta em nenhuma chamada, e uma credencial só funciona no endereço a que pertence.

https://sua-conta.voxli.com.br/api/v1/

Se a sua ouvidoria atende em domínio próprio, ele também serve. O endereço exato aparece em Configurações › API & Webhooks › Referência, já preenchido.

2. Autenticação e escopos

Token no header, em toda requisição:

Authorization: Bearer vxl_live_...

A chave é criada pelo administrador da conta e mostrada uma única vez. Cada chave carrega os escopos que você escolher, e um escopo que falta devolve 403 dizendo exatamente qual.

EscopoPermite
manifestations:readManifestações (leitura)
manifestations:writeManifestações (escrita)
lgpd:readLGPD (leitura)
lgpd:writeLGPD (escrita)
stats:readEstatísticas (leitura)
webhooks:manageWebhooks (gerenciar)
Chave de teste

Uma chave com prefixo vxl_test_ autentica e , mas recusa qualquer escrita com o código test_key_readonly. Ela enxerga os mesmos dados reais: serve para desenvolver a integração sem risco de criar manifestação de verdade, e não é um ambiente separado.

3. A primeira chamada

# Listar manifestações curl -H "Authorization: Bearer vxl_live_..." \ https://sua-conta.voxli.com.br/api/v1/manifestations/ # Resposta { "ok": true, "data": [ { "id": "3f9a1c20-...-c210", "protocol": "2026080087", "type": { "slug": "reclamacao", "name": "Reclamação" }, "status": "IN_REVIEW", "anonymous": true, "description": "...", "description_truncated": false, "created_at": "2026-08-31T14:02:11-03:00" } ], "meta": { "page": 1, "per_page": 20, "total": 128, "total_pages": 7 } }
# Criar e depois responder ao solicitante curl -X POST -H "Authorization: Bearer vxl_live_..." \ -H "Content-Type: application/json" \ -H "Idempotency-Key: $(uuidgen)" \ -d '{"type":"reclamacao","description":"Texto da manifestação"}' \ https://sua-conta.voxli.com.br/api/v1/manifestations/ curl -X POST -H "Authorization: Bearer vxl_live_..." \ -H "Content-Type: application/json" \ -d '{"message":"Recebemos e estamos apurando."}' \ https://sua-conta.voxli.com.br/api/v1/manifestations/{id}/reply/

4. Respostas e erros

Toda resposta tem a mesma forma. Sucesso traz ok, data e, nas listagens, meta. Erro traz code, message e request_id:

{ "ok": false, "error": { "code": "invalid_parameter", "message": "Parâmetro 'since' inválido: 'ontem' não é uma data ISO-8601.", "parameter": "since", "request_id": "9f1c...-4b2a" } }

O request_id vem também no header X-Voxli-Request-Id, em toda resposta — inclusive nas de erro e nas sem credencial. Cite-o ao abrir um chamado: é por ele que a requisição exata é localizada.

Códigos possíveis:

codeSignifica
delivery_pendingA entrega ainda está na fila.
empty_patchNenhum campo para alterar.
field_too_longCampo acima do limite.
idempotency_in_flightOutra requisição com o mesmo Idempotency-Key está em andamento.
insufficient_scopeA chave não tem o escopo. Veja `required_scope`.
internal_errorErro do lado da Voxli.
invalid_destinationURL de webhook recusada (precisa ser https e pública).
invalid_emailE-mail malformado.
invalid_eventsEvento de webhook desconhecido.
invalid_jsonO corpo não é JSON válido.
invalid_parameterUm filtro está ilegível. O campo `parameter` diz qual.
invalid_statusStatus fora do catálogo.
invalid_tokenA chave não existe nesta conta.
invalid_typeO tipo de manifestação não existe ou está inativo.
key_disabledA chave foi desativada no backoffice.
key_expiredA chave foi rotacionada e o prazo acabou.
missing_descriptionCampo 'description' ausente.
missing_eventsCampo 'events' ausente ou vazio.
missing_messageCampo 'message' ausente.
missing_nameCampo 'name' ausente.
missing_typeCampo 'type' ausente.
missing_urlCampo 'url' ausente.
module_unavailableMódulo não disponível nesta instalação.
not_foundO recurso não existe nesta conta.
plan_requiredO plano atual não inclui API & Webhooks.
protocol_errorNão foi possível gerar protocolo único. Repita a requisição.
rate_limitedLimite da chave excedido.
tenant_suspendedConta suspensa.
terminal_statusA manifestação está num estado final.
test_key_readonlyChave vxl_test_ não escreve.
too_many_attemptsMuitas tentativas sem credencial válida.
unauthorizedFalta o header Authorization.

5. Idempotência

Mande Idempotency-Key em qualquer escrita. Repetir com a mesma chave devolve a resposta guardada, com o header X-Voxli-Idempotent-Replay: true — nada é criado duas vezes, mesmo que você não saiba se a primeira chegou.

A chave vale para a conta inteira, não por credencial: dois serviços seus usando chaves de API diferentes continuam protegidos entre si. Se uma requisição com a mesma chave ainda estiver em andamento, a segunda recebe 409 idempotency_in_flight em vez de executar em paralelo.

6. Limites

Itens por página50 no máximo. Pedir mais é limitado em silêncio; meta.per_page diz quanto veio.
Descrição e resposta20000 caracteres
Nome e e-mail de contato320 caracteres
RequisiçõesDefinido por chave. Toda resposta traz X-RateLimit-Limit, -Remaining e -Reset; o 429 traz Retry-After.

Filtro que a API não consegue interpretar devolve 400 nomeando o parâmetro. Ele nunca é ignorado em silêncio: um since malformado que devolvesse a base inteira seria pior que um erro.

7. Webhooks

Você configura um endereço https público e escolhe os eventos. Cada entrega chega como POST com o mesmo envelope:

{ "id": "a3f1...-9c02", // = X-Voxli-Delivery "type": "manifestation.created", "version": "2", "occurred_at": "2026-08-31T14:02:11+00:00", "tenant": "sua-conta", "data": { "id": "...", "protocol": "2026080087" } }
HeaderConteúdo
X-Voxli-EventTipo do evento.
X-Voxli-DeliveryUUID da entrega. É o MESMO em todas as tentativas — use para descartar repetição.
X-Voxli-AttemptNúmero da tentativa.
X-Voxli-TimestampUnix timestamp desta tentativa. Entra no cálculo da assinatura.
X-Voxli-Signaturesha256=<hmac>
X-Voxli-VersionVersão do envelope.

Como validar a assinatura

A assinatura é o HMAC-SHA256 de timestamp + ponto + corpo, com o secret do endpoint como chave. O corpo são os bytes crus da requisição: não desserialize e serialize de novo antes de calcular, porque qualquer diferença de espaço, ordem de chave ou escape de acento muda o hash.

import hmac, hashlib, time def voxli_webhook_valido(secret, headers, corpo_bruto, tolerancia=300): assinatura = headers.get("X-Voxli-Signature", "") timestamp = headers.get("X-Voxli-Timestamp", "") # 1. Sem assinatura, RECUSE. Não trate como "não verificado". if not assinatura.startswith("sha256=") or not timestamp: return False # 2. Janela de tolerância: barra replay de entrega antiga capturada. if abs(time.time() - int(timestamp)) > tolerancia: return False # 3. Compare em tempo constante (nunca com ==). esperado = hmac.new( secret.encode(), f"{timestamp}.{corpo_bruto.decode()}".encode(), hashlib.sha256, ).hexdigest() return hmac.compare_digest(assinatura[7:], esperado)

Retentativa e duplicidade

Qualquer resposta 2xx é entrega concluída. Fora disso, tentamos 3 vezes, com intervalo de 2, 4 e 8 minutos. O timeout de cada tentativa é de 10 segundos: se o seu processamento demorar mais, responda 200 primeiro e processe depois.

Como a retentativa manda o mesmo corpo, guarde o X-Voxli-Delivery que você já processou e descarte o repetido. Redirect não é seguido, e o endereço precisa ser https e público — endereço interno é recusado.

Eventos disponíveis:

EventoQuando dispara
manifestation.createdManifestação criada
manifestation.status_changedStatus alterado
manifestation.assignedManifestação atribuída
manifestation.repliedResposta enviada
manifestation.overdueSLA vencido
lgpd.request.createdSolicitação LGPD criada
lgpd.request.status_changedStatus LGPD alterado
test.pingEvento de teste

8. Especificação OpenAPI

A especificação completa fica no endereço da sua conta, sem exigir autenticação — dá para apontar um gerador de SDK antes mesmo de criar a primeira chave:

https://sua-conta.voxli.com.br/api/v1/openapi.json

Ela é OpenAPI 3.1, já com o servidor certo em servers, e é verificada contra as rotas reais a cada build: um endpoint que exista e não esteja documentado, ou documentado e não exista, quebra a nossa integração contínua.

Ficou faltando alguma coisa?

A API cobre manifestações, tipos, indicadores, solicitações LGPD e webhooks. Se o seu caso precisa de algo que não está aqui, fale com a gente: a lista cresce por pedido de quem integra.

Falar com a Voxli

Quanto mais você espera, mais risco você acumula.

Prazos legais não esperam. Cada dia sem rastreabilidade é um dia de exposição.

Começar agora Agendar demonstração

Teste grátis por 7 dias · Cartão necessário · Cobrança só após o teste

Conforme LGPD
Hospedado no Brasil
Infraestrutura Google Cloud
WhatsApp