Autenticação
Como criar a conta, gerar e revogar API keys (self-service), os modos teste/produção (host sandbox./api. + prefixo pzk_test_/pzk_live_ que casam), o header Authorization, o fallback ?token= para SSE e todos os erros (401, 402, 403, 429).
Toda requisição à API do PEPINO ZAP é autenticada por uma API key, escopada a um Projeto. A key identifica quem está chamando e a qual Projeto pertence: todas as instâncias, conversas e mensagens criadas ou listadas com uma key pertencem ao Projeto dela. Não há login/senha nas chamadas de API — só a key, enviada em cada requisição.
A geração de keys é self-service: você cria e revoga quantas quiser pelo painel, sem depender da autorização de um operador. Esta página cobre o fluxo completo, ponta a ponta:
- Criar a conta e confirmar o e-mail.
- Escolher o modo (teste ou produção) e gerar a key.
- Enviar a key nas requisições (header
Authorization). - O caso especial do SSE de QR Code (fallback
?token=). - Todos os erros que a autenticação pode retornar (
401,402,403,429) e como resolver cada um.
Resumo em uma frase: o host decide o modo (sandbox.* = teste, api.* =
produção) e a key tem que casar com ele (pzk_test_ no sandbox,
pzk_live_ na produção). Key no host errado retorna 401.
Criando a conta e gerando keys
A conta e as keys nascem no painel. O fluxo abaixo é feito uma vez; depois você só gera/revoga keys conforme precisar.
- Cadastre-se (empresa, CNPJ, e-mail e senha) em
app.pepinozap.com.br. O cadastro exige confirmação de e-mail — você recebe um link logo após o envio do formulário. - Confirme o e-mail pelo link enviado. O login só é liberado depois da confirmação — antes disso, tentar entrar não funciona.
- Faça login no painel e vá em Integrações → API Keys. No topo de Integrações há um toggle Teste / Produção — escolha o modo desejado antes de gerar a key.
- Clique em gerar, dê um nome à key (ele só serve para você identificá-la na lista — não aparece para ninguém) e, opcionalmente, defina uma validade.
A key crua aparece uma única vez, no momento da criação. Guarde-a em local seguro (um gerenciador de segredos, uma variável de ambiente do seu servidor). Não há como recuperá-la depois — o painel só guarda um hash e um prefixo de exibição. Se você perder a key, revogue-a e crie outra.
O modo da key é o do toggle no momento em que ela foi gerada e fica gravado nela para sempre:
- toggle em Teste → key começa com
pzk_test_; - toggle em Produção → key começa com
pzk_live_.
O nome da key é obrigatório. Gerar sem nome retorna 400 com a mensagem
"nome obrigatório (identifica a key na listagem)". Escolha algo que diga onde a
key é usada (ex.: backend-producao, integracao-erp) — isso facilita
revogar a certa depois.
Anatomia de uma API key
Uma key crua tem a forma pzk_<modo>_<segredo>, por exemplo:
pzk_test_k4m2qz7r3v8n6t1p9s5w0xab
└──┬───┘ └──────────┬───────────┘
prefixo segredo (aleatório)- Prefixo (
pzk_test_oupzk_live_): indica o modo. É por ele que a API decide, logo de cara, se a key combina com o host. - Segredo: parte aleatória de alta entropia. É o que você não deve expor. O painel mostra apenas um prefixo de exibição (o prefixo do modo + os 6 primeiros caracteres do segredo) para você reconhecer a key na lista sem revelá-la inteira.
Modos: teste e produção
Uma única conta, com dois modos — no mesmo espírito do test/live do Stripe. Não há conta nem ambiente separado: é a mesma conta, os mesmos logins. O que muda é o modo da requisição, e o modo é definido pelo host da API. A key tem que casar com o host, mas não é ela que decide o modo.
| Modo | Base URL da API | Prefixo da key | Cobrança |
|---|---|---|---|
| Teste | https://sandbox.pepinozap.com.br | pzk_test_ | grátis, com teto diário |
| Produção | https://api.pepinozap.com.br | pzk_live_ | exige plano ativo |
O host decide o modo; a key tem que casar
O modo é resolvido pelo hostname da URL que você chama:
- host que começa com
sandbox(sandbox.pepinozap.com.br) → modo teste; - qualquer outro host (
api.pepinozap.com.br) → modo produção.
Depois de resolver o modo pelo host, a API confere o prefixo da key: ela precisa ser do mesmo modo. As combinações válidas e inválidas:
| Host | Key | Resultado |
|---|---|---|
sandbox.pepinozap.com.br | pzk_test_... | OK (modo teste) |
api.pepinozap.com.br | pzk_live_... | OK (modo produção) |
sandbox.pepinozap.com.br | pzk_live_... | 401 — key do modo errado |
api.pepinozap.com.br | pzk_test_... | 401 — key do modo errado |
Quando o prefixo não casa com o host, a resposta é 401 UNAUTHORIZED com a mensagem "chave de API inválida para este ambiente/modo". Esse erro é, na prática, o engano mais comum: usar uma key de teste apontando para api.*, ou vice-versa. Antes de investigar qualquer outra coisa, confirme que o prefixo da key bate com o host.
Isolamento de dados por modo
Os dados são isolados por modo. Instâncias, conversas e webhooks criados em Teste nunca aparecem em Produção, e vice-versa. Consequências práticas:
- Uma instância criada no sandbox não existe em produção (consultá-la lá dá
404). - Listar keys/instâncias retorna apenas as do modo da requisição.
- No painel, o toggle filtra o que você vê em Integrações. O CRM (Inbox, Funil) é sempre Produção.
Se um GET por id retornar 404 ("instância não encontrada") mesmo você
"tendo certeza" de que ela existe, verifique se não está chamando o host do
modo errado. Recurso de teste só aparece no sandbox.*; recurso de produção
só no api.*.
Teste é grátis; produção exige plano
O modo teste é grátis e self-service: criar instâncias e enviar mensagens não exigem plano ativo — você valida a integração inteira sem assinar nada. Para que o teste grátis não vire "produção de graça", ele tem um teto diário de 100 mensagens por dia, por Projeto (enviadas + recebidas; o dia fecha à meia-noite no fuso de São Paulo). Ao ultrapassar o teto, os envios retornam 429 RATE_LIMITED.
A produção exige uma assinatura ativa no Projeto para as ações de uso real (conectar número, enviar mensagem) — é o 402 detalhado mais abaixo. Resumindo: teste à vontade no sandbox e só pague ao ir para produção.
Gerando keys pela API (self-service)
Além do botão no painel, você pode gerar, listar e revogar keys pela API, sob o grupo /v1/keys. Isso é útil para automatizar a rotação de chaves.
Gerenciar keys exige login de usuário (a sessão do painel, um token de
usuário) — uma API key não pode gerar outras. Se você chamar /v1/keys
autenticando com uma pzk_..., recebe 403 com "gestão de chaves requer login
de usuário". Isso é proposital: limita o estrago caso uma key vaze (ela não
consegue se "auto-multiplicar"). Os exemplos desta seção assumem o token de
usuário do painel no Authorization.
Obtendo o token de usuário — POST /v1/auth/login
No navegador, a sessão do painel vive em cookies httpOnly (o token não é exposto ao JavaScript). Para automatizar a rotação de keys do seu backend, chame o login server-to-server pedindo o token no corpo com o header X-Token-Response: body:
curl -X POST https://api.pepinozap.com.br/v1/auth/login \
-H "Content-Type: application/json" \
-H "X-Token-Response: body" \
-d '{ "email": "voce@empresa.com", "password": "sua-senha" }'Resposta 200 OK com accessToken (curto) e refreshToken. Use o accessToken como Bearer <TOKEN_DE_USUARIO> nos exemplos abaixo. Sem esse header, o login responde só com a sessão em cookie (o fluxo do painel) — nunca chame o login com credencial de usuário a partir do navegador de uma página pública.
Criar uma key — POST /v1/keys
Corpo da requisição:
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
name | string | sim | Identifica a key na listagem. Não pode ser vazio. |
expiresInDays | número | não | Validade em dias a partir de agora (inteiro >= 1). Sem este campo, a key não expira. |
O modo da key gerada (e portanto o prefixo pzk_test_/pzk_live_) segue o modo da requisição — no painel/API de usuário, o toggle Teste/Produção.
curl -X POST https://api.pepinozap.com.br/v1/keys \
-H "Authorization: Bearer <TOKEN_DE_USUARIO>" \
-H "Content-Type: application/json" \
-d '{ "name": "backend-producao", "expiresInDays": 90 }'Resposta 201 Created — repare no campo key com a key crua (aparece só aqui, uma vez):
{
"id": "key_abc123",
"name": "backend-producao",
"keyPrefix": "pzk_live_k4m2qz",
"status": "active",
"lastUsedAt": null,
"expiresAt": "2026-09-03T12:00:00Z",
"revokedAt": null,
"createdAt": "2026-06-05T12:00:00Z",
"key": "pzk_live_k4m2qz7r3v8n6t1p9s5w0xab"
}key— a key crua completa. Guarde-a agora; ela não volta a aparecer.keyPrefix— o prefixo de exibição (modo + 6 caracteres), seguro de logar/mostrar.status—active,revokedouexpired, derivado derevokedAt/expiresAt.expiresAt—nullse você não enviouexpiresInDays.
Criar uma key em produção exige plano ativo (gerar key = habilitar uso
via integração). Sem assinatura, POST /v1/keys retorna 402
(PAYMENT_REQUIRED). Em teste, gerar keys é livre. Ver
Plano ativo (erro 402).
Listar suas keys — GET /v1/keys
Retorna apenas as keys do modo atual (o toggle Teste/Produção filtra). A key crua não é incluída — só metadados.
curl https://api.pepinozap.com.br/v1/keys \
-H "Authorization: Bearer <TOKEN_DE_USUARIO>"Resposta 200 OK:
{
"items": [
{
"id": "key_abc123",
"name": "backend-producao",
"keyPrefix": "pzk_live_k4m2qz",
"status": "active",
"lastUsedAt": "2026-06-05T13:40:00Z",
"expiresAt": "2026-09-03T12:00:00Z",
"revokedAt": null,
"createdAt": "2026-06-05T12:00:00Z"
}
]
}O campo lastUsedAt ajuda a identificar keys ociosas (candidatas a revogar). Ele é atualizado de forma assíncrona a cada uso, então pode levar alguns instantes para refletir a última chamada.
Revogar uma key — DELETE /v1/keys/{id}
Revoga imediatamente a key indicada (use o id, não o keyPrefix). A partir daí, qualquer requisição com aquela key retorna 401.
curl -X DELETE https://api.pepinozap.com.br/v1/keys/key_abc123 \
-H "Authorization: Bearer <TOKEN_DE_USUARIO>"Sucesso: 204 No Content (sem corpo). Se o id não existir, não for do seu Projeto, ou for de outro modo, a resposta é 404 ("chave não encontrada").
A revogação é definitiva e não tem desfazer. Não dá para "reativar" uma key revogada — gere uma nova. Por isso, ao trocar uma chave em produção, gere a nova e atualize sua aplicação primeiro, e só então revogue a antiga, evitando uma janela sem key válida.
Como enviar a API key
Em todas as chamadas REST, envie a key no header Authorization com o esquema Bearer:
curl https://sandbox.pepinozap.com.br/v1/instances \
-H "Authorization: Bearer pzk_test_xxxxxxxxxxxxxxxx"Exemplo com fetch (JavaScript):
const res = await fetch('https://sandbox.pepinozap.com.br/v1/instances', {
headers: {
Authorization: 'Bearer pzk_test_xxxxxxxxxxxxxxxx',
},
});Pontos de atenção ao montar o header:
- O esquema
Bearer(com um espaço) é obrigatório. Mandar a key "pelada", semBearer, é tratado como ausência de Authorization →401. - A key não vai na URL nem no corpo — só no header (exceção: o SSE de QR, a seguir).
- Use sempre HTTPS. A key é um segredo de acesso total ao Projeto.
Fallback ?token= (apenas para SSE)
O endpoint de QR Code via stream (GET /v1/instances/{id}/qr) usa Server-Sent Events. O EventSource do navegador não envia headers customizados, então não há como mandar o Authorization nesse caso. Para esse endpoint — e somente para ele — a API aceita a credencial na query string, no parâmetro ?token=.
Há duas formas de preencher o ?token=:
-
A própria key crua (mais simples). Funciona, mas coloca a key na URL:
curl -N "https://sandbox.pepinozap.com.br/v1/instances/{id}/qr?token=pzk_test_xxxxxxxxxxxxxxxx" -
Um token efêmero de SSE (recomendado para o navegador). Gere com
POST /v1/instances/{id}/qr-tokene use o token retornado no?token=. Esse token é curto (validade ~2 min) e escopado a uma única instância (só vale na rota de QR daquela instância), limitando o impacto se vazar em um log ou noReferer.
const id = 'inst_...';
const token = 'pzk_test_xxxxxxxxxxxxxxxx'; // ou o token efêmero de qr-token
const source = new EventSource(
`https://sandbox.pepinozap.com.br/v1/instances/${id}/qr?token=${token}`,
);Utilize ?token= exclusivamente no endpoint SSE de QR. Nas demais
chamadas, use sempre o header Authorization — a query string aparece em logs
de servidor, proxies e no Referer, então expor a key crua ali é arriscado.
Para o QR no navegador, prefira o token efêmero de qr-token justamente por
isso. O passo a passo do pareamento está em
Sua primeira instância.
Erros esperados
Todos os erros da API seguem o mesmo envelope:
{
"error": {
"code": "UNAUTHORIZED",
"message": "explicação legível do que aconteceu"
}
}code— rótulo estável, derivado do status HTTP. Use-o para tratar o erro no seu código (é mais confiável que comparar amessage).message— texto legível, em português, que diz o que deu errado.
Os status que a autenticação pode retornar:
| Status | code | Quando ocorre |
|---|---|---|
401 | UNAUTHORIZED | Key ausente, malformada, inválida, revogada, expirada, ou do modo errado para o host. |
402 | PAYMENT_REQUIRED | O Projeto não tem plano ativo (ou créditos da API zerados). Ver Plano ativo. |
403 | FORBIDDEN | Projeto inativo (key válida, mas o Projeto não está ACTIVE); ou gestão de keys tentada sem login de usuário. |
429 | RATE_LIMITED | Apenas no modo teste: teto diário do Projeto atingido (100 mensagens/dia, enviadas + recebidas). Em produção não ocorre. |
Detalhando o 401 UNAUTHORIZED
O 401 cobre várias causas. A message distingue cada uma — vale tratá-las separadamente ao depurar:
message | Causa | Como resolver |
|---|---|---|
Authorization Bearer ou ?token= ausente | Nenhuma credencial foi enviada (faltou o header, ou veio sem Bearer). | Envie Authorization: Bearer <key>. |
chave de API inválida para este ambiente/modo | O prefixo da key não bate com o host (pzk_live_ no sandbox ou pzk_test_ na produção). | Use a key do modo correto para o host (ver O host decide o modo). |
token ou chave de API inválido | A key não corresponde a nenhuma key existente (digitada errada, truncada, ou inexistente). | Confira se copiou a key inteira. Se perdeu a key, gere outra. |
chave de API revogada | A key foi revogada (no painel ou via DELETE /v1/keys/{id}). | Gere uma key nova. |
chave de API expirada | A key passou da validade definida em expiresInDays. | Gere uma key nova (sem expiresInDays, ou com prazo maior). |
Exemplo de resposta 401:
{
"error": {
"code": "UNAUTHORIZED",
"message": "chave de API inválida para este ambiente/modo"
}
}Há um 401 específico do painel (login de usuário), não da API key: o
code SESSION_SUPERSEDED, emitido quando a mesma conta é aberta em outro
dispositivo (a sessão única invalida a anterior). API keys não têm sessão e
nunca recebem esse erro — ele só aparece em chamadas autenticadas com o token de
usuário do painel. Ao recebê-lo, faça login de novo.
O 403 FORBIDDEN
O 403 significa que a credencial é válida, mas a ação não é permitida no estado atual:
- Projeto inativo — a key é reconhecida, mas o Projeto dela não está com status
ACTIVE(suspenso, por exemplo).message: "projeto não está ativo". A regularização é feita pelo time PEPINO; entre em contato. - Gestão de keys sem login de usuário — você tentou
/v1/keysautenticando com uma API key em vez do token de usuário.message: "gestão de chaves requer login de usuário". Use a sessão do painel.
Exemplo de resposta 403:
{
"error": {
"code": "FORBIDDEN",
"message": "projeto não está ativo"
}
}Plano ativo (erro 402)
Ter uma API key válida não basta para operar em produção. As ações de uso real — conectar um número e enviar mensagens — exigem uma assinatura ativa no Projeto (modelo "pague antes, use depois"). Como a key é escopada a um Projeto, a regra vale igualmente para o painel e para a integração via API. No modo teste, esse erro nunca ocorre (teste é grátis).
Só a assinatura com status active libera. Qualquer outro estado (sem assinatura, pending, paused, past_due, canceled) resulta em 402.
Endpoints que retornam 402 sem plano ativo (em produção):
POST /v1/instances— criar instância;POST /v1/instances/{id}/messagese os demais envios sob/v1/instances/{id}/messages/(/media,/media-upload,/location,/contact,/sticker,/reaction,/poll);POST /v1/keys— gerar API key (habilitar uso via integração).
Endpoints de leitura (listar/detalhar instâncias e keys), o pareamento por QR Code e marcar como lida continuam liberados mesmo sem plano ativo — você consegue inspecionar o estado, mas não produzir tráfego.
Exemplo de resposta 402:
{
"error": {
"code": "PAYMENT_REQUIRED",
"message": "É necessário um plano ativo para usar este recurso. Assine em \"Meu plano\"."
}
}Como resolver: assine um plano em Meu plano, no painel. Assim que a
assinatura fica active, as chamadas voltam a funcionar sem alterar uma
linha de código — não é preciso gerar nova key. Projetos de cortesia,
marcados como isentos pelo time PEPINO, nunca recebem este erro.
Créditos da API insuficientes
Além da falta de plano, o 402 também aparece por créditos zerados. Projetos no modo API consomem créditos pré-pagos a cada mensagem enviada pela API (envios feitos pelo painel não consomem créditos). Quando o saldo zera, os endpoints de envio passam a retornar 402 com code PAYMENT_REQUIRED, e a message indica créditos insuficientes.
A resolução é recarregar créditos em Meu plano. Distinga os dois casos 402 pela message: falta de plano ativo (texto sobre assinar) versus falta de créditos (texto sobre recarregar) — a ação a tomar é diferente em cada um.
Add-on de campanhas (disparo em massa)
As rotas de campanhas (/v1/campaigns, criação/disparo) têm uma exigência extra: além do plano ativo, o Projeto precisa do add-on "Disparo em massa". Sem ele, criar/disparar campanha retorna 402 com a mensagem orientando a ativar o add-on em Meu plano. Leitura de campanhas é livre, e no modo teste o add-on não é exigido. (Detalhes na documentação de campanhas.)
Boas práticas de segurança
- Trate a key como senha. Quem tiver a key tem acesso total ao Projeto. Não a coloque em repositórios, front-end, prints ou tickets de suporte.
- Use variáveis de ambiente / cofre de segredos no servidor — nunca hardcode a key no código.
- Uma key por integração. Dê nomes claros (ex.:
backend-prod,worker-fila). Assim, se uma vazar, você revoga só ela sem derrubar as outras. - Defina validade (
expiresInDays) em keys de vida curta (scripts, testes pontuais) para que expirem sozinhas. - Rotacione com janela de transição: gere a nova key, atualize a aplicação, confirme que funciona e só então revogue a antiga.
- Comece pelo modo teste. Valide a integração inteira no
sandbox.*com umapzk_test_antes de gerar apzk_live_e ligar a produção.
Próximos passos
- Quick start — a primeira chamada de ponta a ponta.
- Criar a primeira instância — criar, parear por QR Code e configurar uma instância.
Quick start
Integração mínima ao PEPINO ZAP, ponta a ponta — da API key ao envio da primeira mensagem e ao recebimento de eventos, com cada request e cada resposta.
Sua primeira instância
Ciclo de vida de uma instância no Pepino Zap — criar, parear com o WhatsApp por QR Code (polling ou SSE), consultar, remover e tratar os erros de cada etapa.