btcpaymailer/WEBHOOK.md
Erling 6edd208245 Handle BTCPay __test__ webhooks with Postmark test email
Send a bannered test transactional email when BTCPay UI test events
arrive instead of failing on a missing invoice API lookup.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-08 13:18:21 +02:00

78 lines
2.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# BTCPay webhook reference
## Endpoint
```
POST https://mailer.nxtgroup.org/btcpay-webhook
```
No query-string token. BTCPay signs each request with the **webhook secret** from the store webhook settings.
## Authentication
BTCPay sends header `BTCPAY-SIG`:
```
sha256=<hmac-sha256-hex>
```
The HMAC is computed over the **raw request body bytes** using the webhook **Secret** shown in BTCPay (same value as `BTCPAY_WEBHOOK_SECRET` in Portainer).
## Disable quickly
1. **BTCPay** → Store → **Webhooks** → delete or disable the webhook.
2. **Portainer** → Stacks → `btcpaymailer` → stop/remove the stack.
## Event subscribed
Only **`InvoiceReceivedPayment`** is processed. Other events return `200` with `"ignored"` (silent unless `DEBUG=true`).
## Webhook body (BTCPay → mailer)
```json
{
"deliveryId": "abc123",
"webhookId": "wh_xyz",
"isRedelivery": false,
"type": "InvoiceReceivedPayment",
"timestamp": 1717843200,
"storeId": "your-store-id",
"invoiceId": "invoice-id-here"
}
```
The app then fetches the full invoice:
```
GET {BTCPAY_URL}/api/v1/stores/{storeId}/invoices/{invoiceId}
```
## Send conditions
1. Valid `BTCPAY-SIG` signature
2. `type == InvoiceReceivedPayment`
3. BTCPay API returns invoice
4. `status == "New"`
5. `0 < amountPaid < amount`
6. `metadata.buyerEmail` is set
## BTCPay UI test events
Invoice IDs containing `__test__` (BTCPays “Send test” button) skip the API fetch and trigger a Postmark test email to `WEBHOOK_TEST_EMAIL`, or the first `BCC_EMAIL` address if unset. The email includes a red **THIS IS A TEST TRANSACTIONAL EMAIL, PLEASE IGNORE.** banner.
## Response codes
| Code | Meaning |
|------|---------|
| `401` | Missing or invalid `BTCPAY-SIG` |
| `400` | Partial payment but no `buyerEmail` |
| `500` | BTCPay API or Postmark failure |
| `200` | Ignored, or email sent |
## Logging
| `DEBUG` | Container logs |
|---------|----------------|
| `false` | Evaluation + send result for payment events only |
| `true` | Full payload and every decision step |