How Adyen Webhooks Handle AUTHORISATION, CAPTURE, and REFUND Events in Salesforce Commerce Cloud

Adyen webhooks process AUTHORISATION, CAPTURE, and REFUND events through dedicated handler modules in the int_adyen_webhooks cartridge, validating success flags before updating Salesforce Commerce Cloud order statuses according to specific business rules.

The adyen/adyen-salesforce-commerce-cloud repository implements a robust webhook integration that synchronizes payment states between Adyen and Salesforce Commerce Cloud (SFCC). When Adyen sends asynchronous notifications for payment events, the int_adyen_webhooks cartridge parses these payloads and executes specific handlers to maintain order consistency. This article examines the source code implementation for the three primary event types: AUTHORISATION, CAPTURE, and REFUND.

Webhook Architecture and Success Validation

All webhook events enter the system through the /cartridge/notify controller, which creates a custom object containing the raw payload (custom.Adyen_log) and convenience fields like custom.value and custom.success. Before any handler executes, the system validates the webhook status via isWebhookSuccessful() in src/cartridges/int_adyen_webhooks/cartridge/utils/webhookUtils.js. This utility strictly returns true only when customObj.custom.success === 'true', ensuring failed webhooks do not trigger state changes.

Handling AUTHORISATION Events

The src/cartridges/int_adyen_webhooks/cartridge/eventHandlers/AUTHORISATION.js module processes authorization confirmations through a multi-stage decision tree.

Parsing Payment Amount and Fraud Status

The handler extracts the paid amount using parseFloat(customObj.custom.value) and retrieves fraud indicators from additionalData.fraudResultType within the parsed JSON log. These values determine the subsequent order processing path.

Order State Decision Logic

The implementation handles four distinct scenarios (see lines 31‑44 of AUTHORISATION.js):

  • Duplicate callbacks: When order.paymentStatus already equals PAID, the handler logs the duplicate and exits without modification.
  • Partial payments: If amountPaid < totalAmount, the handler sets order.setPaymentStatus(Order.PAYMENT_STATUS_PARTPAID).
  • Manual review: For amber fraud status (referenced via constants.FRAUD_STATUS_AMBER), the handler flags the order using order.trackOrderChange('Order sent for manual review in Adyen Customer Area').
  • Failed order recovery: When an order has status FAILED and receives full payment, OrderMgr.undoFailOrder(order) reopens the order before standard processing continues.

Successful Authorisation Flow

For standard successful authorizations, the handler invokes placeOrder(order) from src/cartridges/int_adyen_webhooks/cartridge/utils/paymentUtils.js. Upon successful placement, the handler sets:

order.setPaymentStatus(Order.PAYMENT_STATUS_PAID);
order.setExportStatus(Order.EXPORT_STATUS_READY);
order.setConfirmationStatus(Order.CONFIRMATION_STATUS_CONFIRMED);
result.SubmitOrder = true;

For Customer Service Center (CSC) orders, the handler additionally copies the PSP reference and payment method onto the order and its payment instruments. Finally, it persists webhook metadata to order.custom.Adyen_eventCode and order.custom.Adyen_value (lines 90‑92), then returns { success: true, isAdyenPayment: true } to the controller.

Handling CAPTURE Events

Located in src/cartridges/int_adyen_webhooks/cartridge/eventHandlers/CAPTURE.js, this handler addresses a specific edge case: capturing payments for previously cancelled orders (lines 6‑18). When isWebhookSuccessful() returns true and the order status equals ORDER_STATUS_CANCELLED, the handler executes:

order.setPaymentStatus(Order.PAYMENT_STATUS_PAID);
order.setExportStatus(Order.EXPORT_STATUS_READY);
order.setConfirmationStatus(Order.CONFIRMATION_STATUS_CONFIRMED);
OrderMgr.undoCancelOrder(order);
AdyenLogs.info_log(`Undo failed capture, Order ${order.orderNo} updated to status PAID.`);

This logic enables merchants to capture funds even after an initial order cancellation, effectively reversing the cancel when the payment later succeeds.

Handling REFUND Events

The src/cartridges/int_adyen_webhooks/cartridge/eventHandlers/REFUND.js module processes refund notifications by enforcing a simple business rule: refunded orders become unpaid (lines 4‑8). The handler implements:

order.setPaymentStatus(Order.PAYMENT_STATUS_NOTPAID);
order.trackOrderChange('REFUND notification received');
AdyenLogs.info_log(`Order ${order.orderNo} was refunded.`);

Setting the status to NOTPAID ensures downstream processes treat the order as requiring no further payment collection, while trackOrderChange() preserves the refund notification audit trail.

Summary

  • Success validation occurs in webhookUtils.js, checking custom.success === 'true' before any handler processes the event.
  • AUTHORISATION handles duplicates, partial payments, fraud reviews, failed order recovery, and standard placements via AUTHORISATION.js.
  • CAPTURE specifically reverses cancelled orders when capture succeeds, using undoCancelOrder() in CAPTURE.js.
  • REFUND forces payment status to NOTPAID and logs the event in REFUND.js.
  • All handlers persist webhook data to custom order attributes (Adyen_eventCode, Adyen_value) for comprehensive audit trails.

Frequently Asked Questions

How does the system prevent duplicate AUTHORISATION callbacks from processing?

The AUTHORISATION handler checks order.paymentStatus.value against Order.PAYMENT_STATUS_PAID before executing business logic. If the order is already paid, the handler logs the duplicate and returns early without modifying order state, preventing double-processing of the same authorization.

What happens when a CAPTURE webhook arrives for a cancelled order?

When the CAPTURE handler detects an order with ORDER_STATUS_CANCELLED, it invokes OrderMgr.undoCancelOrder(order) to reopen the order, then sets payment, export, and confirmation statuses to their paid equivalents. This allows the merchant to fulfill the order despite the prior cancellation.

Why does the REFUND handler set the payment status to NOTPAID instead of creating a separate refund status?

The implementation treats refunded orders as unpaid for downstream export and fulfillment systems. Setting Order.PAYMENT_STATUS_NOTPAID ensures no further payment collection attempts occur, while order.trackOrderChange() preserves the refund notification audit trail separately from the payment status.

Where is the webhook success criteria defined?

The success validation logic resides in src/cartridges/int_adyen_webhooks/cartridge/utils/webhookUtils.js. The isWebhookSuccessful() function strictly checks that customObj.custom.success === 'true' before allowing any handler to modify order data, ensuring only successful Adyen events affect order states.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →