Skip to content

Cadastrar Webhook

Endpoints para criar, listar e remover webhooks de notificação.


Criar Webhook

POST /api/external/webhooks

Headers

HeaderTipoObrigatórioDescrição
AuthorizationStringSimApiKey {client_id}:{client_secret}
Content-TypeStringSimapplication/json
hmacStringSimAssinatura HMAC-SHA512 do body (saiba mais)

Request Body

CampoTipoObrigatórioPadrãoDescrição
urlStringSim--URL para receber notificações (HTTPS por padrão)
eventsArraySim--Lista de eventos para assinar. Deve ser um array não-vazio com pelo menos um evento válido da tabela abaixo. Omitir o campo retorna 400 {"errors": {"events": ["can't be blank"]}}.
secretStringNãoauto-geradoChave para assinatura HMAC-SHA256 das entregas. Se omitido, um valor aleatório é gerado automaticamente.
descriptionStringNãonullDescrição livre do webhook para identificação interna
allow_insecureBooleanNãofalsePermite URLs HTTP (não-HTTPS). A segurança dos dados é responsabilidade do cliente.

Eventos disponíveis (apenas PIX — outros produtos não estão em escopo na Owem hoje):

EventoStatus bodyDescriçãoDisparo
pix.charge.createdcreatedQR code gerado ou cash-in iniciadoAtivo
pix.charge.paidpaidPIX recebido e liquidadoAtivo
pix.charge.expiredexpiredQR code expirou sem pagamento (worker a cada 5 min)Ativo
pix.charge.cancelledcancelledQR code cancelado antes de pagamentoRegistrado, ainda não disparado
pix.payout.queuedqueuedPIX enviado enfileirado por rate limit (ClientLimiter por merchant OU bucket DICT BACEN)Ativo
pix.payout.processingprocessingPIX enviado, aguardando confirmaçãoAtivo
pix.payout.confirmedsettledPIX enviado e confirmado (terminal)Ativo
pix.payout.failedrejectedPIX enviado rejeitado (terminal)Ativo
pix.payout.returnedreturnedPIX enviado devolvidoAtivo
pix.refund.requestedrequestedPedido de devolução recebido (infração BACEN); bloqueio cautelar criado no saldo do clienteAtivo
pix.refund.completedsettled / completedAnálise da defesa finalizada e devolução executada (ou liberada)Ativo
pix.return.receivedsettledDevolução PIX recebida (crédito)Ativo
pix.infraction.createdACKNOWLEDGEDInfração PIX reportada pela contraparte via BACEN DICTAtivo
pix.infraction.resolvedCLOSED / CANCELLEDInfração resolvida (admin close, auto-deny ou contraparte cancelou)Ativo
pix.infraction.defense_submitteddefense_submittedDefesa submetida pelo merchantAtivo
webhook.testtestTeste manual. Disponível apenas via portal Admin/Merchant — não há endpoint External API para dispararDisparo manual

pix.charge.cancelled ainda não é disparado

O evento está no enum de assinaturas válidas, mas nenhum código em produção dispara notificações desse tipo hoje (fluxo de cancelamento de QR code não implementado). Você pode incluí-lo no array events — a API aceita — porém nenhuma notificação chegará ao seu endpoint até que o fluxo seja implementado.

Qualquer evento fora dessa tabela é rejeitado

Ao criar um webhook, validate_events no backend verifica cada item contra o enum @valid_events (schema Fluxiq.Schemas.Webhooks.Webhook). Eventos desconhecidos (boleto.paid, account.created, sta.file.*, etc.) retornam 400 com erro events: contains invalid events: .... Antes da sessão 163 esses nomes estavam no enum como aspiracional — foram removidos porque não havia dispatchers em código.

Payloads de cada evento

Exemplos de payload completos para cada evento estão em Payloads dos Webhooks.

Exemplo

bash
BODY='{"url":"https://seusite.com.br/webhook","events":["pix.charge.paid","pix.payout.confirmed"]}'
HMAC=$(echo -n "$BODY" | openssl dgst -sha512 -hmac "$CLIENT_SECRET" | awk '{print $2}')

curl -X POST https://api.owem.com.br/api/external/webhooks \
  -H "Authorization: ApiKey $CLIENT_ID:$CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -H "hmac: $HMAC" \
  -d "$BODY"

Resposta de Sucesso (201)

json
{
  "worked": true,
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "url": "https://seusite.com.br/webhook",
  "events": ["pix.charge.paid", "pix.payout.confirmed"],
  "secret": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4",
  "description": null,
  "is_active": true,
  "created_at": "2026-03-07T15:30:00Z"
}

Formato do id

O id do webhook é um UUID v4 canônico (36 caracteres com hífens). Use esse valor direto em DELETE /api/external/webhooks/:id.

Resposta de Erro (422)

json
{
  "worked": false,
  "detail": "URL deve utilizar HTTPS"
}

Apenas HTTPS por Padrão

A URL do webhook deve utilizar HTTPS. URLs com HTTP serão rejeitadas, a menos que allow_insecure: true seja enviado no cadastro.

Importante — Secret do Webhook

O campo secret retornado na resposta de cadastro é a chave usada para assinar as entregas do webhook (HMAC-SHA256). Armazene esse valor com segurança assim que receber — é ele quem valida que uma notificação veio realmente da Owem Pay.

