# 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`). BTCPay’s 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: ```json { "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 |