Vue Storefront 2 Checkout Webhooks: Diagnosing Missing Order Status Updates
When Vue Storefront 2 checkout orders stay pending after payment, the cause is often a misconfigured middleware webhook or missing idempotency handling. Inspect, validate, and fix webhook delivery and order-state updates.
24 Feb 2026, 07:24 UTC

The Problem: Orders Stay Pending After Payment
A customer completes payment, returns to your Vue Storefront 2 storefront, and the order remains in pending or never reaches complete. The useful takeaway is that this is usually a middleware webhook delivery or order-state mapping problem, not a frontend rendering issue. Vue Storefront 2 uses a composable architecture: the Nuxt 3 frontend calls GraphQL APIs, while payment provider events arrive as HTTP webhooks handled by server-side middleware extensions. If the webhook never reaches the middleware, or the middleware cannot map the event to an order, the status never updates.
Diagnostic Table: Checkout Webhook Failures
| Symptom | Likely cause | Diagnostic check |
|---|---|---|
| Order stays pending after successful payment | Webhook URL not registered or unreachable | Send a test POST to the configured endpoint from the middleware host |
| Webhook received but order status unchanged | Signature verification rejecting the payload | Compare configured webhook secret with provider dashboard; inspect middleware logs for signature errors |
| Duplicate orders or status changes | Missing idempotency handling for repeated webhook deliveries | Check whether the same payment event ID appears multiple times in logs |
| Status updates arrive minutes late | Middleware queue backlog or eventual consistency between services | Compare webhook receipt timestamp with order update timestamp in logs |
Step-by-Step Diagnostic Process
- Confirm the webhook endpoint is reachable Run from the middleware server or container, not your laptop, because network rules may differ:
- Verify webhook signature verification Payment providers sign webhook requests so the middleware can confirm authenticity. In your middleware configuration, locate the secret used to validate incoming requests. It often looks like:
- Trace the order ID through middleware logs Find the log file or log stream for the middleware extension handling checkout events. Required permissions: read access to application logs. Search for the order ID from the storefront. Expected check: the log should show the webhook event, the matched order ID, and the status transition. If the order ID is missing, the payment provider may be sending a different identifier than your storefront expects.
- Check idempotency for repeated deliveries Payment providers may deliver the same webhook more than once. Search logs for the same event ID arriving multiple times. If the middleware updates the order each time without checking whether it was already processed, you can see duplicate status transitions or, in worse cases, duplicate fulfillment triggers. Expected check: the second delivery should be acknowledged but not change order state again.
curl -v -X POST https://your-storefront.example.com/api/payment/webhook \
-H "Content-Type: application/json" \
-d '{"event":"payment.completed","orderId":"ORDER-123"}'
Required permissions: shell access to the middleware host and permission to make outbound HTTP calls. Expected check: HTTP 200 or 204 from the middleware. Risk: do not include real webhook secrets or customer data in the test payload; a failed connection could mean firewall rules, a wrong route, or the middleware process not running.
WEBHOOK_SECRET=your_provider_signing_secret
Place this in the middleware environment, not in the Nuxt frontend bundle. Check middleware logs for messages such as invalid signature around the time of a failed payment. Risk: if the secret does not match the provider dashboard exactly, every valid webhook is rejected. Clock skew between servers can also invalidate timestamp-based signatures.
Common Fixes Based on Findings
Fix 1: Register the Correct Webhook URL
If the endpoint is unreachable, register the public middleware URL in the payment provider dashboard. Example configuration concept; exact keys vary by provider:
paymentProvider:
webhook:
url: "https://your-storefront.example.com/api/payment/webhook"
secret: "${WEBHOOK_SECRET}"
Apply the change in the middleware extension configuration, redeploy the middleware, then repeat the curl check from step 1. Rollback: revert the URL to the previous value and redeploy, or delete the webhook from the provider dashboard if the new endpoint causes failures.
Fix 2: Align the Webhook Secret and Signature Header
If logs show signature failures, copy the signing secret from the provider dashboard into the middleware environment variable. Do not hard-code it in the frontend. Restart the middleware process after changing the variable. Verify by triggering a test payment in the provider sandbox and confirming the middleware logs show a successful signature check.
Fix 3: Map the Payment Event to the Correct Order Status
If the webhook arrives but the order does not move, the middleware may not translate the provider's event into a Vue Storefront order status. Add or correct a mapping in the webhook handler:
const statusMap = {
'payment.completed': 'complete',
'payment.failed': 'cancelled',
'payment.pending': 'pending'
};
Ensure the handler looks up the order by the identifier the provider sends, then calls the appropriate commerce API or repository method to update the order. Test with a sandbox payment and confirm the storefront order page reflects the new status.
Fix 4: Add an Idempotency Guard
If the same event ID appears multiple times, guard the handler so it processes each event once:
const processed = new Set();
async function handleWebhook(event) {
if (processed.has(event.id)) {
return { status: 'already processed' };
}
processed.add(event.id);
// update order state here
}
Note: an in-memory set resets on restart. For production, use a persistent store such as a database table or Redis key keyed by event ID. Verify by sending the same test webhook twice and confirming the order status changes only once.
Escalation Criteria: When to Involve the Payment or Platform Team
- Signature failures persist after confirming the secret and server clocks. The provider may have rotated the signing key or changed the header format.
- Webhooks reach the middleware but orders never update across multiple providers. This suggests a commerce API or order repository problem rather than a webhook configuration issue.
- Updates are consistently delayed by minutes or more under normal load. This may indicate a middleware queue backlog or eventual consistency lag between the order service and the storefront cache.
- You suspect PCI scope issues. Do not store raw card data in middleware logs; involve the security team before changing payment handling code.
Verification Steps
- Place a test order through the provider sandbox.
- Confirm the middleware receives the webhook and returns HTTP 200 or 204.
- Confirm the order status in the storefront moves from
pendingto the expected terminal status. - Send the same webhook payload a second time and confirm no duplicate status change occurs.
- Check that no card numbers or authentication tokens appear in middleware logs.
Limitations and Version Assumptions
- This guide assumes Vue Storefront 2.x with a Nuxt 3 frontend and server-side middleware extensions. Custom project structures may use different file paths or handler names.
- Webhook behavior and signature headers vary by payment provider; consult the provider's documentation for exact values.
- Eventual consistency means order status may not be instant across all services, even when the webhook is handled correctly.
- Practical check: after a fix, compare the webhook receipt timestamp in middleware logs with the order update timestamp in the commerce API response. A large gap points to downstream processing delay, not webhook delivery.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.