NÃO confunda com client_secret:

  • client_secret = autenticação das suas requisições à API (header Authorization)
  • secret do webhook = verificação da assinatura das entregas recebidas (header X-Owem-Signature)

Se você não enviar o campo secret no cadastro, um valor aleatório será gerado automaticamente e retornado na resposta.

Veja Validação de Webhooks para exemplos de como verificar a assinatura.

Recuperando o secret depois

O secret é retornado tanto em POST /api/external/webhooks (criação) quanto em GET /api/external/webhooks e GET /api/external/webhooks/:id (consulta). Se você perdeu o valor, basta consultar o webhook novamente via GET.

Em uma futura versão este comportamento pode ser restringido (exibir apenas na criação); recomendamos armazenar o secret em um segredo gerenciado (vault, SSM, etc.) no momento do cadastro.

URLs HTTP

Por padrão, webhooks exigem HTTPS para garantir a segurança dos dados em trânsito. Para utilizar HTTP, envie allow_insecure: true no cadastro do webhook.

Atenção

URLs HTTP transmitem dados sem criptografia. A segurança e o sigilo das informações trafegadas ficam sob inteira responsabilidade do cliente. A Owem Pay realiza a entrega do webhook normalmente, porém não se responsabiliza por interceptação ou vazamento de dados em conexões não criptografadas.

URLs privadas são sempre bloqueadas

Mesmo com allow_insecure: true, URLs apontando para endereços privados/internos são rejeitadas:

  • localhost / 127.x.x.x
  • RFC1918: 10.x.x.x, 192.168.x.x, 172.16-31.x.x
  • TLDs internos: .local, .internal

Webhooks devem apontar para URLs públicas acessíveis pela internet.


Listar Webhooks

GET /api/external/webhooks

Headers

HeaderTipoObrigatórioDescrição
AuthorizationStringSimApiKey {client_id}:{client_secret}

Exemplo

bash
curl -X GET https://api.owem.com.br/api/external/webhooks \
  -H "Authorization: ApiKey $CLIENT_ID:$CLIENT_SECRET"

Resposta de Sucesso (200)

Retorna um array de objetos (não envelopado em {"worked": true}). Cada item contém os mesmos campos do cadastro, incluindo secret.

json
[
  {
    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "url": "https://seusite.com.br/webhook",
    "events": ["pix.charge.paid", "pix.payout.confirmed"],
    "description": null,
    "account_id": 10014,
    "is_active": true,
    "allow_insecure": false,
    "status": "active",
    "secret": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4",
    "created_at": "2026-03-07T15:30:00",
    "updated_at": "2026-03-07T15:30:00"
  }
]
CampoTipoDescrição
idstring (UUID)Identificador do webhook
urlstringURL de destino
eventsarrayEventos assinados
descriptionstring ou nullDescrição opcional
account_idinteger ou nullConta associada. null = webhook global para a API key (se suportado)
is_activebooleanfalse = webhook pausado, nenhuma delivery é disparada
allow_insecurebooleantrue = URLs HTTP aceitas
statusstringDerivado de is_active"active" ou "inactive"
secretstringChave HMAC-SHA256 usada para assinar entregas. Retornada no LIST para permitir recuperação caso o cliente tenha perdido o valor original
created_at / updated_atstring ISO 8601Timestamps em UTC, formato NaiveDateTime (sem sufixo Z, ex: "2026-03-07T15:30:00"). Diferente de outros campos de data em payloads de webhook (paid_at, returned_at, expired_at) que usam DateTime ISO 8601 com Z final. Sempre assuma UTC para os campos do webhook object

Remover Webhook

DELETE /api/external/webhooks/:id

Headers

HeaderTipoObrigatórioDescrição
AuthorizationStringSimApiKey {client_id}:{client_secret}

Path Parameters

ParâmetroTipoObrigatórioDescrição
idString (UUID)SimID do webhook (UUID v4 retornado pelo endpoint de criação)

Exemplo

bash
curl -X DELETE https://api.owem.com.br/api/external/webhooks/a1b2c3d4-e5f6-7890-abcd-ef1234567890 \
  -H "Authorization: ApiKey $CLIENT_ID:$CLIENT_SECRET"

Resposta de Sucesso (204)

HTTP 204 No Content — body vazio. O webhook foi removido com sucesso; nenhuma delivery pendente será disparada.

Primeira chamada: 204. Subsequentes: 404

A primeira chamada bem-sucedida retorna 204 No Content. Chamadas subsequentes com o mesmo id retornam 404 { "errors": { "not_found": "webhook not found" } } — o webhook já foi removido. Isso não é idempotência estrita HTTP (em que toda chamada retornaria 204) — é o comportamento padrão de DELETE quando o recurso deixa de existir. Escreva sua integração para aceitar tanto 204 quanto 404 como "o webhook não está mais ativo".

Resposta de Erro (400)

Formato de id inválido (não é UUID):

json
{
  "errors": {
    "bad_request": "id must be a valid UUID"
  }
}

Resposta de Erro (404)

Webhook não existe ou não pertence à sua conta:

json
{
  "errors": {
    "not_found": "webhook not found"
  }
}

Owem Pay Instituição de Pagamento — ISPB 37839059