askill
b2c-hooks

b2c-hooksSafety 90Repository

Hook registration, HookMgr, OCAPI/SCAPI hooks, and system extension points

0 stars
1.2k downloads
Updated 2/5/2026

Package Files

Loading files...
SKILL.md

B2C Commerce Hooks

Hooks are extension points that allow you to customize business logic by registering scripts. B2C Commerce supports two types of hooks:

  1. OCAPI/SCAPI Hooks - Extend API resources with before, after, and modifyResponse hooks
  2. System Hooks - Custom extension points for order calculation, payment, and other core functionality

Hook Types Overview

TypePurposeExamples
OCAPI/SCAPIExtend API behaviordw.ocapi.shop.basket.afterPOST
SystemCore business logicdw.order.calculate
CustomYour own extension pointsapp.checkout.validate

Hook Registration

File Structure

my_cartridge/
├── package.json           # References hooks.json
└── cartridge/
    └── scripts/
        ├── hooks.json     # Hook registrations
        └── hooks/         # Hook implementations
            ├── basket.js
            └── order.js

package.json

Reference the hooks configuration file:

{
  "name": "my_cartridge",
  "hooks": "./cartridge/scripts/hooks.json"
}

hooks.json

Register hooks with their implementing scripts:

{
  "hooks": [
    {
      "name": "dw.ocapi.shop.basket.afterPOST",
      "script": "./hooks/basket.js"
    },
    {
      "name": "dw.ocapi.shop.basket.modifyPOSTResponse",
      "script": "./hooks/basket.js"
    },
    {
      "name": "dw.order.calculate",
      "script": "./hooks/order.js"
    }
  ]
}

Hook Script

Export functions matching the hook method name (without package prefix):

// hooks/basket.js
var Status = require('dw/system/Status');

exports.afterPOST = function(basket) {
    // Called after basket creation
    return new Status(Status.OK);
};

exports.modifyPOSTResponse = function(basket, basketResponse) {
    // Modify the API response
    basketResponse.c_customField = 'value';
};

HookMgr API

Use dw.system.HookMgr to call hooks programmatically:

var HookMgr = require('dw/system/HookMgr');

// Check if hook exists
if (HookMgr.hasHook('dw.order.calculate')) {
    // Call the hook
    var result = HookMgr.callHook('dw.order.calculate', 'calculate', basket);
}
MethodDescription
hasHook(extensionPoint)Returns true if hook is registered or has default implementation
callHook(extensionPoint, functionName, args...)Calls the hook, returns result or undefined

Status Object

Hooks return dw.system.Status to indicate success or failure:

var Status = require('dw/system/Status');

// Success - continue processing
return new Status(Status.OK);

// Error - stop processing, rollback transaction
var status = new Status(Status.ERROR);
status.addDetail('error_code', 'INVALID_ADDRESS');
status.addDetail('message', 'Address validation failed');
return status;
StatusHTTP ResponseBehavior
Status.OKContinuesHook execution continues
Status.ERROR400 Bad RequestTransaction rolled back, processing stops
Uncaught exception500 Internal ErrorTransaction rolled back

OCAPI/SCAPI Hooks

OCAPI and SCAPI share the same hooks. Enable in Business Manager: Administration > Global Preferences > Feature Switches > Enable Salesforce Commerce Cloud API hook execution

Hook Types

HookWhen CalledUse Case
before<METHOD>Before processingValidation, access control
after<METHOD>After processing (in transaction)Data modification, external calls
modify<METHOD>ResponseBefore response sentAdd/modify response properties

Common Hook Patterns

// Validation in beforePUT
exports.beforePUT = function(basket, addressDoc) {
    if (!isValidAddress(addressDoc)) {
        var status = new Status(Status.ERROR);
        status.addDetail('validation_error', 'Invalid address');
        return status;
    }
};

// External call in afterPOST (within transaction)
exports.afterPOST = function(basket, paymentDoc) {
    var result = callPaymentService(paymentDoc);
    request.custom.paymentResult = result; // Pass to modifyResponse
    return new Status(Status.OK);
};

// Modify response
exports.modifyPOSTResponse = function(basket, basketResponse, paymentDoc) {
    basketResponse.c_paymentStatus = request.custom.paymentResult.status;
};

Passing Data Between Hooks

Use request.custom to pass data between hooks in the same request:

// In afterPOST
exports.afterPOST = function(basket, doc) {
    request.custom.externalId = callExternalService();
};

