A Malga utiliza o serviço de webhooks para notificar o seu sistema sobre os eventos ocorridos no motor de recorrência. Através de webhooks, você consegue atualizar seu sistema sempre que um evento importante acontece, como a criação de uma assinatura, mudança de status ou criação de cobranças automáticas.

Fluxo básico para receber notificações via webhooks:

  • Crie um serviço com um endpoint acessível dentro do seu sistema para receber as requisições de notificação dos eventos de recorrência.
  • Registre seu endpoint na Malga criando um webhook para receber notificações dos eventos desejados.
  • A Malga enviará uma requisição HTTP para seu endpoint com os dados do objeto alterado sempre que o determinado evento registrado no seu webhook acontecer.

Criação de um webhook

Realize a criação e gestão de webhooks usando o Serviço de Webhooks.
curl --location --request POST 'https://api.malga.io/v1/webhooks' \
    --header 'X-Client-Id: <YOUR_CLIENT_ID>' \
    --header 'X-Api-Key: <YOUR_SECRET_KEY>' \
    --header 'Content-Type: application/json' \
    --data-raw '{
        "event": "subscription.created",
        "endpoint": "https://seu-dominio.com/webhooks/recurrence",
        "version": 1.1,
        "status": true
    }'

Evento de notificação enviado

Quando um determinado evento ocorre no motor de recorrência, a Malga cria um objeto do tipo event que é enviado através de uma requisição HTTP para o seu endpoint cadastrado. O evento é imutável dentro da estrutura de notificações da Malga, isso significa que os dados do objeto que sofreu alteração são gravados junto com o evento, representando o estado do objeto imediatamente após o evento que o alterou. Exemplo de requisição de notificação de evento de uma assinatura enviada pela Malga para seu endpoint:
> POST <ENDPOINT_URL> HTTP/2
> Host: <ENDPOINT_HOST>
> User-Agent: axios/0.21.1
> Accept: application/json, text/plain, */*
> Content-Type: application/json
> X-Idempotency-Key: 5616b19e-4d99-4bd3-b415-4990e5cab4f4
> X-Plug-Date: 1660053072711
> X-Plug-Signature: 1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75
> HTTP/2

{
  "id": "5616b19e-4d99-4bd3-b415-4990e5cab4f4",
  "apiVersion": "1.1",
  "object": "subscription",
  "event": "created",
  "createdAt": "2021-07-05T18:56:08.672Z",
  "data": {
    "id": "01985cf8-96df-7d37-b17c-a9985a1e78bb",
    "name": "Assinatura Premium com Eventos",
    "clientId": "e234eeb3-483d-4df2-87eb-1e2be5cdaccd",
    "merchantId": "225d39bc-1fbb-480a-90bd-f0caad05d2d0",
    "customerId": "2a8b64ce-904c-4256-b79a-49525808609c",
    "referenceKey": "SUB-PREMIUM-001",
    "currency": "BRL",
    "items": [
      {
        "name": "Ingresso VIP Mensal",
        "description": "Acesso VIP premium a eventos mensais",
        "amount": 29900,
        "quantity": 1,
        "sku": "VIP-EVENT-001",
        "risk": "Low",
        "categoryId": "entertainment",
        "locality": "São Paulo",
        "date": "2025-12-01",
        "type": 1,
        "genre": "Shows e Eventos",
        "tickets": {
          "quantityTicketSale": 1,
          "convenienceFeeValue": 15.5,
          "quantityFull": 1,
          "batch": 1
        },
        "location": {
          "street": "Av. Paulista",
          "number": "1000",
          "complement": "Centro de Convenções",
          "zipCode": "01310-100",
          "city": "São Paulo",
          "state": "SP",
          "country": "Brasil",
          "district": "Bela Vista",
          "reference": "Próximo ao MASP"
        }
      }
    ],
    "recurrence": {
      "interval": "monthly",
      "startAt": "2025-07-30",
      "nextDueDate": "2025-07-30"
    },
    "paymentMethod": {
      "type": "credit",
      "card": {
        "cardId": "ebef4e7e-b5d3-49d8-ac8f-b973faaa3ac5"
      },
      "installments": 1
    },
    "status": "created",
    "amount": 29900,
    "liveMode": true,
    "createdAt": "2025-07-30T20:14:12.191866Z",
    "updatedAt": "2025-07-30T20:14:12.191866Z"
  }
}

Eventos suportados para notificação via webhooks

EventoDescrição
subscription.createdEvento enviado quando uma nova assinatura é criada
subscription.activatedEvento enviado quando uma assinatura tem seu primeiro pagamento aprovado
subscription.updatedEvento enviado quando uma assinatura é atualizada (mudança de valor, produtos, etc.)
subscription.pausedEvento enviado quando uma assinatura é pausada
subscription.resumedEvento enviado quando uma assinatura pausada é retomada
subscription.unpaidEvento enviado quando uma assinatura fica em situação de não paga
subscription.expiredEvento enviado quando uma assinatura expira
subscription.cycle_failedEvento enviado quando um ciclo de pagamento falhar devido a inconsistencia de dados

Exemplos de payloads

Estrutura padrão do payload

Todos os eventos de assinatura seguem a mesma estrutura base. A diferença está no campo event e nos dados específicos dentro de data.
{
  "id": "5616b19e-4d99-4bd3-b415-4990e5cab4f4",
  "apiVersion": "1.1",
  "object": "subscription",
  "event": "created",
  "createdAt": "2021-07-05T18:56:08.672Z",
  "data": {
    "id": "01985cf8-96df-7d37-b17c-a9985a1e78bb",
    "name": "Assinatura Premium com Eventos",
    "status": "created",
    "amount": 29900,
    "currency": "BRL",
    "createdAt": "2025-07-30T20:14:12.191866Z",
    "updatedAt": "2025-07-30T20:14:12.191866Z"
  }
}

Evento subscription.activated

O evento subscription.activated inclui informações adicionais sobre o cycle que foi processado com sucesso:
{
  "id": "webhook_event_id_example",
  "apiVersion": "1.1",
  "object": "subscription",
  "event": "activated",
  "createdAt": "2021-07-05T18:56:08.672Z",
  "data": {
    "id": "subscription_id_example",
    "name": "Assinatura Premium com Eventos",
    "status": "active",
    "amount": 29900,
    "currency": "BRL",
    "createdAt": "2025-07-30T20:14:12.191866Z",
    "updatedAt": "2025-07-30T20:14:15.239441719Z",
    "cycle": {
      "id": "cycle_id_example",
      "customerId": "YOUR_CUSTOMER_ID",
      "merchantId": "YOUR_MERCHANT_ID",
      "cycle": 1,
      "status": "authorized",
      "createdAt": "2025-07-30T20:14:12.599715Z"
    }
  }
}

Evento subscription.cycle_failed

Este evento é enviado quando o processamento de um novo ciclo de cobrança falha devido a alguma inconsistência nos dados da assinatura. Um exemplo comum é quando o merchant vinculado à assinatura foi desativado.
Nesses casos,nenhuma transação é criada.
{
  "id": "webhook_event_id_example",
  "apiVersion": "1.1",
  "object": "subscription",
  "event": "cycle_failed",
  "createdAt": "2025-08-06T13:57:36.672Z",
  "data": {
    "subscription": {
      "id": "subscription_id_example",
      "name": "Assinatura Premium com Eventos",
      "clientId": "YOUR_CLIENT_ID",
      "merchantId": "YOUR_MERCHANT_ID",
      "customerId": "YOUR_CUSTOMER_ID",
      "referenceKey": "SUB-PREMIUM-001",
      "currency": "BRL",
      "items": [
        {
          "name": "Ingresso VIP Mensal",
          "description": "Acesso VIP premium a eventos mensais",
          "amount": 29900,
          "quantity": 1,
          "sku": "VIP-EVENT-001",
          "risk": "Low",
          "categoryId": "entertainment",
          "locality": "São Paulo",
          "date": "2025-12-01",
          "type": 1,
          "genre": "Shows e Eventos",
          "tickets": {
            "quantityTicketSale": 1,
            "convenienceFeeValue": 15.5,
            "quantityFull": 1,
            "batch": 1
          },
          "location": {
            "street": "Av. Paulista",
            "number": "1000",
            "complement": "Centro de Convenções",
            "zipCode": "01310-100",
            "city": "São Paulo",
            "state": "SP",
            "country": "Brasil",
            "district": "Bela Vista",
            "reference": "Próximo ao MASP"
          }
        }
      ],
      "recurrence": {
        "interval": "monthly",
        "startAt": "2025-08-06",
        "nextDueDate": "2025-09-06"
      },
      "paymentMethod": {
        "type": "credit",
        "card": {
          "cardId": "YOUR_CARD_ID"
        },
        "installments": 1
      },
      "status": "created",
      "amount": 29900,
      "liveMode": true,
      "createdAt": "2025-08-06T13:57:36.295605Z",
      "updatedAt": "2025-08-06T13:57:36.393955Z",
      "lastCycle": {
        "id": "cycle_id_example",
        "customerId": "YOUR_CUSTOMER_ID",
        "merchantId": "YOUR_MERCHANT_ID",
        "cycle": 1,
        "attempts": 1,
        "status": "pending",
        "isEmulated": false,
        "createdAt": "2025-08-06T13:57:36.3877Z",
        "scheduledAt": "2025-08-06",
        "paymentHistory": [
          {
            "id": "payment_history_id_example",
            "createdAt": "2025-08-06T13:57:36.396306294Z",
            "chargeId": null,
            "attemptNumber": 1,
            "error": null
          }
        ]
      }
    },
    "errorCode": 404
  }
}

Comportamento especial para startAt sendo hoje

Quando uma assinatura é criada com startAt definido como a data atual, o motor de recorrência processa o primeiro pagamento imediatamente.
Nesse caso, voce deve receber webhooks na ordem abaixo:
Ordem de eventos quando startAt é hoje:
  1. subscription.created - Assinatura criada
  2. subscription.activated (se sucesso) ou subscription.cycle_failed (caso haja alguma inconsistencia de dados na assinatura)
  3. subscription.unpaid (se todas as tentativas de pagamento do ciclo falharem)

Webhooks de Cobrança

Quando o motor de recorrência cria cobranças automaticamente, você também receberá os webhooks de cobrança padrão da Malga. Nestes casos, o subscriptionId estará presente no payload da cobrança para identificar a qual assinatura a cobrança pertence.

Exemplo de webhook de cobrança com subscriptionId

{
  "id": "5616b19e-4d99-4bd3-b415-4990e5cab4f4",
  "apiVersion": "1.1",
  "object": "transaction",
  "event": "pending",
  "createdAt": "2021-07-05T18:56:08.672Z",
  "data": {
    "id": "chr_123456789",
    "amount": 29900,
    "currency": "BRL",
    "status": "pending",
    "customerId": "cus_123456789",
    "subscriptionId": "sub_123456789",
    "createdAt": "2024-01-01T00:00:00Z",
    "updatedAt": "2024-01-01T00:00:00Z"
  }
}
Esta documentação fornece uma base sólida para implementar webhooks de recorrência seguindo os padrões da Malga. Lembre-se de adaptar os exemplos para sua stack tecnológica específica e sempre testar em ambiente de desenvolvimento antes de ir para produção.