Comece em 15 minutos

Do primeiro request ao primeiro webhook. Tudo no sandbox, sem tocar em nada real.

0. O que você precisa

Uma credencial hp_test_… fornecida pela agência que administra sua conta. Ela aponta para uma subconta de teste com dados fictícios.

export HAPEE_KEY="hp_test_..."
export HAPEE_URL="https://beta.hapee.ai/api/v1"

1. Confirmar que a credencial funciona · 1 min

curl -s "$HAPEE_URL/me" -H "Authorization: Bearer $HAPEE_KEY"
{
  "key": { "id": 44, "name": "Mi ERP sandbox", "mode": "test",
           "read_only": false, "scoped_to_subaccount": true },
  "subaccount": { "id": 91, "name": "Cliente — Sandbox",
                  "timezone": "America/Santiago", "default_currency": "CLP",
                  "sandbox": true, "language": "es" },
  "limits": { "requests_per_minute": 100, "batch_max_items": 100,
              "events_retention_days": 30, "idempotency_window_hours": 24 },
  "api_version": "v1"
}

Verifique se sandbox diz true. Se disser false, pare aqui: essa credencial aponta para dados reais.

2. Criar um contato · 2 min

curl -s -X POST "$HAPEE_URL/contacts/upsert" \
  -H "Authorization: Bearer $HAPEE_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: meu-primeiro-teste-001" \
  -d '{
    "external_id": "ERP-DEMO-1",
    "email": "prueba@ejemplo.cl",
    "first_name": "Ana", "last_name": "Pérez",
    "phone": "+56912345678",
    "rut": "12.345.678-5"
  }'
{ "data": { "id": 90211, "email": "prueba@ejemplo.cl", "…": "…" },
  "created": true }

external_id é o id do seu sistema. É o que permite repetir a carga sem duplicar: na segunda vez ele atualiza em vez de criar.

3. Testar que a idempotência funciona · 2 min

Execute o mesmo comando outra vez, sem mudar nada. Você receberá a mesma resposta e o header Idempotent-Replay: true. Nenhum segundo contato foi criado.

Agora execute uma terceira vez, mudando first_name mas mantendo a mesma Idempotency-Key:

{ "error": {
    "code": "idempotency_key_reusada",
    "message": "Esta Idempotency-Key ya se usó con un cuerpo distinto..."
} }

Isso está correto: a mesma chave com outro corpo significa que você a reutilizou para outra coisa. Uma chave por operação.

4. Registrar um webhook · 5 min

Você precisa de uma URL pública. Para testar na sua máquina, abra um túnel:

ngrok http 3000     # dá algo como https://a1b2c3.ngrok-free.app
curl -s -X POST "$HAPEE_URL/webhooks/endpoints" \
  -H "Authorization: Bearer $HAPEE_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://a1b2c3.ngrok-free.app/hooks",
    "description": "Testes locais",
    "events": ["*"]
  }'

Salve o secret agora. Ele só é exibido completo uma vez. Depois você verá apenas whsec_…aB3d.

Receptor mínimo

const express = require('express');
const crypto = require('crypto');
const app = express();

const SECRETO = 'whsec_aB3dE...';

app.post('/hooks', express.raw({ type: 'application/json' }), (req, res) => {
  const crudo = req.body.toString('utf8');
  const cab = req.get('X-Hapee-Signature') || '';
  const { t, v1 } = Object.fromEntries(
    cab.split(',').map(p => p.split('=').map(s => s.trim())));

  const esperado = crypto.createHmac('sha256', SECRETO)
                         .update(`${t}.${crudo}`).digest('hex');
  if (esperado !== v1) return res.sendStatus(401);

  console.log('evento:', JSON.parse(crudo).type);
  res.sendStatus(200);
});

app.listen(3000);

Em produção é necessária uma comparação em tempo constante e uma janela de atualidade. A versão completa está em Webhooks, com exemplos em Node, Python, PHP e C#.

5. Disparar o primeiro evento · 1 min

curl -s -X POST "$HAPEE_URL/webhooks/endpoints/12/ping" \
  -H "Authorization: Bearer $HAPEE_KEY"

No seu console: evento: webhook.test

E agora um de verdade — atualize o contato do passo 2:

curl -s -X POST "$HAPEE_URL/contacts/upsert" \
  -H "Authorization: Bearer $HAPEE_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: meu-primeiro-teste-002" \
  -d '{"external_id": "ERP-DEMO-1", "match_by": "external_id",
       "first_name": "Ana María"}'

No seu console: evento: contact.updated

Os eventos são disparados por tudo o que acontece na subconta, não apenas pelo que você faz. Se alguém da equipe comercial mover um negócio para «ganho» pelo aplicativo, você recebe do mesmo jeito.

6. Se você não pode expor uma URL · 2 min

O mesmo, mas consultando você mesmo:

curl -s "$HAPEE_URL/events?limit=10" -H "Authorization: Bearer $HAPEE_KEY"

Guarde o next_cursor e passe-o na próxima vez. Mesmos eventos, mesmo corpo.

7. Ver o que aconteceu com uma entrega

curl -s "$HAPEE_URL/webhooks/deliveries?endpoint_id=12" \
  -H "Authorization: Bearer $HAPEE_KEY"

Cada entrega mostra seu status, quantas tentativas já fez, o que seu endpoint respondeu e quando é a próxima tentativa.

Pronto. E agora?

Antes de ir para produção, o checklist está no final do guia de integração. Ir para o live é trocar a credencial e a URL do webhook: nada mais.