API Documentation
A PumaHelp API é uma API RESTful completa para gerenciamento de tickets de suporte, permitindo criar, atualizar e gerenciar tickets, comentários, usuários, grupos, macros, webhooks e muito mais.
🔗 Base URL
Todas as requisições devem ser feitas para o subdomínio da sua organização:
https://{seu-app-name}.pumahelp.com.br/v1
Exemplo:
https://acme.pumahelp.com.br/v1
O subdomínio é definido pelo App Name configurado na seção de Configurações do dashboard. Se não souber qual é, verifique em Configurações ou entre em contato com o suporte.
🚀 Como Começar
Passo 1: Obter Acesso
Você tem duas opções para começar a usar a API:
Opção A: Usar credenciais de usuário (JWT)
- Ideal para: aplicações que já têm usuários cadastrados
- Requer: email e senha de um usuário existente
Opção B: Criar API Key (Recomendado para integrações)
- Ideal para: sistemas externos, automações, integrações de longo prazo
- Requer: acesso ao dashboard PumaHelp com permissões de admin/owner
Passo 2: Fazer Sua Primeira Requisição
Com JWT:
# 1. Fazer login
curl -X POST https://acme.pumahelp.com.br/v1/users/login \
-H "Content-Type: application/json" \
-d '{
"email": "[email protected]",
"password": "sua-senha"
}'
# 2. Usar o token recebido
curl -X GET https://acme.pumahelp.com.br/v1/tickets \
-H "Authorization: Bearer SEU_TOKEN_AQUI"
Com API Key:
# 1. Criar API Key no dashboard (Configurações → API Keys)
# 2. Usar a API Key diretamente
curl -X GET https://acme.pumahelp.com.br/v1/tickets \
-H "X-API-Key: SEU_API_KEY_SECRET"
Passo 3: Criar Seu Primeiro Ticket
curl -X POST https://acme.pumahelp.com.br/v1/tickets \
-H "Authorization: Bearer SEU_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"subject": "Meu primeiro ticket via API",
"priority": "normal",
"type": "question",
"comment": {
"body": "Testando a integração com sucesso!",
"public": true
}
}'
Passo 4: Próximos Passos
- ✅ Configure webhooks para receber notificações em tempo real
- ✅ Configure scopes adequados para sua API Key
- ✅ Implemente tratamento de erros robusto
📝 Convenções de Nomenclatura
A API utiliza snake_case para todos os campos de request e response.
Exemplo:
{
"public_id": 12345,
"created_at": "2025-01-01T10:00:00Z",
"assignee_id": "uuid",
"public": true
}
Todos os nomes de campos devem usar snake_case_lower (letras minúsculas com underscores).
🔐 Autenticação
A PumaHelp API suporta dois métodos de autenticação:
1. JWT (JSON Web Token)
Para usuários que fazem login via email/senha.
Como obter:
POST https://acme.pumahelp.com.br/v1/users/login
Content-Type: application/json
{
"email": "[email protected]",
"password": "sua-senha"
}
Resposta:
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"verified": true
}
Como usar:
GET https://acme.pumahelp.com.br/v1/tickets
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
2. API Key
Para integrações automatizadas e sistemas externos.
Como obter:
- Faça login na plataforma PumaHelp
- Navegue até Configurações → API Keys
- Clique em "Criar Nova API Key"
- Selecione os scopes necessários
- Copie o secret (visível apenas uma vez!)
Como usar:
GET https://acme.pumahelp.com.br/v1/tickets
X-API-Key: seu-api-key-secret-aqui
O secret da API Key é exibido apenas uma vez durante a criação. Guarde-o em local seguro!
🔒 Sistema de Scopes
A API utiliza um sistema granular de permissões baseado em scopes (no formato resource:action).
Como Funcionam os Scopes
| Tipo de Autenticação | Comportamento |
|---|---|
| JWT (Login) | Scopes atribuídos automaticamente baseados na role do usuário |
| API Key | Scopes devem ser explicitamente selecionados na criação |
Listagem de Scopes Disponíveis
Para obter a lista completa de scopes via API, consulte a seção 🔍 Escopos Disponíveis.
📊 Rate Limiting
A API implementa rate limiting para proteger contra abuso:
Limites por IP (Endpoints Públicos)
- 100 requisições a cada 10 segundos
- Fila de até 20 requisições
Limites por Organização (Endpoints Autenticados)
- 1000 tokens disponíveis
- 100 tokens repostos a cada 10 segundos
Headers de Resposta:
X-RateLimit-Remaining: 987
Retry-After: 10
Response quando limite excedido: 429 Too Many Requests
{
"errors": ["Rate limit exceeded"]
}
📝 Endpoints
🎫 Tickets
Criar Ticket
POST https://acme.pumahelp.com.br/v1/tickets
Authorization: Bearer {token}
Content-Type: application/json
Scope: ticket:create
Request Body:
{
"subject": "Problema com login",
"priority": "high",
"type": "question",
"group_id": "uuid-do-grupo",
"requester": {
"name": "Cliente Nome",
"email": "[email protected]"
},
"comment": {
"body": "Não consigo fazer login no sistema",
"public": true,
"author_id": "uuid-autor",
"uploads": ["uuid-arquivo-1", "uuid-arquivo-2"]
},
"tags": ["login", "urgent"],
"via": {
"channel": "api"
}
}
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
subject | string | Sim | Assunto do ticket |
priority | string | Não | Prioridade: low, normal, high, urgent (padrão: normal) |
type | string | Não | Tipo: question, incident, problem, task |
group_id | uuid | Não | ID do grupo responsável |
requester | object | Não | Dados do solicitante (se criar em nome de outro usuário) |
requester.name | string | Não | Nome do solicitante |
requester.email | string | Não | Email do solicitante |
requester.external_id | string | Não | ID externo do solicitante |
requester.id | uuid | Não | ID do solicitante |
comment | object | Sim | Primeiro comentário do ticket |
comment.body | string | Sim | Conteúdo do comentário |
comment.public | boolean | Não | Se visível para o cliente (padrão: true) |
comment.author_id | uuid | Não | ID do autor (se diferente do usuário autenticado) |
comment.uploads | array[uuid] | Não | IDs de arquivos anexados |
tags | array[string] | Não | Tags para categorização |
via | object | Não | Canal de origem |
via.channel | string | Não | Canal: api, widget, discord |
Response: 201 Created
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"public_id": 12345,
"subject": "Problema com login",
"status": "new",
"created_at": "2025-01-01T10:00:00Z",
"conversation_id": "uuid-conversa"
}
Listar Tickets
GET https://acme.pumahelp.com.br/v1/tickets?page=1&page_size=25
Authorization: Bearer {token}
Scope: ticket:read
Query Parameters:
| Parâmetro | Tipo | Descrição | Obrigatório |
|---|---|---|---|
page | integer | Número da página | Sim |
page_size | integer | Itens por página (max: 100) | Sim |
query | string | Query language para filtros avançados | Não |
sort_by | string | Campo para ordenação: created_at, updated_at, priority, status | Não |
sort_order | string | Ordem: asc ou desc | Não |
include | array[string] | Campos extras: assignee, requester, last_comment, tags | Não |
Query Language Examples:
# Status
status:open
status:pending OR status:solved
# Prioridade
priority:high
# Assignee
assignee:me
assignee:'uuid-do-agente'
# Requester
requester:me
# Datas
created:today
created:last_7_days
updated:last_24_hours
# Combinações
status:open AND priority:high
Response: 200 OK
{
"count": 150,
"tickets": [
{
"id": "uuid",
"public_id": 12345,
"subject": "Problema com login",
"status": "open",
"priority": "high",
"type": "question",
"created_at": "2025-01-01T10:00:00Z",
"updated_at": "2025-01-01T12:00:00Z",
"solved_at": null,
"archived_at": null,
"group_id": "uuid",
"conversation_id": "uuid",
"tags": ["login", "urgent"],
"assignee": {
"id": "uuid",
"name": "Maria Santos",
"role": "agent",
"email": "[email protected]",
"verified": true
},
"requester": {
"id": "uuid",
"name": "João Silva",
"role": "end-user",
"email": "[email protected]",
"verified": true
},
"last_comment": {
"id": "uuid",
"body": "Último comentário",
"public": true,
"created_at": "2025-01-01T12:00:00Z",
"updated_at": null,
"author": {
"id": "uuid",
"name": "Maria Santos",
"role": "agent",
"email": "[email protected]",
"verified": true
},
"attachments": []
},
"via": {
"channel": "widget"
}
}
]
}
Obter Ticket por ID
GET https://acme.pumahelp.com.br/v1/tickets/{public_id}
Authorization: Bearer {token}
Scope: ticket:read
Response: 200 OK
{
"id": "uuid",
"public_id": 12345,
"subject": "Problema com login",
"status": "open",
"priority": "high",
"type": "question",
"created_at": "2025-01-01T10:00:00Z",
"updated_at": "2025-01-01T12:00:00Z",
"solved_at": null,
"archived_at": null,
"group_id": "uuid",
"conversation_id": "uuid",
"tags": ["login", "urgent"],
"assignee": {
"id": "uuid",
"name": "Maria Santos",
"role": "owner",
"email": "[email protected]",
"verified": true
},
"requester": {
"id": "uuid",
"name": "João Silva",
"role": "end-user",
"email": "[email protected]",
"verified": true
},
"via": {
"channel": "api"
}
}
Atualizar Ticket
PUT https://acme.pumahelp.com.br/v1/tickets/{public_id}
Authorization: Bearer {token}
Content-Type: application/json
Scope: ticket:update
Request Body:
{
"subject": "Problema com login - RESOLVIDO",
"status": "solved",
"priority": "normal",
"type": "incident",
"requester_id": "uuid-novo-requester",
"assignee_id": "uuid-agente",
"group_id": "uuid-grupo",
"archived": false,
"tags": ["login", "resolved"],
"comment": {
"body": "Problema resolvido!",
"public": true,
"uploads": ["uuid-arquivo"]
}
}
| Campo | Tipo | Descrição |
|---|---|---|
subject | string | Novo assunto |
status | string | Novo status: new, open, pending, solved, closed |
priority | string | Nova prioridade |
type | string | Novo tipo |
requester_id | uuid | Transferir para outro requester |
assignee_id | uuid | Atribuir a agente (use null para desatribuir) |
group_id | uuid | Atribuir a grupo |
archived | boolean | Arquivar ticket |
tags | array[string] | Substituir tags |
comment | object | Adicionar comentário com a atualização |
Todos os campos são opcionais. Para remover assignee, envie null explicitamente.
Response: 204 No Content
Arquivar Ticket
DELETE https://acme.pumahelp.com.br/v1/tickets/{public_id}
Authorization: Bearer {token}
Scope: ticket:delete
Response: 204 No Content
Tickets são arquivados (soft delete), não excluídos permanentemente.
📊 Relatórios
Estatísticas ao Longo do Tempo
GET https://acme.pumahelp.com.br/v1/tickets/stats-over-time?period=30d
Authorization: Bearer {token}
Scope: reports:read
Query Parameters:
| Parâmetro | Valores Aceitos |
|---|---|
period | 24h, 7d, 30d |
Response: 200 OK
{
"data": [
{
"date": "2025-01-01",
"created": 45,
"resolved": 38
},
{
"date": "2025-01-02",
"created": 52,
"resolved": 41
}
]
}
Ranking de Agentes
GET https://acme.pumahelp.com.br/v1/tickets/agent-ranking?period=30d
Authorization: Bearer {token}
Scope: reports:read
Query Parameters:
| Parâmetro | Valores Aceitos |
|---|---|
period | 24h, 7d, 30d |
Response: 200 OK
{
"data": [
{
"agent": "Maria Santos",
"resolved": 127
},
{
"agent": "João Silva",
"resolved": 98
}
]
}
💬 Comentários
Listar Comentários de um Ticket
GET https://acme.pumahelp.com.br/v1/tickets/{public_id}/comments?page=1&page_size=50
Authorization: Bearer {token}
Scope: comment:read
Query Parameters:
| Parâmetro | Tipo | Descrição | Padrão | Obrigatório |
|---|---|---|---|---|
page | integer | Número da página | - | Sim |
page_size | integer | Itens por página (max: 100) | - | Sim |
sort_by | string | Campo para ordenação: created_at | created_at | Não |
sort_order | string | Ordem: asc ou desc | asc | Não |
Response: 200 OK
{
"count": 5,
"comments": [
{
"id": "uuid",
"body": "Estamos investigando o problema",
"public": true,
"created_at": "2025-01-01T11:00:00Z",
"updated_at": null,
"author": {
"id": "uuid",
"name": "Maria Santos",
"role": "agent",
"email": "[email protected]",
"verified": true
},
"attachments": [
{
"id": "uuid",
"file_name": "screenshot.png",
"content_type": "image/png",
"size": 102400,
"content_url": "https://cdn.pumahelp.com/attachments/abc123"
}
]
}
]
}
Redigir Comentário
PUT https://acme.pumahelp.com.br/v1/tickets/{public_id}/comments/{comment_id}/redact
Authorization: Bearer {token}
Content-Type: application/json
Scope: comment:redact
Request Body:
{
"body": "Comentário <redact>removido</redact>"
}
Response: 204 No Content
O texto entre as tags
Redigir Anexo de Comentário
PUT https://acme.pumahelp.com.br/v1/tickets/{public_id}/comments/{comment_id}/attachment/{attachment_id}/redact
Authorization: Bearer {token}
Scope: comment:redact
Response: 204 No Content
Remove permanentemente o arquivo anexado.
Marcar Comentário como Privado
PUT https://acme.pumahelp.com.br/v1/tickets/{public_id}/comments/{comment_id}/make_private
Authorization: Bearer {token}
Scope: comment:update
Response: 204 No Content
Torna o comentário invisível para end-users. Apenas agentes e admins poderão visualizar. dependendo do meio de comunicação, o comentário pode continuar visível para o end-user (cliente).
👥 Usuários
Login
POST https://acme.pumahelp.com.br/v1/users/login
Content-Type: application/json
Rate Limit: IP-based (100 req/10s)
Request Body:
{
"email": "[email protected]",
"password": "sua-senha"
}
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
email | string | Sim | Email do usuário |
password | string | Sim | Senha do usuário |
Response: 200 OK
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"verified": true
}
| Campo | Tipo | Descrição |
|---|---|---|
access_token | string | Token JWT para autenticação (válido por 24h) |
refresh_token | string | Token para renovar o access_token |
verified | boolean | Se o email do usuário foi verificado |
Renovar Token (Refresh)
POST https://acme.pumahelp.com.br/v1/users/refresh
Content-Type: application/json
Rate Limit: IP-based (100 req/10s)
Request Body:
{
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
Response: 201 Created
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
Logout
POST https://acme.pumahelp.com.br/v1/users/logout
Authorization: Bearer {token}
Content-Type: application/json
Scope: session:delete:own
Rate Limit: IP-based
Request Body:
{
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
Response: 204 No Content
Criar Usuário
POST https://acme.pumahelp.com.br/v1/users
Authorization: Bearer {token}
Content-Type: application/json
Scope: user:create
Request Body:
{
"name": "João Silva",
"email": "[email protected]",
"role": "agent",
"external_id": "crm-user-123",
"verified": false,
"group_ids": ["uuid-grupo-1", "uuid-grupo-2"]
}
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
name | string | Sim | Nome completo do usuário |
email | string | Não | Email do usuário (opcional) |
role | string | Sim | Role: end-user, agent, admin, owner |
external_id | string | Não | ID externo para integração com outros sistemas |
verified | boolean | Não | Se o email deve ser marcado como verificado (padrão: false) |
group_ids | array[uuid] | Não | IDs dos grupos aos quais o usuário pertence |
Response: 201 Created
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "João Silva",
"email": "[email protected]",
"role": "agent",
"external_id": "crm-user-123",
"verified": false
}
Criar ou Atualizar Usuário (Upsert)
POST https://acme.pumahelp.com.br/v1/users/create_or_update
Authorization: Bearer {token}
Content-Type: application/json
Scope: user:upsert
Request Body:
{
"name": "João Silva",
"email": "[email protected]",
"role": "agent",
"external_id": "crm-user-123",
"verified": false,
"group_ids": ["uuid-grupo-1"]
}
Response: 200 OK ou 201 Created
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "João Silva",
"email": "[email protected]",
"role": "agent",
"external_id": "crm-user-123",
"verified": false
}
Este endpoint verifica se já existe um usuário com o email ou external_id informado. Se existir, atualiza; se não, cria. Ideal para sincronizações com sistemas externos.
Impersonificar Usuário
POST https://acme.pumahelp.com.br/v1/users/impersonate
Authorization: Bearer {token}
Content-Type: application/json
Scope: user:impersonate
Request Body:
{
"email": "[email protected]",
"external_id": "crm-user-123",
"name": "João Silva",
"role": "end-user",
"verified": false,
"group_ids": ["uuid-grupo-1"]
}
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
email | string | Condicional | Email do usuário (obrigatório se external_id não fornecido) |
external_id | string | Condicional | ID externo (obrigatório se email não fornecido) |
name | string | Não | Nome completo (usado apenas se criar novo usuário) |
role | string | Não | Role: end-user, agent, admin, owner (padrão: end-user) |
verified | boolean | Não | Se o email deve ser verificado (apenas para criação) |
group_ids | array[uuid] | Não | IDs dos grupos (apenas para criação) |
Response: 200 OK
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 86400
}
| Campo | Tipo | Descrição |
|---|---|---|
access_token | string | Token JWT para autenticação em nome do usuário |
token_type | string | Sempre "Bearer" |
expires_in | integer | Tempo de expiração em segundos |
Este endpoint permite gerar um access token em nome de um usuário específico. Se o usuário não existir, ele será criado automaticamente. Ideal para implementações de "Login as User" ou integração com sistemas de SSO (Single Sign-On).
Este é um endpoint sensível que permite assumir a identidade de qualquer usuário. Disponível apenas para roles ADMIN e OWNER, ou via API Key com scope user:impersonate.
Listar Usuários
GET https://acme.pumahelp.com.br/v1/users?page=1&page_size=50
Authorization: Bearer {token}
Scope: user:read
Query Parameters:
| Parâmetro | Tipo | Descrição | Padrão |
|---|---|---|---|
page | integer | Número da página | 1 |
page_size | integer | Itens por página (max: 100) | 25 |
roles | array[string] | Filtrar por roles (pode enviar múltiplos) | - |
query | string | Busca por nome ou email | - |
external_id | string | Filtrar por ID externo | - |
group_id | uuid | Filtrar por grupo | - |
active | boolean | Filtrar por usuários ativos | - |
Exemplo com múltiplas roles:
GET /v1/users?roles=agent&roles=admin
Response: 200 OK
{
"count": 150,
"users": [
{
"id": "uuid",
"name": "Maria Santos",
"email": "[email protected]",
"role": "agent",
"external_id": "crm-123",
"verified": true
}
]
}
Obter Próprio Perfil
GET https://acme.pumahelp.com.br/v1/users/me
Authorization: Bearer {token}
Scope: profile:read:own
Response: 200 OK
{
"id": "uuid",
"name": "João Silva",
"email": "[email protected]",
"role": "agent",
"notes": "Notas internas sobre o usuário",
"external_id": "crm-123",
"verified": true,
"created_at": "2025-01-01T10:00:00Z",
"updated_at": "2025-01-15T14:30:00Z"
}
Obter Usuário por ID
GET https://acme.pumahelp.com.br/v1/users/{user_id}
Authorization: Bearer {token}
Scope: user:read
Response: 200 OK
{
"id": "uuid",
"name": "João Silva",
"email": "[email protected]",
"role": "agent",
"notes": "Notas internas",
"external_id": "crm-123",
"verified": true,
"created_at": "2025-01-01T10:00:00Z",
"updated_at": "2025-01-15T14:30:00Z"
}
Atualizar Usuário
PUT https://acme.pumahelp.com.br/v1/users/{user_id}
Authorization: Bearer {token}
Content-Type: application/json
Scope: user:update
Request Body:
{
"name": "João Silva Santos",
"role": "admin",
"email": "[email protected]",
"notes": "Promovido a admin em Jan/2025",
"external_id": "crm-456",
"verified": true,
"group_ids": ["uuid-grupo-3"]
}
| Campo | Tipo | Descrição |
|---|---|---|
name | string | Nome do usuário |
role | string | Nova role do usuário |
email | string | Novo email |
notes | string | Notas internas (não visível para end-users) |
external_id | string | ID externo |
verified | boolean | Status de verificação de email |
group_ids | array[uuid] | Grupos do usuário |
Todos os campos são opcionais. Apenas os campos enviados serão atualizados.
Response: 200 OK
{
"id": "uuid",
"name": "João Silva Santos",
"email": "[email protected]",
"role": "admin",
"external_id": "crm-456",
"verified": true
}
Deletar Usuário
DELETE https://acme.pumahelp.com.br/v1/users/{user_id}
Authorization: Bearer {token}
Scope: user:delete
Response: 204 No Content
Enviar Email de Verificação
POST https://acme.pumahelp.com.br/v1/users/{user_id}/email/send/verification
Authorization: Bearer {token}
Scope: user:manage
Response: 204 No Content
Envia um email para o usuário com link para verificar o endereço de email.
Verificar Email
POST https://acme.pumahelp.com.br/v1/users/email/verify?token={verification_token}
Rate Limit: IP-based
Sem autenticação necessária
Query Parameters:
token- Token de verificação enviado por email
Response: 204 No Content
Reenviar Email de Verificação
POST https://acme.pumahelp.com.br/v1/users/email/resend/verification?email={user_email}
Rate Limit: IP-based
Sem autenticação necessária
Query Parameters:
email- Email do usuário que precisa reenviar verificação
Response: 204 No Content
Mesclar Sessão (Merge Session)
POST https://acme.pumahelp.com.br/v1/users/merge-session
Authorization: Bearer {token}
Content-Type: application/json
Scope: session:merge
Request Body:
{
"target_auth_token": "token-jwt-do-usuario-autenticado"
}
Response: 204 No Content
Use este endpoint para mesclar a sessão de um usuário convidado (guest) com um usuário autenticado. Útil quando um visitante cria tickets como guest e depois faz login/cadastro.
👤 Usuários Convidados (Guests)
Usuários convidados permitem criar sessões temporárias para visitantes que ainda não possuem uma conta completa no sistema. Ideal para permitir que potenciais clientes criem tickets sem necessidade de registro completo.
Criar Usuário Convidado
POST https://acme.pumahelp.com.br/v1/guests
Authorization: Bearer {token}
Content-Type: application/json
Scope: guest:create
Use Case: Permitir que visitantes do seu site ou aplicativo abram tickets de suporte sem criar uma conta completa, reduzindo fricção no processo de obter ajuda.
Request Body:
{
"name": "Visitante João"
}
Campos do Request:
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
name | string | Não | Nome do visitante. Se não fornecido, será gerado automaticamente |
Response: 201 Created
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Visitante João",
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
Campos do Response:
| Campo | Tipo | Descrição |
|---|---|---|
id | uuid | ID único do usuário convidado |
name | string | Nome do convidado |
access_token | string | Token JWT para autenticar requests em nome deste convidado |
Exemplo Completo:
# Criar guest user
curl -X POST https://acme.pumahelp.com.br/v1/guests \
-H "Authorization: Bearer SEU_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "Visitante da Landing Page"}'
# Usar o access_token do guest para criar ticket
curl -X POST https://acme.pumahelp.com.br/v1/tickets \
-H "Authorization: Bearer TOKEN_DO_GUEST" \
-H "Content-Type: application/json" \
-d '{
"subject": "Dúvida sobre o produto",
"priority": "normal",
"type": "question",
"comment": {
"body": "Gostaria de saber mais sobre os planos disponíveis",
"public": true
}
}'
Use este recurso para implementar um formulário de contato avançado ou chat widget onde visitantes possam criar tickets sem criar conta.
👥 Grupos
Criar Grupo
POST https://acme.pumahelp.com.br/v1/groups
Authorization: Bearer {token}
Content-Type: application/json
Scope: group:create
Request Body:
{
"name": "Suporte Técnico",
"description": "Equipe responsável por suporte técnico"
}
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
name | string | Sim | Nome do grupo |
description | string | Não | Descrição do grupo |
Response: 201 Created
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Suporte Técnico",
"description": "Equipe responsável por suporte técnico",
"default": false
}
Listar Grupos
GET https://acme.pumahelp.com.br/v1/groups?page=1&page_size=50
Authorization: Bearer {token}
Scope: group:read
Query Parameters:
| Parâmetro | Tipo | Descrição | Obrigatório |
|---|---|---|---|
page | integer | Número da página | Sim |
page_size | integer | Itens por página | Sim |
query | string | Busca por nome ou descrição | Não |
user_id | uuid | Filtrar grupos que contêm um usuário específico | Não |
Response: 200 OK
{
"count": 3,
"groups": [
{
"id": "uuid",
"name": "Suporte Técnico",
"description": "Equipe responsável por suporte técnico",
"default": false
},
{
"id": "uuid",
"name": "Vendas",
"description": "Equipe de vendas",
"default": true
}
]
}
Listar Grupos com Usuários
GET https://acme.pumahelp.com.br/v1/groups/users?page=1&page_size=50
Authorization: Bearer {token}
Scope: group:read
Query Parameters:
| Parâmetro | Tipo | Descrição | Obrigatório |
|---|---|---|---|
page | integer | Número da página | Sim |
page_size | integer | Itens por página | Sim |
query | string | Busca por nome ou descrição | Não |
user_id | uuid | Filtrar grupos que contêm um usuário específico | Não |
Response: 200 OK
{
"count": 3,
"groups": [
{
"id": "uuid",
"name": "Suporte Técnico",
"description": "Equipe responsável por suporte técnico",
"default": false,
"users": [
{
"id": "uuid",
"name": "Maria Santos",
"email": "[email protected]",
"role": "agent",
"external_id": null,
"verified": true
},
{
"id": "uuid",
"name": "João Silva",
"email": "[email protected]",
"role": "agent",
"external_id": null,
"verified": true
}
]
}
]
}
Use este endpoint quando precisar dos membros de cada grupo. Mais eficiente que buscar grupo por grupo.
Obter Grupo por ID
GET https://acme.pumahelp.com.br/v1/groups/{group_id}
Authorization: Bearer {token}
Scope: group:read
Response: 200 OK
{
"id": "uuid",
"name": "Suporte Técnico",
"description": "Equipe responsável por suporte técnico",
"default": false
}
Atualizar Grupo
PUT https://acme.pumahelp.com.br/v1/groups/{group_id}
Authorization: Bearer {token}
Content-Type: application/json
Scope: group:update
Request Body:
{
"name": "Suporte Técnico Nível 2",
"description": "Equipe de suporte avançado"
}
| Campo | Tipo | Descrição |
|---|---|---|
name | string | Novo nome do grupo |
description | string | Nova descrição |
Todos os campos são opcionais. Apenas os campos enviados serão atualizados.
Response: 204 No Content
Deletar Grupo
DELETE https://acme.pumahelp.com.br/v1/groups/{group_id}
Authorization: Bearer {token}
Scope: group:delete
Response: 204 No Content
Para adicionar ou remover usuários de um grupo, use o endpoint de atualização de usuário (PUT /v1/users/{user_id}) enviando o campo group_ids. apenas os grupos padrão não podem ser removidos.
🤖 Macros
Criar Macro
POST https://acme.pumahelp.com.br/v1/macros
Authorization: Bearer {token}
Content-Type: application/json
Scope: macro:create
Request Body:
{
"title": "Resposta Padrão - Problema de Login",
"description": "Resposta automática para problemas de login",
"type": "group",
"group_ids": ["uuid-grupo-1", "uuid-grupo-2"],
"actions": [
{
"field": "status",
"value": "pending"
},
{
"field": "priority",
"value": "high"
},
{
"field": "comment_value",
"value": "Por favor, tente limpar o cache do navegador e fazer login novamente."
}
]
}
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
title | string | Sim | Título da macro |
description | string | Não | Descrição da macro |
type | string | Sim | Tipo: user (usuário) ou group (grupo) |
group_ids | array[uuid] | Não | IDs dos grupos que podem usar esta macro (obrigatório se type=group) |
actions | array[object] | Sim | Lista de ações a executar |
actions[].field | string | Sim | Campo a modificar: comment_value, status, type, priority |
actions[].value | any | Sim | Valor a aplicar (tipo depende do field) |
Response: 201 Created
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"title": "Resposta Padrão - Problema de Login",
"description": "Resposta automática para problemas de login",
"type": "auto",
"group_ids": ["uuid-grupo-1"],
"actions": [
{
"field": "status",
"value": "pending"
},
{
"field": "comment_value",
"value": "Por favor, tente limpar o cache..."
}
],
"created_at": "2025-01-01T10:00:00Z"
}
Listar Macros
GET https://acme.pumahelp.com.br/v1/macros?page=1&page_size=50
Authorization: Bearer {token}
Scope: macro:read
Query Parameters:
| Parâmetro | Tipo | Descrição | Obrigatório |
|---|---|---|---|
page | integer | Número da página | Sim |
page_size | integer | Itens por página | Sim |
Response: 200 OK
{
"count": 5,
"macros": [
{
"id": "uuid",
"title": "Resposta Padrão - Problema de Login",
"description": "Resposta automática para problemas de login",
"type": "user",
"group_ids": [],
"actions": [],
"created_at": "2025-01-01T10:00:00Z"
}
]
}
Obter Macro por ID
GET https://acme.pumahelp.com.br/v1/macros/{macro_id}
Authorization: Bearer {token}
Scope: macro:read
Response: 200 OK
{
"id": "uuid",
"title": "Resposta Padrão - Problema de Login",
"description": "Resposta automática para problemas de login",
"type": "user",
"group_ids": ["uuid-grupo-1"],
"actions": [
{
"field": "status",
"value": "pending"
},
{
"field": "priority",
"value": "high"
}
],
"created_at": "2025-01-01T10:00:00Z"
}
Atualizar Macro
PUT https://acme.pumahelp.com.br/v1/macros/{macro_id}
Authorization: Bearer {token}
Content-Type: application/json
Scope: macro:update
Request Body:
{
"title": "Resposta Padrão - Login Atualizada",
"description": "Nova descrição",
"type": "group",
"group_ids": ["uuid-grupo-3"],
"actions": [
{
"field": "status",
"value": "solved"
}
]
}
Todos os campos são opcionais. Apenas os campos enviados serão atualizados.
Response: 200 OK
{
"id": "uuid",
"title": "Resposta Padrão - Login Atualizada",
"description": "Nova descrição",
"type": "group",
"group_ids": ["uuid-grupo-3"],
"actions": [
{
"field": "status",
"value": "solved"
}
],
"created_at": "2025-01-01T10:00:00Z"
}
Deletar Macro
DELETE https://acme.pumahelp.com.br/v1/macros/{macro_id}
Authorization: Bearer {token}
Scope: macro:delete
Response: 204 No Content
🔗 Webhooks
Criar Webhook
POST https://acme.pumahelp.com.br/v1/webhooks
Authorization: Bearer {token}
Content-Type: application/json
Scope: webhook:create
Request Body:
{
"name": "Notificação Slack",
"url": "https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXX",
"events": ["ticket.created", "ticket.updated", "user.created"]
}
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
name | string | Sim | Nome do webhook |
url | string | Sim | URL que receberá as notificações |
events | array[string] | Sim | Eventos a monitorar: ticket.created, ticket.updated, user.created, user.updated, user.deleted |
Response: 201 Created
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Notificação Slack",
"url": "https://hooks.slack.com/services/...",
"events": ["ticket.created", "ticket.updated", "user.created"],
"created_at": "2025-01-01T10:00:00Z",
"key": "whk_live_a1b2c3d4e5_secretkeyhereXXXXXXXX"
}
Cada organização pode criar no máximo 5 webhooks. Se você atingir esse limite, será necessário deletar um webhook existente antes de criar um novo.
A key é gerada automaticamente durante a criação do webhook e é usada para assinar as requisições enviadas. Guarde-a de forma segura, pois será necessária para validar a autenticidade dos webhooks recebidos.
Listar Webhooks
GET https://acme.pumahelp.com.br/v1/webhooks?page=1&page_size=50
Authorization: Bearer {token}
Scope: webhook:read
Query Parameters:
| Parâmetro | Tipo | Descrição | Obrigatório |
|---|---|---|---|
page | integer | Número da página | Sim |
page_size | integer | Itens por página | Sim |
Response: 200 OK
{
"count": 2,
"webhooks": [
{
"id": "uuid",
"name": "Notificação Slack",
"url": "https://hooks.slack.com/services/...",
"events": ["ticket.created", "ticket.updated"],
"created_at": "2025-01-01T10:00:00Z",
"key": "whk_live_a1b2c3d4e5_secretkeyhereXXXXXXXX"
}
]
}
Obter Webhook
GET https://acme.pumahelp.com.br/v1/webhooks/{webhook_id}
Authorization: Bearer {token}
Scope: webhook:read
Response: 200 OK
{
"id": "uuid",
"name": "Notificação Slack",
"url": "https://hooks.slack.com/services/...",
"events": ["ticket.created", "ticket.updated", "user.created"],
"created_at": "2025-01-01T10:00:00Z",
"key": "whk_live_a1b2c3d4e5_secretkeyhereXXXXXXXX"
}
Atualizar Webhook
PUT https://acme.pumahelp.com.br/v1/webhooks/{webhook_id}
Authorization: Bearer {token}
Content-Type: application/json
Scope: webhook:update
Request Body:
{
"name": "Notificação Slack Atualizada",
"url": "https://hooks.slack.com/services/UPDATED",
"events": ["ticket.created", "user.deleted"]
}
| Campo | Tipo | Descrição |
|---|---|---|
name | string | Novo nome do webhook |
url | string | Nova URL |
events | array[string] | Novos eventos |
Todos os campos são opcionais. Apenas os campos enviados serão atualizados.
Response: 204 No Content
Deletar Webhook
DELETE https://acme.pumahelp.com.br/v1/webhooks/{webhook_id}
Authorization: Bearer {token}
Scope: webhook:delete
Response: 204 No Content
Rotacionar Chave do Webhook
PUT https://acme.pumahelp.com.br/v1/webhooks/rotate/{webhook_id}
Authorization: Bearer {token}
Scope: webhook:rotate
Descrição:
Gera uma nova chave de assinatura para o webhook. A chave antiga é invalidada imediatamente.
Após rotacionar a chave, atualize imediatamente sua aplicação que recebe os webhooks com a nova chave para validação de assinatura HMAC. Webhooks enviados após a rotação usarão a nova chave.
Response: 200 OK
{
"key": "whk_live_x9y8z7w6v5_newsecretkeyXXXXXXXX"
}
| Campo | Tipo | Descrição |
|---|---|---|
key | string | Nova chave gerada (com prefixo whk_live_) |
Exemplo de validação HMAC em Node.js:
const crypto = require('crypto');
function validateWebhook(body, signature, timestamp, webhookKey) {
const stringToSign = `${timestamp}.${JSON.stringify(body)}`;
const expectedSignature = crypto
.createHmac('sha256', webhookKey)
.update(stringToSign)
.digest('base64');
return signature === expectedSignature;
}
🔑 API Keys
Listar API Keys
GET https://acme.pumahelp.com.br/v1/keys?page=1&page_size=50
Authorization: Bearer {token}
Scope: apikey:read
Query Parameters:
| Parâmetro | Tipo | Descrição | Obrigatório |
|---|---|---|---|
page | integer | Número da página | Sim |
page_size | integer | Itens por página | Sim |
Response: 200 OK
{
"count": 3,
"keys": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"prefix": "rk_live_",
"name": "Integration - CRM",
"description": "API Key para sincronização com CRM",
"scopes": ["ticket:create", "ticket:read", "user:upsert"],
"key_lookup": "a1b2c3d4e5f6",
"created_at": "2025-01-01T10:00:00Z"
}
]
}
| Campo | Tipo | Descrição |
|---|---|---|
id | uuid | ID da API Key |
prefix | string | Prefixo da chave para identificação rápida |
name | string | Nome da API Key |
description | string | Descrição |
scopes | array[string] | Escopos atribuídos |
key_lookup | string | Lookup hash para busca interna |
created_at | datetime | Data de criação |
Criar API Key
POST https://acme.pumahelp.com.br/v1/keys
Authorization: Bearer {token}
Content-Type: application/json
Scope: apikey:create
Request Body:
{
"name": "Integration - CRM",
"description": "Para sincronização automática de tickets e usuários",
"scopes": ["ticket:create", "ticket:read", "user:upsert"]
}
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
name | string | Sim | Nome da API Key |
description | string | Não | Descrição do uso da chave |
scopes | array[string] | Sim | Lista de escopos permitidos |
Response: 201 Created
{
"key": "rk_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0"
}
A chave completa (key) é exibida apenas uma vez! Guarde-a imediatamente em local seguro. Após esta resposta, você só verá o prefix e key_lookup ao listar as chaves.
Atualizar API Key
PUT https://acme.pumahelp.com.br/v1/keys/{key_id}
Authorization: Bearer {token}
Content-Type: application/json
Scope: apikey:update
Request Body:
{
"name": "Integration - CRM v2",
"description": "Atualizado para nova integração",
"scopes": ["ticket:create", "ticket:read", "ticket:update", "user:upsert"]
}
| Campo | Tipo | Descrição |
|---|---|---|
name | string | Novo nome |
description | string | Nova descrição |
scopes | array[string] | Novos escopos |
Todos os campos são opcionais. Apenas os campos enviados serão atualizados.
Response: 200 OK
{
"id": "uuid",
"prefix": "rk_live_",
"name": "Integration - CRM v2",
"description": "Atualizado para nova integração",
"scopes": ["ticket:create", "ticket:read", "ticket:update", "user:upsert"],
"key_lookup": "a1b2c3d4e5f6",
"created_at": "2025-01-01T10:00:00Z"
}
Rotacionar API Key
PUT https://acme.pumahelp.com.br/v1/keys/rotate/{key_id}
Authorization: Bearer {token}
Scope: apikey:rotate
Response: 200 OK
{
"key": "rk_live_x9y8z7w6v5u4t3s2r1q0p9o8n7m6l5k4j3i2h1g0"
}
Ao rotacionar, a chave antiga torna-se inválida imediatamente. Atualize seus sistemas com a nova chave antes de rotacionar!
Deletar API Key
DELETE https://acme.pumahelp.com.br/v1/keys/{key_id}
Authorization: Bearer {token}
Scope: apikey:delete
Response: 204 No Content
Esta ação é irreversível. Sistemas usando esta chave perderão acesso imediatamente.
📊 Relatórios
Estatísticas ao Longo do Tempo
GET https://acme.pumahelp.com.br/v1/reports/stats?start_date=2025-01-01&end_date=2025-01-31&interval=day
Authorization: Bearer {token}
Scope: reports:read
Query Parameters:
start_date- Data inicial (formato: YYYY-MM-DD)end_date- Data final (formato: YYYY-MM-DD)interval- Intervalo de agregação:hour,day,week,month
Response: 200 OK
{
"stats": [
{
"date": "2025-01-01",
"tickets_created": 45,
"tickets_solved": 38,
"tickets_pending": 12,
"average_response_time_minutes": 150,
"average_resolution_time_minutes": 495,
"satisfaction_rate": 0.92
},
{
"date": "2025-01-02",
"tickets_created": 52,
"tickets_solved": 41,
"tickets_pending": 15,
"average_response_time_minutes": 135,
"average_resolution_time_minutes": 480,
"satisfaction_rate": 0.94
}
]
}
Ranking de Agentes
GET https://acme.pumahelp.com.br/v1/reports/agent-ranking?start_date=2025-01-01&end_date=2025-01-31
Authorization: Bearer {token}
Scope: reports:read
Query Parameters:
start_date- Data inicial (formato: YYYY-MM-DD)end_date- Data final (formato: YYYY-MM-DD)
Response: 200 OK
{
"ranking": [
{
"position": 1,
"agent": {
"id": "uuid",
"name": "Maria Santos",
"email": "[email protected]"
},
"tickets_solved": 127,
"average_rating": 4.8,
"average_response_time_minutes": 120,
"average_resolution_time_minutes": 405,
"satisfaction_rate": 0.95
},
{
"position": 2,
"agent": {
"id": "uuid",
"name": "João Silva",
"email": "[email protected]"
},
"tickets_solved": 98,
"average_rating": 4.6,
"average_response_time_minutes": 145,
"average_resolution_time_minutes": 440,
"satisfaction_rate": 0.91
}
]
}
🏢 Organização
Obter Organização
GET https://acme.pumahelp.com.br/v1/organizations
Authorization: Bearer {token}
Scope: organization:read
Response: 200 OK
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Acme Corporation",
"app_name": "acme",
"subscription_status": "active",
"created_at": "2025-01-01T10:00:00Z"
}
📁 Upload de Arquivos
Upload de Arquivo
POST https://acme.pumahelp.com.br/v1/uploads
Authorization: Bearer {token}
Content-Type: multipart/form-data
Scope: file:upload
Limite: 50MB por arquivo
Request Body (multipart):
file: (binary data)
Response: 201 Created
{
"id": "uuid",
"file_name": "screenshot.png",
"content_type": "image/png",
"size": 102400,
"content_url": "https://cdn.pumahelp.com.br/files/abc123xyz789"
}
Tipos de Arquivo Suportados:
- Imagens:
.jpg,.jpeg,.png,.gif,.webp - Documentos:
.pdf,.doc,.docx,.xls,.xlsx,.txt - Outros:
.zip,.rar,.csv
Exemplo:
curl -X POST https://acme.pumahelp.com.br/v1/uploads \
-H "Authorization: Bearer SEU_TOKEN" \
-F "file=@/caminho/para/arquivo.png"
Exemplo com JavaScript:
const formData = new FormData();
formData.append('file', fileInput.files[0]);
fetch('https://acme.pumahelp.com.br/v1/uploads', {
method: 'POST',
headers: {
'Authorization': 'Bearer SEU_TOKEN'
},
body: formData
})
.then(res => res.json())
.then(data => {
console.log('Arquivo enviado:', data.content_url);
});
Após o upload, use o id retornado para anexar o arquivo a um comentário ao criar ou atualizar um ticket.
🔍 Escopos Disponíveis
Listar Escopos
GET https://acme.pumahelp.com.br/v1/scopes?category=ticket
Authorization: Bearer {token}
Scope: Público (qualquer usuário autenticado)
Query Parameters:
| Parâmetro | Tipo | Descrição | Obrigatório |
|---|---|---|---|
category | string | Filtrar por categoria | Não |
Response: 200 OK
{
"count": 15,
"categories_count": {
"ticket": 5,
"user": 4,
"group": 3,
"macro": 3
},
"scopes": [
{
"scope": "ticket:read",
"name": "Ler Tickets",
"description": "Permite visualizar tickets",
"category": "ticket"
},
{
"scope": "ticket:create",
"name": "Criar Tickets",
"description": "Permite criar novos tickets",
"category": "ticket"
}
]
}
⚙️ Configurações de Conta
Alterar Email
POST https://acme.pumahelp.com.br/v1/account/email/change
Authorization: Bearer {token}
Content-Type: application/json
Scope: account:update:own
Request Body:
{
"new_email": "[email protected]",
"password": "senha-atual"
}
Response: 204 No Content
Solicitar Redefinição de Senha
POST https://acme.pumahelp.com.br/v1/account/password/forgot
Content-Type: application/json
Rate Limit: IP-based
Endpoint público. Envia email com token de redefinição.
Request Body:
{
"email": "[email protected]"
}
Response: 204 No Content
Redefinir Senha
POST https://acme.pumahelp.com.br/v1/account/password/reset
Content-Type: application/json
Rate Limit: IP-based
Request Body:
{
"token": "token-recebido-por-email",
"new_password": "nova-senha-segura"
}
Response: 204 No Content
Alterar Senha
PUT https://acme.pumahelp.com.br/v1/account/password/change
Authorization: Bearer {token}
Content-Type: application/json
Scope: account:update:own
Request Body:
{
"current_password": "senha-atual",
"new_password": "nova-senha-segura"
}
Response: 204 No Content
❌ Códigos de Erro
A API retorna códigos HTTP padrão:
| Código | Significado | Descrição |
|---|---|---|
200 | OK | Requisição bem-sucedida |
201 | Created | Recurso criado com sucesso |
204 | No Content | Recurso excluído com sucesso |
400 | Bad Request | Dados inválidos na requisição |
401 | Unauthorized | Token inválido ou ausente |
403 | Forbidden | Sem permissão (scope insuficiente) |
404 | Not Found | Recurso não encontrado |
409 | Conflict | Conflito (ex: email já existe) |
422 | Unprocessable Entity | Validação falhou |
429 | Too Many Requests | Rate limit excedido |
500 | Internal Server Error | Erro no servidor |
Formato de Erro:
{
"errors": [
"O campo 'email' é obrigatório",
"O campo 'password' deve ter no mínimo 8 caracteres"
]
}
Quick Start
# 1. Login (substitua 'acme' pelo seu subdomínio)
curl -X POST https://acme.pumahelp.com.br/v1/users/login \
-H "Content-Type: application/json" \
-d '{
"email": "[email protected]",
"password": "senha"
}'
# Response:
# {
# "access_token": "eyJhbGc...",
# "refresh_token": "eyJhbGc..."
# }
# 2. Criar API Key (opcional, para integrações)
curl -X POST https://acme.pumahelp.com.br/v1/keys \
-H "Authorization: Bearer SEU_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Minha Integração",
"scopes": ["ticket:create", "ticket:read"]
}'
# 3. Criar Ticket (com JWT)
curl -X POST https://acme.pumahelp.com.br/v1/tickets \
-H "Authorization: Bearer SEU_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"subject": "Meu primeiro ticket via API",
"priority": "normal",
"type": "question",
"comment": {
"body": "Testando a integração com a API",
"public": true
}
}'
# OU com API Key
curl -X POST https://acme.pumahelp.com.br/v1/tickets \
-H "X-API-Key: SEU_API_KEY_SECRET" \
-H "Content-Type: application/json" \
-d '{...}'
# 4. Listar Tickets
curl -X GET "https://acme.pumahelp.com.br/v1/tickets?page=1&page_size=10" \
-H "Authorization: Bearer SEU_ACCESS_TOKEN"
Substitua acme em todos os exemplos pelo seu App Name configurado no dashboard.
💡 Melhores Práticas
Segurança
- ✅ Use HTTPS sempre
- ✅ Nunca exponha secrets no código versionado
- ✅ Rotacione API Keys regularmente
- ✅ Use princípio do menor privilégio (scopes mínimos necessários)
- ✅ Valide assinaturas HMAC dos webhooks
Performance
- ✅ Use paginação adequada (
page_sizeadequado) - ✅ Implemente retry logic com backoff exponencial
- ✅ Cache dados que mudam pouco
- ✅ Monitore headers
X-RateLimit-* - ✅ Use webhooks em vez de polling
Integração
- ✅ Valide dados antes de enviar
- ✅ Trate todos os códigos de erro
- ✅ Implemente logs para auditoria
- ✅ Teste em ambiente de desenvolvimento primeiro
🔧 Troubleshooting
Erro 401: Unauthorized
Sintoma: Todas as requisições retornam 401 Unauthorized
Causas Comuns:
- Token JWT expirado
- API Key inválida ou revogada
- Header de autorização mal formatado
Soluções:
# Verifique o formato do header
# ✅ Correto:
Authorization: Bearer eyJhbGci...
# ❌ Incorreto:
Authorization: eyJhbGci...
Authorization: bearer eyJhbGci...
# Para API Key:
# ✅ Correto:
X-API-Key: rk_live_abc123...
# Renovar token expirado:
curl -X POST https://acme.pumahelp.com.br/v1/tokens/refresh \
-H "Content-Type: application/json" \
-d '{"refresh_token": "SEU_REFRESH_TOKEN"}'
Erro 403: Forbidden
Sintoma: Request autenticado mas retorna 403 Forbidden
Causas Comuns:
- API Key sem o scope necessário
- Usuário sem permissão para a ação
Soluções:
# Verificar scopes da sua API Key:
curl -X GET https://acme.pumahelp.com.br/v1/keys \
-H "Authorization: Bearer SEU_TOKEN"
# Verificar scopes disponíveis:
curl -X GET https://acme.pumahelp.com.br/v1/scopes \
-H "Authorization: Bearer SEU_TOKEN"
# Atualizar API Key com scopes necessários ou criar nova
Erro 422: Unprocessable Entity
Sintoma: Request retorna 422 com mensagem de validação
Causas Comuns:
- Campos obrigatórios faltando
- Formato de dados inválido
- Valor fora do range permitido
Exemplo de Response:
{
"errors": [
"O campo 'subject' é obrigatório",
"O campo 'priority' deve ser: low, normal, high ou urgent"
]
}
Soluções:
- Revise a documentação do endpoint para campos obrigatórios
- Verifique tipos de dados esperados
- Valide valores enum (status, priority, type)
Erro 429: Too Many Requests
Sintoma: Requests bloqueados com 429 Too Many Requests
Causa: Rate limit excedido
Solução:
// Implementar retry com backoff exponencial
async function requestWithRetry(url, options, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
const response = await fetch(url, options);
if (response.status === 429) {
const retryAfter = response.headers.get('Retry-After') || 10;
const delay = Math.pow(2, i) * 1000; // Backoff exponencial
await new Promise(resolve => setTimeout(resolve, Math.max(delay, retryAfter * 1000)));
continue;
}
return response;
}
throw new Error('Max retries exceeded');
}
Webhook Não Está Sendo Chamado
Sintomas:
- Webhook criado mas não recebe eventos
- Eventos não aparecem nos logs
Checklist:
- ✅ URL está acessível publicamente (não localhost)?
- ✅ URL usa HTTPS?
- ✅ Servidor responde com
200 OKem menos de 30 segundos? - ✅ Eventos selecionados estão corretos?
Testar Webhook:
# Verificar status do webhook:
curl -X GET https://acme.pumahelp.com.br/v1/webhooks/{webhook_id} \
-H "Authorization: Bearer SEU_TOKEN"
# Criar evento de teste (criar ticket):
curl -X POST https://acme.pumahelp.com.br/v1/tickets \
-H "X-API-Key: SEU_API_KEY" \
-H "Content-Type: application/json" \
-d '{"subject": "Teste Webhook", "priority": "normal", "type": "question", "comment": {"body": "Teste", "public": true}}'
FAQ
P: Posso usar a mesma API Key em múltiplos ambientes?
R: Não é recomendado. Crie API Keys separadas para desenvolvimento, staging e produção.
P: Quantos webhooks posso criar?
R: Máximo de 5 webhooks por organização. Recomendamos consolidar eventos relacionados em um único endpoint quando possível.
P: Como sei qual scope usar?
R: Consulte GET /v1/scopes para lista completa. Use o princípio do menor privilégio: apenas os scopes necessários.
P: Posso deletar permanentemente um ticket?
R: Não. DELETE arquiva o ticket (soft delete). Isso preserva histórico e auditoria.
Status de Ticket
new
Ticket recém criado, aguardando primeira atribuição ou triagem.
open
Ticket em andamento, sendo trabalhado por um agente.
pending
Aguardando resposta do cliente ou informação externa.
solved
Ticket resolvido. Cliente pode reabrir se necessário.
closed
Ticket fechado. Não pode ser reaberto.
Prioridades
low - Baixa prioridade
normal - Prioridade normal (padrão)
high - Alta prioridade
urgent - Urgente
Tipos de Ticket
question - Pergunta/dúvida
incident - Problema/erro
problem - Problema complexo que afeta múltiplos usuários
task - Tarefa a ser realizada
Roles de Usuário
end-user
Usuário final, cliente. Pode criar tickets e visualizar apenas seus próprios tickets.
agent
Agente de suporte. Pode visualizar, atualizar e resolver tickets.
admin
Administrador. Pode gerenciar usuários, grupos, configurações e tem acesso completo.
owner
Proprietário da organização. Acesso total incluindo configurações de billing e organização.
Eventos de Webhook
ticket.created - Novo ticket criado
ticket.updated - Ticket atualizado (status, prioridade, assignee, etc)
user.created - Novo usuário criado
user.updated - Usuário atualizado
user.deleted - Usuário deletado
Versão da API: v2.1.0
Última Atualização: Dezembro de 2025