Pular para o conteúdo

Webhooks

O FeitPay envia um POST HTTPS aos seus endpoints cadastrados sempre que acontece algo que você assinou. As entregas são assinadas, pelo menos uma vez (at-least-once) e repetidas com backoff — por isso o seu receptor precisa verificar, descartar duplicatas e responder rápido.

POST/v1/webhook-endpointslive · após ativação da conta
{
"url": "https://merchant.example/webhooks/feitpay",
"enabled_events": ["payment.confirmed", "payment.review_required", "payment.reorged", "payment.expired"],
"description": "Entrega de pedidos"
}

A resposta traz o secret de assinatura (whsec_…) uma única vez. Use ["*"] para receber todos os tipos de evento. Endpoints são por ambiente e podem ser limitados a uma loja. Eventos live só são entregues a endpoints cadastrados no modo live, então cadastre o seu quando a sua conta for ativada.

As URLs precisam ser HTTPS públicas. Elas são verificadas no cadastro e de novo no momento da entrega: o IP de destino é validado na conexão (faixas privadas, loopback, link-local e de metadados são recusadas), redirecionamentos não são seguidos e tamanhos e tempos são limitados. No desenvolvimento local, uma URL privada como http://localhost:4400 só funciona quando o operador da plataforma habilita uma flag explícita de desenvolvimento.

event_type Enviado quando
payment_intent.created Uma intenção é criada (API, painel, fatura ou link de pagamento)
invoice.awaiting_payment A intenção de uma fatura tem cotação travada e endereço
payment.detected Uma transferência foi vista, mas não é final
payment.confirming A transferência está em um bloco, acumulando confirmações
payment.confirmed O valor esperado é final — verifique data.fulfillable
payment.expired A cotação expirou sem pagamento
payment.review_required underpaid, overpaid, late_payment, manual_review ou pagamento extra após a confirmação
payment.reorged Um bloco com o pagamento foi substituído — pause a entrega
payment.resolved Uma resolução do lojista ou do operador foi registrada
payment.canceled Você cancelou a intenção
webhook.test Você clicou em Enviar evento de teste (ou chamou POST /v1/webhook-endpoints/{id}/test)
merchant.verification_updated O status da verificação da sua empresa mudou
payout.requested Um saque foi solicitado e o valor ficou retido do seu saldo em custódia
payout.approved Um segundo membro aprovou o saque; em seguida um operador do FeitPay o revisa
payout.rejected Um operador do FeitPay rejeitou o saque; o valor volta a ficar disponível
payout.canceled O saque foi cancelado antes do envio; o valor volta a ficar disponível
payout.sent A carteira quente da plataforma transmitiu o saque (data.tx_hash)
payout.completed O Bitcart informa que a transação do saque foi confirmada
payout.failed O saque não pôde ser enviado; o valor continua retido enquanto o FeitPay investiga, a menos que nada possa ter sido transmitido

Eventos de pagamento e de saque começam quando a sua conta é ativada para pagamentos live. O store_id dos eventos payout.* é null porque saldos e saques pertencem à organização inteira.

O corpo é o mesmo objeto retornado por GET /v1/events/{event_id}:

{
"event_id": "evt_01J…",
"event_type": "payment.confirmed",
"api_version": "2026-10-01",
"created_at": "2026-10-20T12:00:00Z",
"merchant_id": "org_…",
"store_id": "store_01J…",
"environment": "live",
"object": { "type": "payment_intent", "id": "pi_01J…" },
"data": {
"status": "confirmed",
"previous_status": "confirming",
"status_reason": "bitcart_complete",
"amount": "59.90",
"currency": "EUR",
"merchant_order_id": "order-123",
"fulfillable": true,
"quote": null,
"totals": null
}
}

data é propositalmente mínimo. Em pagamentos live, quote e totals são null (eles descrevem o processamento somente de observação); consulte o objeto processor da intenção com GET /v1/payment-intents/{id} para ver o ativo e o valor pagos. payment_intent.created traz status, amount, currency, merchant_order_id e checkout_url; webhook.test traz message e endpoint_id; merchant.verification_updated traz kyb_status e previous_kyb_status.

Cabeçalho Valor
FeitPay-Signature t=<unix>,v1=<hex> — vários v1 durante a rotação do segredo
FeitPay-Event-Id Igual a event_id
FeitPay-Event-Type Igual a event_type
FeitPay-Delivery-Id A entrega (whd_…) — uma por evento e endpoint
FeitPay-Delivery-Attempt 1 na primeira tentativa, depois 2, 3, …
Content-Type application/json
  1. Verifique a assinatura sobre o corpo bruto antes de interpretá-lo (como). Responda 400 em caso de falha.
  2. Descarte duplicatas pelo event_id. As entregas são at-least-once; o mesmo evento pode chegar mais de uma vez, inclusive após uma nova tentativa manual.
  3. Confirme rápido com qualquer 2xx (em poucos segundos). Faça o trabalho lento depois.
  4. Não dependa da ordem. Use data.status e, quando importar, releia a intenção.
  5. Consulte antes de ações irreversíveis. Antes de enviar mercadorias ou conceder valor, chame GET /v1/payment-intents/{id} e confira fulfillable. O webhook é um sinal; a API é a fonte da verdade.
  • Uma entrega tem sucesso com qualquer 2xx. Qualquer outra coisa — não 2xx, timeout, erro de conexão — é repetida com backoff exponencial e jitter.
  • Após o número máximo de tentativas, a entrega é marcada como dead e listada como dead letter para os operadores; ela nunca é descartada em silêncio.
  • Cada tentativa fica registrada: horário, duração, status da resposta e um trecho curto e sanitizado da resposta. Consulte no painel ou com GET /v1/webhook-deliveries/{id}.
  • Tentar agora: POST /v1/webhook-deliveries/{id}/retry recoloca a entrega na fila imediatamente. O mesmo event_id é entregue de novo, e a ação vai para o log de auditoria.
POST/v1/webhook-deliveries/{webhook_delivery_id}/retrylive · após ativação da conta

POST /v1/webhook-endpoints/{id}/rotate-secret retorna um novo segredo (exibido uma vez). O segredo anterior continua assinando em paralelo por previous_secret_ttl_hours (padrão 24, até 168, ou 0 para expirá-lo na hora); durante essa janela, cada entrega traz duas assinaturas v1. Publique o novo segredo — ou configure os dois — e deixe o antigo expirar.

Webhooks nunca contêm chaves de API, segredos de assinatura, dados pessoais completos de clientes ou chaves públicas estendidas de carteiras. Os logs, dos dois lados, nunca devem registrar o valor de FeitPay-Signature junto com o seu segredo.