API

Webhooks

Receba notificações em tempo real sobre eventos da academia.

Webhooks

Webhooks permitem que você receba notificações em tempo real sobre eventos importantes da sua academia: novos alunos, mensalidades ativadas/canceladas, check-ins, reservas de aulas e muito mais.

Configuração via painel

O gerenciamento de webhooks via API ainda não está disponível. Configure seus webhooks diretamente pelo painel do OctaGym em Configurações → Webhooks.

Como Funciona

┌─────────────────────┐     ┌─────────────────────┐     ┌─────────────────────┐
│    Evento Ocorre     │────>│     OctaGym          │────>│   Seu Servidor      │
│  (ex: aluno criado,  │     │   envia POST         │     │   processa e        │
│   check-in, etc.)    │     │   para sua URL       │     │   responde 200 OK   │
└─────────────────────┘     └─────────────────────┘     └─────────────────────┘
  1. Um evento ocorre na plataforma (aluno matriculado, check-in realizado, etc.)
  2. O OctaGym envia uma requisição POST para a URL configurada
  3. Seu servidor processa o evento e responde com 200 OK
  4. Se falhar, tentamos novamente com backoff exponencial

Eventos Disponíveis

Eventos de Alunos (Members)

EventoQuando é Disparado
member.createdNovo aluno cadastrado
member.updatedDados do aluno alterados
member.status_changedStatus alterado (ativo, inativo, trial)

Eventos de Mensalidades (Memberships)

EventoQuando é Disparado
membership.createdNova mensalidade criada
membership.activatedMensalidade ativada (pagamento confirmado)
membership.cancelledMensalidade cancelada
membership.frozenMensalidade congelada
membership.unfrozenMensalidade descongelada
membership.past_dueMensalidade em atraso (pagamento vencido)

Eventos de Aulas (Classes)

EventoQuando é Disparado
class.booking_createdReserva de aula realizada
class.booking_cancelledReserva de aula cancelada

Eventos de Check-in

EventoQuando é Disparado
checkin.createdCheck-in realizado (catraca, app ou manual)

Formato do Payload

Todas as notificações seguem este formato:

{
  "id": "evt_abc123def456",
  "type": "member.created",
  "api_version": "v1",
  "created_at": "2026-03-22T14:30:00Z",
  "data": {
    "object": {
      "id": "uuid-do-aluno",
      "name": "Ana Oliveira",
      "email": "ana@email.com",
      "status": "trial",
      "created_at": "2026-03-22T14:30:00Z"
    },
    "previous_attributes": null
  },
  "team_id": "uuid-da-academia",
  "webhook_id": "uuid-do-webhook"
}

Para eventos de atualização, previous_attributes contém os valores anteriores dos campos alterados:

{
  "id": "evt_update789",
  "type": "member.status_changed",
  "api_version": "v1",
  "created_at": "2026-03-22T15:00:00Z",
  "data": {
    "object": {
      "id": "uuid-do-aluno",
      "name": "Ana Oliveira",
      "status": "active"
    },
    "previous_attributes": {
      "status": "trial"
    }
  },
  "team_id": "uuid-da-academia",
  "webhook_id": "uuid-do-webhook"
}

Exemplo: Mensalidade cancelada

{
  "id": "evt_cancel456",
  "type": "membership.cancelled",
  "api_version": "v1",
  "created_at": "2026-03-22T10:15:00Z",
  "data": {
    "object": {
      "id": "uuid-da-mensalidade",
      "member_id": "uuid-do-aluno",
      "plan_id": "uuid-do-plano",
      "status": "cancelled",
      "cancelled_at": "2026-03-22T10:15:00Z",
      "cancellation_reason": "Mudança de cidade"
    },
    "previous_attributes": {
      "status": "active"
    }
  },
  "team_id": "uuid-da-academia",
  "webhook_id": "uuid-do-webhook"
}

Exemplo: Check-in realizado

{
  "id": "evt_checkin789",
  "type": "checkin.created",
  "api_version": "v1",
  "created_at": "2026-03-22T07:32:00Z",
  "data": {
    "object": {
      "id": "uuid-do-checkin",
      "member_id": "uuid-do-aluno",
      "member_name": "Bruno Santos",
      "method": "qr_code",
      "checked_in_at": "2026-03-22T07:32:00Z"
    },
    "previous_attributes": null
  },
  "team_id": "uuid-da-academia",
  "webhook_id": "uuid-do-webhook"
}

Verificando a Assinatura

Para garantir que a notificação veio do OctaGym, verifique a assinatura HMAC-SHA256 no header X-OctaGym-Signature.

