# How to Handle Refund Processing Including Partial Refunds in Adyen Salesforce Commerce Cloud

> Learn to process full and partial refunds in Adyen Salesforce Commerce Cloud. Discover webhook handler strategies and how to manage gift card order refunds efficiently.

- Repository: [Adyen/adyen-salesforce-commerce-cloud](https://github.com/adyen/adyen-salesforce-commerce-cloud)
- Tags: how-to-guide
- Published: 2026-02-23

---

**The Adyen SFCC integration processes full refunds via webhook handlers that mark orders as `NOTPAID`, while partial refunds for gift-card orders require calling `cancelPartialPaymentOrderHelper` to restore balances and clean up session data.**

The `adyen/adyen-salesforce-commerce-cloud` repository provides a comprehensive refund architecture that handles both standard refunds and complex partial-payment scenarios involving gift cards. Understanding how to handle refund processing including partial refunds ensures that your Commerce Cloud storefront maintains accurate order states and financial records when customers request money back. This guide examines the webhook-driven refund flow, the specific handlers for different notification types, and the helper functions that manage gift-card reversals.

## Understanding the Refund Flow Architecture

The integration adopts a webhook-driven architecture where Adyen pushes notification events to your SFCC endpoints. This design ensures that refund statuses remain synchronized between Adyen’s platform and your Commerce Cloud order management system.

### Webhook Routing and Event Handling

When Adyen processes a refund or cancellation, it dispatches notifications to `src/cartridges/int_adyen_webhooks/cartridge/controllers/webhook/`. The router inspects the `eventCode` field and delegates to the appropriate handler in `src/cartridges/int_adyen_webhooks/cartridge/eventHandlers/`.

The system distinguishes between three primary refund scenarios:
- **Full refunds** triggered by the `REFUND` webhook
- **Ambiguous cancel/refund operations** handled by `CANCEL_OR_REFUND`
- **Partial payment reversals** for gift-card transactions managed by `cancelPartialPaymentOrderHelper`

### Full Refund Processing

For standard refunds, the [`REFUND.js`](https://github.com/adyen/adyen-salesforce-commerce-cloud/blob/main/REFUND.js) handler receives the order object and updates the payment status immediately. This ensures that the order appears as "Not Paid" in Business Manager, preventing accidental fulfillment of refunded orders.

### Cancel or Refund Processing

The `CANCEL_OR_REFUND` webhook type handles scenarios where Adyen cannot distinguish between a cancellation and a refund (common in certain payment methods). The handler logic mirrors the standard refund process but logs the specific event type for audit trails.

## Implementing Full Refunds with the REFUND Handler

The [`REFUND.js`](https://github.com/adyen/adyen-salesforce-commerce-cloud/blob/main/REFUND.js) handler in `src/cartridges/int_adyen_webhooks/cartridge/eventHandlers/` provides the core logic for processing full refund notifications. When executed, it performs three critical operations: updating the order status, recording an audit trail, and writing system logs.

```javascript
// src/cartridges/int_adyen_webhooks/cartridge/eventHandlers/REFUND.js
const Order = require('dw/order/Order');
const AdyenLogs = require('*/cartridge/adyen/logs/adyenCustomLogs');

function handle({ order }) {
    // Mark the order as NOTPAID (full amount is no longer captured)
    order.setPaymentStatus(Order.PAYMENT_STATUS_NOTPAID);
    
    // Record a note for audit purposes
    order.trackOrderChange('REFUND notification received');
    
    // Write an info log (visible in Business Manager)
    AdyenLogs.info_log(`Order ${order.orderNo} was refunded.`);
}

module.exports = { handle };

```

**Key implementation details:**
- **`Order.PAYMENT_STATUS_NOTPAID`** immediately removes the paid status from the order
- **`trackOrderChange()`** creates a permanent record in the order history
- **`AdyenLogs.info_log()`** ensures visibility in Business Manager log files

The handler is covered by unit tests in [`src/cartridges/int_adyen_webhooks/cartridge/eventHandlers/__tests__/REFUND.test.js`](https://github.com/adyen/adyen-salesforce-commerce-cloud/blob/main/src/cartridges/int_adyen_webhooks/cartridge/eventHandlers/__tests__/REFUND.test.js), which verify that all three operations execute correctly when the webhook fires.

## Handling Cancel or Refund Scenarios

The [`CANCEL_OR_REFUND.js`](https://github.com/adyen/adyen-salesforce-commerce-cloud/blob/main/CANCEL_OR_REFUND.js) handler addresses edge cases where payment methods blur the line between cancellations and refunds. Located in the same directory as the standard refund handler, it executes identical status updates but differentiates the audit trail.

```javascript
// src/cartridges/int_adyen_webhooks/cartridge/eventHandlers/CANCEL_OR_REFUND.js
const Order = require('dw/order/Order');
const AdyenLogs = require('*/cartridge/adyen/logs/adyenCustomLogs');

function handle({ order }) {
    order.setPaymentStatus(Order.PAYMENT_STATUS_NOTPAID);
    order.trackOrderChange('CANCEL_OR_REFUND notification received');
    AdyenLogs.info_log(`Order ${order.orderNo} was cancelled or refunded.`);
}

module.exports = { handle };

```

Both handlers ensure that regardless of whether Adyen sends a `REFUND` or `CANCEL_OR_REFUND` notification, your SFCC order reflects the financial reality that funds have been returned to the customer.

## Processing Partial Refunds for Gift Card Orders

Partial refunds present unique complexity when orders use **split payment** methods—specifically when customers combine gift cards with Adyen payment instruments. In these scenarios, the integration must cancel the partial-payment order on Adyen’s side to restore gift-card balances.

### The Partial Payment Cancellation Helper

The `cancelPartialPaymentOrderHelper` function in [`src/cartridges/int_adyen_SFRA/cartridge/adyen/scripts/partialPayments/cancelPartialPaymentOrder.js`](https://github.com/adyen/adyen-salesforce-commerce-cloud/blob/main/src/cartridges/int_adyen_SFRA/cartridge/adyen/scripts/partialPayments/cancelPartialPaymentOrder.js) encapsulates the logic for reversing partial payments. It extracts the Adyen order reference from `basket.custom.partialPaymentOrderData`, calls the cancellation API, and cleans up local session data.

```javascript
// src/cartridges/int_adyen_SFRA/cartridge/adyen/scripts/partialPayments/cancelPartialPaymentOrder.js
function cancelPartialPaymentOrderHelper(basket) {
    // Guard clause – only run if a partial-payment order exists
    if (!basket || !basket.custom.partialPaymentOrderData) {
        return null;
    }

    // Extract the Adyen order reference stored in the basket
    const { order } = JSON.parse(basket.custom.partialPaymentOrderData);

    // Build the request for Adyen
    const cancelOrderRequest = {
        merchantAccount: AdyenConfigs.getAdyenMerchantAccount(),
        order,
    };

    // Execute the API call
    const response = adyenCheckout.doCancelPartialPaymentOrderCall(cancelOrderRequest);

    // On success – clean up basket and session
    if (response.resultCode === constants.RESULTCODES.RECEIVED) {
        Transaction.wrap(() => {
            collections.forEach(basket.getPaymentInstruments(), (item) => {
                if (item.custom.adyenPartialPaymentsOrder) {
                    basket.removePaymentInstrument(item);
                }
            });
            clearForms.clearAdyenBasketData(basket);
        });
        session.privacy.giftCardResponse = null;
        session.privacy.partialPaymentAmounts = null;
        session.privacy.giftCardBalance = null;
    } else {
        // Unexpected result – raise a custom error
        throw new AdyenError(`received resultCode ${response.resultCode}`);
    }

    return response;
}

```

This helper performs four critical cleanup operations:
1. **Removes gift-card payment instruments** from the basket
2. **Clears Adyen-specific basket data** using `clearForms.clearAdyenBasketData()`
3. **Nullifies session privacy variables** that track gift-card responses and balances
4. **Returns the API response** for upstream error handling

### Integration in Checkout Flow

The helper integrates into the checkout pipeline within [`src/cartridges/int_adyen_SFRA/cartridge/controllers/middlewares/checkout_services/placeOrder.js`](https://github.com/adyen/adyen-salesforce-commerce-cloud/blob/main/src/cartridges/int_adyen_SFRA/cartridge/controllers/middlewares/checkout_services/placeOrder.js). When payment authorization fails, the system checks for gift-card usage and triggers the cancellation helper to prevent orphaned holds on customer gift-card balances.

```javascript
// src/cartridges/int_adyen_SFRA/cartridge/controllers/middlewares/checkout_services/placeOrder.js
if (handlePaymentResult.error) {
    // Cancel partial payment order to refund gift cards if applicable
    let basketDataCleared = false;
    if (giftCardsAdded) {
        try {
            cancelPartialPaymentOrderHelper(currentBasket);
            basketDataCleared = true;
        } catch (error) {
            AdyenLogs.error_log('Failed to cancel partial payment order on payment failure:', error);
        }
    }
    // Continue with order failure handling...
}

```

The same helper function is exposed through a public controller endpoint (`cancelPartialPaymentOrder`) that client-side JavaScript in [`giftcards/index.js`](https://github.com/adyen/adyen-salesforce-commerce-cloud/blob/main/giftcards/index.js) can invoke via `window.cancelPartialPaymentOrderUrl` when users manually cancel checkout.

## Testing Your Refund Implementation

The repository includes comprehensive unit tests to validate refund behavior before deployment.

**Full refund testing:**
- Location: [`src/cartridges/int_adyen_webhooks/cartridge/eventHandlers/__tests__/REFUND.test.js`](https://github.com/adyen/adyen-salesforce-commerce-cloud/blob/main/src/cartridges/int_adyen_webhooks/cartridge/eventHandlers/__tests__/REFUND.test.js)
- Validates that `setPaymentStatus()`, `trackOrderChange()`, and logging all execute correctly

**Partial refund testing:**
- Location: [`src/cartridges/int_adyen_SFRA/cartridge/adyen/scripts/partialPayments/__tests__/cancelPartialPaymentOrder.test.js`](https://github.com/adyen/adyen-salesforce-commerce-cloud/blob/main/src/cartridges/int_adyen_SFRA/cartridge/adyen/scripts/partialPayments/__tests__/cancelPartialPaymentOrder.test.js)
- Tests both success paths (resultCode `RECEIVED`) and failure handling (AdyenError throwing)

**Manual sandbox verification:**
1. Configure the Adyen webhook URL to point at your SFCC endpoint
2. Trigger a full refund from the Adyen dashboard and confirm the order status changes to *Not Paid*
3. Create a basket with a gift-card, simulate a payment failure (e.g., `resultCode = REFUSED`), and verify that `cancelPartialPaymentOrderHelper` restores the gift-card balance and clears session data

## Summary

- **Full refunds** are processed via the [`REFUND.js`](https://github.com/adyen/adyen-salesforce-commerce-cloud/blob/main/REFUND.js) webhook handler, which sets orders to `PAYMENT_STATUS_NOTPAID` and creates audit trails
- **Cancel/Refund ambiguity** is handled by [`CANCEL_OR_REFUND.js`](https://github.com/adyen/adyen-salesforce-commerce-cloud/blob/main/CANCEL_OR_REFUND.js) using identical logic but distinct logging for compliance tracking
- **Partial refunds** require `cancelPartialPaymentOrderHelper` to call Adyen's cancellation API and restore gift-card balances
- **Checkout integration** automatically triggers partial refund cleanup when payment authorization fails in [`placeOrder.js`](https://github.com/adyen/adyen-salesforce-commerce-cloud/blob/main/placeOrder.js)
- **Session cleanup** is mandatory for partial refunds to prevent data leakage between checkout attempts

## Frequently Asked Questions

### How does the Adyen SFCC integration distinguish between full and partial refunds?

Full refunds are triggered by Adyen webhook notifications (`REFUND` or `CANCEL_OR_REFUND`) that invoke handlers in `int_adyen_webhooks`, while partial refunds for gift-card orders are handled proactively by `cancelPartialPaymentOrderHelper` in the checkout flow. The helper checks for `basket.custom.partialPaymentOrderData` to determine if a partial payment exists before attempting cancellation.

### What happens to the order status when a refund webhook is received?

The order status changes to `NOTPAID` immediately upon receipt of a valid refund webhook. According to the source code in [`REFUND.js`](https://github.com/adyen/adyen-salesforce-commerce-cloud/blob/main/REFUND.js), the handler calls `order.setPaymentStatus(Order.PAYMENT_STATUS_NOTPAID)` before recording the change note and writing the info log.

### Can customers reuse gift cards after a partial payment cancellation?

Yes, once `cancelPartialPaymentOrderHelper` successfully executes, the gift-card balance is restored on Adyen's platform and the local payment instrument is removed from the basket. The helper clears `session.privacy.giftCardBalance` and related variables, making the gift card available for immediate reuse.

### Where should I look if refunds are not updating order statuses in Business Manager?

First, verify that the webhook endpoint in `int_adyen_webhooks` is receiving notifications and routing them to the correct handler. Check `AdyenLogs` entries for the string "Order {orderNo} was refunded" to confirm the [`REFUND.js`](https://github.com/adyen/adyen-salesforce-commerce-cloud/blob/main/REFUND.js) handler executed. If processing partial refunds, ensure `cancelPartialPaymentOrderHelper` is being called and that `basket.custom.partialPaymentOrderData` contains valid JSON with the Adyen order reference.