// In modifyPOSTResponse
exports.modifyPOSTResponse = function(basket, response, doc) {
    response.c_externalId = request.custom.externalId;
};

Detect SCAPI vs OCAPI

exports.afterPOST = function(basket) {
    if (request.isSCAPI()) {
        // SCAPI-specific logic
    } else {
        // OCAPI-specific logic
    }
};

System Hooks

Calculate Hooks

Extension PointFunctionPurpose
dw.order.calculatecalculateFull basket/order calculation
dw.order.calculateShippingcalculateShippingShipping calculation
dw.order.calculateTaxcalculateTaxTax calculation
// hooks/calculate.js
var Status = require('dw/system/Status');
var HookMgr = require('dw/system/HookMgr');

exports.calculate = function(lineItemCtnr) {
    // Calculate shipping
    HookMgr.callHook('dw.order.calculateShipping', 'calculateShipping', lineItemCtnr);

    // Calculate promotions, totals...

    // Calculate tax
    HookMgr.callHook('dw.order.calculateTax', 'calculateTax', lineItemCtnr);

    return new Status(Status.OK);
};

Payment Hooks

Extension PointFunctionPurpose
dw.order.payment.authorizeauthorizePayment authorization
dw.order.payment.capturecaptureCapture authorized payment
dw.order.payment.refundrefundRefund payment
dw.order.payment.validateAuthorizationvalidateAuthorizationCheck authorization validity
dw.order.payment.reauthorizereauthorizeRe-authorize expired auth

Order Hooks

Extension PointFunctionPurpose
dw.order.createOrderNocreateOrderNoCustom order number generation
var OrderMgr = require('dw/order/OrderMgr');
var Site = require('dw/system/Site');

exports.createOrderNo = function() {
    var seqNo = OrderMgr.createOrderSequenceNo();
    var prefix = Site.current.ID;
    return prefix + '-' + seqNo;
};

Custom Hooks

Create your own extension points:

// Define custom hook
var HookMgr = require('dw/system/HookMgr');

function processCheckout(basket) {
    // Call custom hook if registered
    if (HookMgr.hasHook('app.checkout.validate')) {
        var status = HookMgr.callHook('app.checkout.validate', 'validate', basket);
        if (status && status.error) {
            return status;
        }
    }
    // Continue processing...
}

Register in hooks.json:

{
  "hooks": [
    {
      "name": "app.checkout.validate",
      "script": "./hooks/checkout.js"
    }
  ]
}

Custom hooks always execute all registered implementations regardless of return value.

Remote Includes in Hooks

Enhance API responses with data from other SCAPI endpoints:

var RESTResponseMgr = require('dw/system/RESTResponseMgr');

exports.modifyGETResponse = function(product, doc) {
    // Include Custom API response
    var include = RESTResponseMgr.createScapiRemoteInclude(
        'custom',           // API family
        'my-api',           // API name
        'v1',               // Version
        'endpoint'          // Endpoint
    );
    doc.c_additionalData = { value: [include] };
};

Best Practices

Do

  • Return Status objects to control flow
  • Use request.custom to pass data between hooks
  • Check request.isSCAPI() when supporting both APIs
  • Keep hooks focused and performant
  • Use custom properties (c_ prefix) in modifyResponse

Don't

  • Use transactions in calculate hooks (breaks SCAPI)
  • Modify standard response properties (only c_ properties)
  • Rely on hook execution order across cartridges
  • Make slow external calls in beforeGET (affects caching)

Error Handling

Circuit Breaker

Too many hook errors triggers circuit breaker (HTTP 503):

{
  "title": "Hook Circuit Breaker",
  "type": "https://api.commercecloud.salesforce.com/.../hook-circuit-breaker",
  "detail": "Failure rate above threshold of '50%'",
  "extensionPointName": "dw.ocapi.shop.basket.afterPOST"
}

Timeout

Hooks must complete within the SCAPI timeout (HTTP 504 on timeout).

Detailed References

Install

Download ZIP
Requires askill CLI v1.0+

AI Quality Score

95/100Analyzed 2/9/2026

An exceptionally thorough and well-structured guide to Salesforce B2C Commerce hooks. It covers registration, implementation, API usage, and specific hook types with clear code examples and best practices.

90
100
90
98
95

Metadata

Licenseunknown
Version-
Updated2/5/2026
Publishermajiayu000

Tags

apisecurity