From 52634f84bf06ffe26d8691a9f73621b278e6bb2e Mon Sep 17 00:00:00 2001 From: Alexander Schmidt Date: Fri, 6 Feb 2026 15:32:30 +0100 Subject: [PATCH] fix: webhook handles test events and missing metadata gracefully --- docs/pow-server/btcpay-webhook.php | 33 ++++++++++++++++--------- js/components/pages/page-my-listings.js | 6 +++++ js/services/directus.js | 1 - 3 files changed, 28 insertions(+), 12 deletions(-) diff --git a/docs/pow-server/btcpay-webhook.php b/docs/pow-server/btcpay-webhook.php index d1d1edf..f6a431a 100644 --- a/docs/pow-server/btcpay-webhook.php +++ b/docs/pow-server/btcpay-webhook.php @@ -8,8 +8,21 @@ if ($_SERVER['REQUEST_METHOD'] !== 'POST') { } $rawBody = file_get_contents('php://input'); + +if (!$rawBody) { + http_response_code(400); + echo json_encode(['error' => 'Empty body']); + exit; +} + $payload = json_decode($rawBody, true); +if ($payload === null) { + http_response_code(400); + echo json_encode(['error' => 'Invalid JSON', 'raw' => substr($rawBody, 0, 500)]); + exit; +} + // Verify HMAC signature if secret is configured if (BTCPAY_WEBHOOK_SECRET) { $sigHeader = $_SERVER['HTTP_BTCPAY_SIG'] ?? ''; @@ -25,16 +38,9 @@ if (BTCPAY_WEBHOOK_SECRET) { $type = $payload['type'] ?? null; $invoiceId = $payload['invoiceId'] ?? null; -if (!$type || !$invoiceId) { +if (!$type) { http_response_code(400); - echo json_encode([ - 'error' => 'Missing type or invoiceId', - 'received' => [ - 'type' => $type, - 'invoiceId' => $invoiceId, - 'keys' => array_keys($payload ?: []), - ], - ]); + echo json_encode(['error' => 'Missing type', 'keys' => array_keys($payload ?: [])]); exit; } @@ -44,6 +50,12 @@ if ($type !== 'InvoiceSettled' && $type !== 'InvoicePaymentSettled') { exit; } +// For settled events, invoiceId is required +if (!$invoiceId) { + echo json_encode(['ok' => true, 'action' => 'test_acknowledged', 'type' => $type]); + exit; +} + // Fetch invoice from BTCPay to get listing ID from metadata $btcpayUrl = BTCPAY_BASE_URL . '/api/v1/stores/' . BTCPAY_STORE_ID . '/invoices/' . urlencode($invoiceId); $btcpayContext = stream_context_create([ @@ -66,8 +78,7 @@ $invoice = json_decode($btcpayResponse, true); $listingId = $invoice['metadata']['listingId'] ?? null; if (!$listingId) { - http_response_code(400); - echo json_encode(['error' => 'No listingId in invoice metadata']); + echo json_encode(['ok' => true, 'action' => 'skipped', 'reason' => 'No listingId in invoice metadata']); exit; } diff --git a/js/components/pages/page-my-listings.js b/js/components/pages/page-my-listings.js index 6c3d98f..11d11b3 100644 --- a/js/components/pages/page-my-listings.js +++ b/js/components/pages/page-my-listings.js @@ -50,6 +50,12 @@ class PageMyListings extends HTMLElement { } const response = await directus.getListings({ + fields: [ + 'id', 'status', 'title', 'slug', 'price', 'currency', + 'condition', 'payment_status', 'date_created', 'user_created', + 'images.directus_files_id.id', + 'location.id', 'location.name' + ], filter: { user_created: { _eq: user.id } }, diff --git a/js/services/directus.js b/js/services/directus.js index e22af51..89b35e5 100644 --- a/js/services/directus.js +++ b/js/services/directus.js @@ -327,7 +327,6 @@ class DirectusService { 'price', 'currency', 'condition', - 'payment_status', 'date_created', 'user_created', 'images.directus_files_id.id',