Pular para o conteúdo principal

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
observação

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


📝 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
}
important

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:

  1. Faça login na plataforma PumaHelp
  2. Navegue até Configurações → API Keys
  3. Clique em "Criar Nova API Key"
  4. Selecione os scopes necessários
  5. 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
important

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çãoComportamento
JWT (Login)Scopes atribuídos automaticamente baseados na role do usuário
API KeyScopes 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"
}
}
CampoTipoObrigatórioDescrição
subjectstringSimAssunto do ticket
prioritystringNãoPrioridade: low, normal, high, urgent (padrão: normal)
typestringNãoTipo: question, incident, problem, task
group_iduuidNãoID do grupo responsável
requesterobjectNãoDados do solicitante (se criar em nome de outro usuário)
requester.namestringNãoNome do solicitante
requester.emailstringNãoEmail do solicitante
requester.external_idstringNãoID externo do solicitante
requester.iduuidNãoID do solicitante
commentobjectSimPrimeiro comentário do ticket
comment.bodystringSimConteúdo do comentário
comment.publicbooleanNãoSe visível para o cliente (padrão: true)
comment.author_iduuidNãoID do autor (se diferente do usuário autenticado)
comment.uploadsarray[uuid]NãoIDs de arquivos anexados
tagsarray[string]NãoTags para categorização
viaobjectNãoCanal de origem
via.channelstringNãoCanal: 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âmetroTipoDescriçãoObrigatório
pageintegerNúmero da páginaSim
page_sizeintegerItens por página (max: 100)Sim
querystringQuery language para filtros avançadosNão
sort_bystringCampo para ordenação: created_at, updated_at, priority, statusNão
sort_orderstringOrdem: asc ou descNão
includearray[string]Campos extras: assignee, requester, last_comment, tagsNã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"]
}
}
CampoTipoDescrição
subjectstringNovo assunto
statusstringNovo status: new, open, pending, solved, closed
prioritystringNova prioridade
typestringNovo tipo
requester_iduuidTransferir para outro requester
assignee_iduuidAtribuir a agente (use null para desatribuir)
group_iduuidAtribuir a grupo
archivedbooleanArquivar ticket
tagsarray[string]Substituir tags
commentobjectAdicionar comentário com a atualização
observaçã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

observação

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âmetroValores Aceitos
period24h, 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âmetroValores Aceitos
period24h, 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âmetroTipoDescriçãoPadrãoObrigatório
pageintegerNúmero da página-Sim
page_sizeintegerItens por página (max: 100)-Sim
sort_bystringCampo para ordenação: created_atcreated_atNão
sort_orderstringOrdem: asc ou descascNã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

aviso

O texto entre as tags é substituído por caracteres especiais como ████████ permanentemente.


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

aviso

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

observação

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"
}
CampoTipoObrigatórioDescrição
emailstringSimEmail do usuário
passwordstringSimSenha do usuário

Response: 200 OK

{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"verified": true
}
CampoTipoDescrição
access_tokenstringToken JWT para autenticação (válido por 24h)
refresh_tokenstringToken para renovar o access_token
verifiedbooleanSe 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"]
}
CampoTipoObrigatórioDescrição
namestringSimNome completo do usuário
emailstringNãoEmail do usuário (opcional)
rolestringSimRole: end-user, agent, admin, owner
external_idstringNãoID externo para integração com outros sistemas
verifiedbooleanNãoSe o email deve ser marcado como verificado (padrão: false)
group_idsarray[uuid]NãoIDs 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
}
dica

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"]
}
CampoTipoObrigatórioDescrição
emailstringCondicionalEmail do usuário (obrigatório se external_id não fornecido)
external_idstringCondicionalID externo (obrigatório se email não fornecido)
namestringNãoNome completo (usado apenas se criar novo usuário)
rolestringNãoRole: end-user, agent, admin, owner (padrão: end-user)
verifiedbooleanNãoSe o email deve ser verificado (apenas para criação)
group_idsarray[uuid]NãoIDs dos grupos (apenas para criação)

Response: 200 OK

{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 86400
}
CampoTipoDescrição
access_tokenstringToken JWT para autenticação em nome do usuário
token_typestringSempre "Bearer"
expires_inintegerTempo de expiração em segundos
dica

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).