Headers Enviados

HeaderDescrição
X-OctaGym-SignatureAssinatura HMAC-SHA256
X-OctaGym-TimestampTimestamp Unix do envio
X-OctaGym-Event-IdID único do evento
Content-Typeapplication/json

A assinatura é calculada sobre a string {timestamp}.{payload} usando o webhook_secret que você recebe ao criar o webhook no painel.

Verificação em Node.js

import crypto from 'crypto';
import express from 'express';

const app = express();
const WEBHOOK_SECRET = process.env.OCTAGYM_WEBHOOK_SECRET;

app.use('/webhook', express.raw({ type: 'application/json' }));

app.post('/webhook', (req, res) => {
  const signature = req.headers['x-octagym-signature'];
  const timestamp = req.headers['x-octagym-timestamp'];
  const payload = req.body.toString();

  // Verificar timestamp (previne replay attacks — janela de 5 minutos)
  const now = Math.floor(Date.now() / 1000);
  if (Math.abs(now - parseInt(timestamp)) > 300) {
    return res.status(401).json({ error: 'Timestamp expirado' });
  }

  // Calcular assinatura esperada
  const signedPayload = `${timestamp}.${payload}`;
  const expectedSignature = crypto
    .createHmac('sha256', WEBHOOK_SECRET)
    .update(signedPayload)
    .digest('hex');

  // Comparação segura (previne timing attacks)
  if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expectedSignature))) {
    return res.status(401).json({ error: 'Assinatura inválida' });
  }

  // Processar evento
  const event = JSON.parse(payload);

  switch (event.type) {
    case 'member.created':
      // Enviar email de boas-vindas, notificar equipe, etc.
      break;
    case 'membership.cancelled':
      // Registrar motivo, disparar fluxo de retenção, etc.
      break;
    case 'checkin.created':
      // Atualizar contador de ocupação, registrar frequência, etc.
      break;
    case 'membership.past_due':
      // Enviar lembrete de pagamento, bloquear acesso, etc.
      break;
  }

  // Responda RAPIDAMENTE com 200 OK
  res.status(200).json({ received: true });
});

Verificação em Python

import hmac
import hashlib
import time
import os
from flask import Flask, request, jsonify

app = Flask(__name__)
WEBHOOK_SECRET = os.environ['OCTAGYM_WEBHOOK_SECRET']

@app.route('/webhook', methods=['POST'])
def webhook():
    signature = request.headers.get('X-OctaGym-Signature')
    timestamp = request.headers.get('X-OctaGym-Timestamp')
    payload = request.get_data(as_text=True)

    # Verificar timestamp (janela de 5 minutos)
    now = int(time.time())
    if abs(now - int(timestamp)) > 300:
        return jsonify({'error': 'Timestamp expirado'}), 401

    # Calcular assinatura esperada
    signed_payload = f"{timestamp}.{payload}"
    expected_signature = hmac.new(
        WEBHOOK_SECRET.encode(),
        signed_payload.encode(),
        hashlib.sha256
    ).hexdigest()

    # Comparação segura
    if not hmac.compare_digest(signature, expected_signature):
        return jsonify({'error': 'Assinatura inválida'}), 401

    event = request.json

    match event['type']:
        case 'member.created':
            # Enviar email de boas-vindas
            pass
        case 'membership.cancelled':
            # Fluxo de retenção
            pass
        case 'checkin.created':
            # Registrar frequência
            pass

    return jsonify({'received': True}), 200

Política de Retentativas

Se sua URL não responder com 2xx, tentaremos novamente com backoff exponencial:

TentativaIntervalo
1aImediato
2a1 minuto
3a5 minutos
4a30 minutos

Após 3 tentativas falhas consecutivas, o evento é marcado como falho. Após múltiplas falhas seguidas, o webhook pode ser desativado automaticamente. Você receberá um email de alerta.

Boas Práticas

  • Responda rapidamente — Retorne 200 OK em até 5 segundos. Não processe a lógica de negócio antes de responder.
  • Processe de forma assíncrona — Use filas de mensagens (Bull, Celery, SQS, etc.) para tarefas demoradas. Receba o webhook, enfileire e responda 200.
  • Implemente idempotência — O mesmo evento pode ser entregue mais de uma vez. Use o campo id do evento para evitar processamento duplicado.
  • Verifique a assinatura — Sempre valide a autenticidade com o X-OctaGym-Signature antes de processar qualquer evento.
  • Use HTTPS — Obrigatório para receber webhooks em produção.
  • Monitore falhas — Configure alertas para quando webhooks falharem repetidamente.

Suporte

On this page