Pular para o conteúdo

SDK JavaScript/TypeScript

O @pliic/sdk é um cliente tipado, sem dependências, que envolve a API do widget (/widget/*) do Pliic. Ele é para quem quer construir uma interface própria de sugestões e tickets (um mural custom, uma caixa de sugestão com o seu próprio visual, uma central de suporte integrada ao seu produto), em vez de embutir o widget pronto.

Se o widget embutido já atende (janela flutuante, botão de feedback), você não precisa do SDK. Use o SDK quando quiser controlar 100% da interface e consumir os dados diretamente.

Sem build, sem npm, carregue o script hospedado e use o global PliicSDK:

<script src="https://pliic.com/sdk/v1.js"></script>
<script>
const { Pliic } = window.PliicSDK;
</script>

O global se chama PliicSDK, diferente do Pliic do widget embutido, os dois podem coexistir na mesma página sem conflito.

Terminal window
npm install @pliic/sdk
import { Pliic } from '@pliic/sdk';

Crie o cliente com a chave pública do seu app e, opcionalmente, um token de usuário:

const client = new Pliic({
appKey: 'pk_live_...',
userToken: '<jwt do usuário>', // opcional
baseUrl: 'https://pliic.com', // opcional, padrão: origem da página/script
timeoutMs: 10000, // opcional, padrão 10s
});
  • appKey (pk_live_...) identifica o app e a equipe. Encontre-a na aba Instalação do app.
  • userToken identifica o usuário final e libera ações como votar. Ele é um JWT gerado no seu servidor com a chave secreta (sk_...) do app: o fluxo completo de geração está documentado em Autenticação de usuários. Sem token, as ações do SDK funcionam como anônimas (sem votação).
  • O navegador envia o header Origin automaticamente em cada requisição: o domínio da sua página precisa estar nos domínios permitidos do app (aba Geral), do mesmo jeito que no widget embutido.
const init = await client.init(); // { app, config, user }
await client.ping();

init() retorna as configurações do app e, se houver userToken válido, os dados do usuário identificado. Use ping() para verificar rapidamente se as credenciais e o domínio estão corretos.

// Listar (com busca e filtro por status)
const list = await client.suggestions.list({ search: 'dark mode', status: 'open' });
// Criar
const created = await client.suggestions.create({
title: 'Modo escuro',
description: 'Seria ótimo ter um tema escuro.',
});
// { id, title, status }
// Editar (só o autor, e só enquanto ninguém mais se envolveu)
await client.suggestions.update(created.id, {
title: 'Modo escuro para todo o app',
});
// Excluir (mesma regra do autor)
await client.suggestions.delete(created.id);
// Votar
await client.suggestions.vote(created.id);
// Comentários
const comments = await client.suggestions.comments(created.id, { page: 1 });
const comment = await client.suggestions.addComment(created.id, { body: 'Concordo!' });
// Checar duplicadas antes de criar
const { duplicates, has_duplicates } = await client.suggestions.checkDuplicates({
title: 'Modo escuro',
});
// Listar
const tickets = await client.tickets.list({ page: 1 });
// Criar
const ticket = await client.tickets.create({
subject: 'Não consigo fazer login',
body: 'Recebo erro 500 ao entrar.',
type: 'bug',
});
// { id, ticket_number, subject, status }
// Buscar um ticket (com mensagens)
const { ticket: full, messages } = await client.tickets.get(ticket.id);
// Responder
await client.tickets.reply(ticket.id, { body: 'Ainda estou com o problema.' });
// Marcar como resolvido (só enquanto o ticket estiver aberto ou pendente)
await client.tickets.resolve(ticket.id);
// { id, status: 'resolved', resolved_at }

Responder a um ticket resolved reabre ele automaticamente, sem precisar de nenhuma chamada extra. Não existe um método para reabrir nem para fechar (closed) um ticket pelo SDK, essas transições ficam com a equipe.

O SDK expõe apenas o lado de consumo das enquetes: buscar a enquete ativa para o usuário identificado, responder e dispensar. Criação e gestão de enquetes ficam no painel do app.

// Buscar a enquete ativa para o usuário atual
const survey = await client.surveys.active();
// null quando não há enquete elegível no momento
if (survey) {
// Responder
await client.surveys.submit(survey.id, {
answers: survey.questions.map((question) => ({
question_id: question.id,
value: '5',
})),
});
// ou dispensar, se o usuário fechar sem responder
await client.surveys.dismiss(survey.id);
}

Cada pergunta de survey.questions traz type (single_choice, rating ou text), label, options (quando single_choice), rating_low_label/rating_high_label (quando rating), placeholder e is_required, o suficiente para renderizar o formulário sem chamadas extras.

Qualquer resposta que não seja 2xx lança PliicApiError, com status (código HTTP) e body (corpo bruto da resposta, quando disponível):

import { Pliic, PliicApiError } from '@pliic/sdk';
try {
await client.suggestions.create({ title: '' });
} catch (error) {
if (error instanceof PliicApiError) {
console.error(error.status, error.message, error.body);
}
}

Erros comuns:

  • 401: appKey inválida, userToken ausente/expirado, ou domínio fora da lista de domínios permitidos.
  • 422: dados de validação inválidos (ex.: título vazio).
  • 403: update/delete numa sugestão que não é do usuário identificado, ou numa sugestão que já saiu do controle do autor (recebeu voto de outra pessoa, comentário, resposta oficial ou mudou de status). Veja Editando ou excluindo sua sugestão. O mesmo código cobre tickets.resolve num ticket que não é do usuário identificado ou que já não está open/pending. Veja Marcando seu chamado como resolvido.
  • 429 ou erro de limite: o app atingiu o limite do plano (sugestões ou tickets por mês).

Requisições que excedem o timeoutMs configurado também são rejeitadas como PliicApiError.