aviso

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âmetroTipoDescriçãoPadrão
pageintegerNúmero da página1
page_sizeintegerItens por página (max: 100)25
rolesarray[string]Filtrar por roles (pode enviar múltiplos)-
querystringBusca por nome ou email-
external_idstringFiltrar por ID externo-
group_iduuidFiltrar por grupo-
activebooleanFiltrar 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"]
}
CampoTipoDescrição
namestringNome do usuário
rolestringNova role do usuário
emailstringNovo email
notesstringNotas internas (não visível para end-users)
external_idstringID externo
verifiedbooleanStatus de verificação de email
group_idsarray[uuid]Grupos do usuário
observação

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

observação

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

dica

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:

CampoTipoObrigatórioDescrição
namestringNãoNome 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:

CampoTipoDescrição
iduuidID único do usuário convidado
namestringNome do convidado
access_tokenstringToken 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
}
}'
dica

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"
}
CampoTipoObrigatórioDescrição
namestringSimNome do grupo
descriptionstringNãoDescriçã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âmetroTipoDescriçãoObrigatório
pageintegerNúmero da páginaSim
page_sizeintegerItens por páginaSim
querystringBusca por nome ou descriçãoNão
user_iduuidFiltrar grupos que contêm um usuário específicoNã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âmetroTipoDescriçãoObrigatório
pageintegerNúmero da páginaSim
page_sizeintegerItens por páginaSim
querystringBusca por nome ou descriçãoNão
user_iduuidFiltrar grupos que contêm um usuário específicoNã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
}
]
}
]
}
dica

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"
}
CampoTipoDescrição
namestringNovo nome do grupo
descriptionstringNova descrição
observaçã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

observação

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."
}
]
}
CampoTipoObrigatórioDescrição
titlestringSimTítulo da macro
descriptionstringNãoDescrição da macro
typestringSimTipo: user (usuário) ou group (grupo)
group_idsarray[uuid]NãoIDs dos grupos que podem usar esta macro (obrigatório se type=group)
actionsarray[object]SimLista de ações a executar
actions[].fieldstringSimCampo a modificar: comment_value, status, type, priority
actions[].valueanySimValor 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âmetroTipoDescriçãoObrigatório
pageintegerNúmero da páginaSim
page_sizeintegerItens por páginaSim

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"
}
]
}
observação

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"]
}
CampoTipoObrigatórioDescrição
namestringSimNome do webhook
urlstringSimURL que receberá as notificações
eventsarray[string]SimEventos 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"
}
observação

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.

important

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âmetroTipoDescriçãoObrigatório
pageintegerNúmero da páginaSim
page_sizeintegerItens por páginaSim

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"]
}
CampoTipoDescrição
namestringNovo nome do webhook
urlstringNova URL
eventsarray[string]Novos eventos
observação

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.

aviso

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"
}
CampoTipoDescrição
keystringNova 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âmetroTipoDescriçãoObrigatório
pageintegerNúmero da páginaSim
page_sizeintegerItens por páginaSim

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"
}
]
}
CampoTipoDescrição
iduuidID da API Key
prefixstringPrefixo da chave para identificação rápida
namestringNome da API Key
descriptionstringDescrição
scopesarray[string]Escopos atribuídos
key_lookupstringLookup hash para busca interna
created_atdatetimeData 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"]
}
CampoTipoObrigatórioDescrição
namestringSimNome da API Key
descriptionstringNãoDescrição do uso da chave
scopesarray[string]SimLista de escopos permitidos

Response: 201 Created

{
"key": "rk_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0"
}
cuidado

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"]
}
CampoTipoDescrição
namestringNovo nome
descriptionstringNova descrição
scopesarray[string]Novos escopos
observação

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"
}
aviso

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

cuidado

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);
});
observação

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âmetroTipoDescriçãoObrigatório
categorystringFiltrar por categoriaNã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

observação

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ódigoSignificadoDescrição
200OKRequisição bem-sucedida
201CreatedRecurso criado com sucesso
204No ContentRecurso excluído com sucesso
400Bad RequestDados inválidos na requisição
401UnauthorizedToken inválido ou ausente
403ForbiddenSem permissão (scope insuficiente)
404Not FoundRecurso não encontrado
409ConflictConflito (ex: email já existe)
422Unprocessable EntityValidação falhou
429Too Many RequestsRate limit excedido
500Internal Server ErrorErro 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"
dica

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_size adequado)
  • ✅ 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:

  1. Token JWT expirado
  2. API Key inválida ou revogada
  3. 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:

  1. API Key sem o scope necessário
  2. 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:

  1. Campos obrigatórios faltando
  2. Formato de dados inválido
  3. 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:

  1. ✅ URL está acessível publicamente (não localhost)?
  2. ✅ URL usa HTTPS?
  3. ✅ Servidor responde com 200 OK em menos de 30 segundos?
  4. ✅ 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