btcpaymailer/WEBHOOK.md
Erling 203bdd3567 Add webhook evaluation logging with optional DEBUG mode
Log partial-payment decisions and email results to stdout for Portainer
logs; DEBUG enables full webhook payload tracing. Document BTCPay payload
and shutdown steps in WEBHOOK.md.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-08 12:05:38 +02:00

2.5 KiB
Raw Blame History

BTCPay webhook reference

Endpoint

POST https://mailer.nxtgroup.org/btcpay-webhook?token=YOUR_WEBHOOK_SECRET

Auth is the token query parameter (must match WEBHOOK_SECRET). BTCPays optional webhook signing secret is not used by this app.

Disable quickly

  1. BTCPay → Store → Settings → Webhooks → delete or disable the webhook.
  2. Portainer → Stacks → btcpaymailer → stop/remove the stack.

No emails are sent while the webhook is disabled or the stack is down.

Event subscribed

Only InvoiceReceivedPayment is processed. All other event types return 200 with "ignored" and are silent unless DEBUG=true.

Webhook body (BTCPay → mailer)

Typical payload:

{
  "deliveryId": "abc123",
  "webhookId": "wh_xyz",
  "originalDeliveryId": "abc123",
  "isRedelivery": false,
  "type": "InvoiceReceivedPayment",
  "timestamp": 1717843200,
  "storeId": "your-store-id",
  "invoiceId": "invoice-id-here"
}

Fields used by this app from the webhook:

Field Use
type Must be InvoiceReceivedPayment
storeId Fetch invoice from BTCPay API
invoiceId Fetch invoice from BTCPay API

The webhook does not include full payment amounts or buyer email. The app calls:

GET {BTCPAY_URL}/api/v1/stores/{storeId}/invoices/{invoiceId}

Invoice fields used (BTCPay API response)

Field Use
amount Invoice total
amountPaid Paid so far
currency e.g. USD, BTC
status Must be New for partial-payment email
metadata.buyerEmail Recipient (required to send)
metadata.orderId Shown in email subject/body

Send conditions (all must pass)

  1. type == InvoiceReceivedPayment
  2. BTCPay API returns invoice successfully
  3. status == "New"
  4. 0 < amountPaid < amount (partial payment, not zero or full)
  5. metadata.buyerEmail is set

Otherwise the handler returns 200 with "ignored" or 400 if buyer email is missing on a qualifying partial payment.

Logging

DEBUG What appears in container logs
false (default) Evaluation + send result for InvoiceReceivedPayment only
true Every webhook, full payload, each decision step

View logs in Portainer → Containers → btcpay-mailer → Logs.

Response codes

Code Meaning
401 Wrong or missing token
400 Partial payment but no buyerEmail
500 BTCPay API or Postmark failure
200 Ignored, or email sent successfully