BasketMergeHooks
CalculateHooks
CheckoutHooks
OrderHooks
PaymentHooks
ReturnHooks
ShippingHooks
ShippingOrderHooks
TaxHooks
DID THIS ARTICLE SOLVE YOUR ISSUE?
Let us know so we can improve!
Let us know so we can improve!
This interface represents tax extension points for Commerce App tax providers.
These hooks provide integration points for external tax calculation services installed via the Commerce App
framework. They are distinct from the legacy dw.order.calculateTax extension point.
IMPORTANT: These hooks should only be implemented and registered by Commerce Apps
(applications installed via the Commerce App framework with a CAP file). They are not intended for custom merchant
cartridges or storefront implementations. Merchants who want custom tax calculation logic should use the legacy
dw.order.calculateTax extension point instead.
Hook Registration A function must be defined inside a JavaScript source and must be exported. The script
with the exported hook function must be located inside a site cartridge. Inside the site cartridge a
package.json file with a ‘hooks’ entry must exist:
1"hooks": "./hooks.json"The hooks entry links to a JSON file, relative to the package.json file. This file lists all registered
hooks inside the hooks property:
1"hooks": [
2 {"name": "sfcc.app.tax.calculate", "script": "./calculate.js"},
3 {"name": "sfcc.app.tax.commit", "script": "./commit.js"},
4 {"name": "sfcc.app.tax.cancel", "script": "./cancel.js"}
5]A hook entry has a name and a script property:
namecontains the extension point name (the hook name).scriptcontains the script path relative to the hooks file, with the exported hook function.Function Naming Convention: The exported JavaScript function name must match the last segment of the
extension point name, for example, calculate, commit, cancel..
Order Lifecycle Context Each hook fires at a specific point in the order lifecycle:
CREATED). Notifies the tax provider that the order has been created and tax amounts should be committed.Hook Precedence
sfcc.app.tax.calculateis registered, it takes precedence over the legacy dw.order.calculateTaxhook.dw.order.calculateTax(if registered).Important: If you override the dw.order.calculate hook (the parent basket calculation
hook), the platform’s tax hook selection logic is bypassed entirely. In this case, if you want to use Commerce App
tax providers, you must manually invoke the sfcc.app.tax.calculate hook from within your custom
dw.order.calculate implementation.
SCAPI Behavior
SCAPI requests with ScapiHookExecutionEnabled disabled bypass all hooks (both Commerce App tax hooks and
the legacy dw.order.calculateTax hook) and go straight to the default platform tax calculation.
Hook Arguments and Return Types
dw.order.LineItemCtnr(typically a dw.order.Basket) as the first argument. Must return a dw.system.Statusobject (or nullfor success).dw.order.Orderobject as the first argument. Must return a dw.system.Statusobject (or nullfor success).dw.order.Orderobject as the first argument. Must return a dw.system.Statusobject (or nullfor success).Error Handling For calculate hook:
Status.ERRORand throwing an exception prevent the basket calculation from completing successfully. The platform logs the error and halts the current basket operation. Since order creation requires a successful basket calculation, this also prevents orders from being created with incorrect tax amounts.For commit hook:
The Commerce App developer chooses whether errors should block order creation by how they handle errors in their hook implementation:
**Non-blocking error:**Catch exceptions and return a Status.ERROR. The platform logs the error as a warning and continues with the order lifecycle. Use this when the tax provider is temporarily unavailable but the order should still be created.
1return new Status(Status.ERROR, 'TAX_COMMIT_FAILED', 'Details about the failure');**Blocking error:**Let exceptions propagate (don’t catch them). The platform logs the error and rolls back the order lifecycle operation, preventing the order from being created.
1throw new Error('Tax provider unavailable');For cancel hook:
The Commerce App developer chooses whether errors should block order cancellation by how they handle errors in their hook implementation:
**Non-blocking error:**Catch exceptions and return a Status.ERROR. The platform logs the error as a warning and continues with the order lifecycle. Use this when the tax provider is temporarily unavailable but the order cancellation should still proceed.
1return new Status(Status.ERROR, 'TAX_CANCEL_FAILED', 'Details about the failure');**Blocking error:**Let exceptions propagate (don’t catch them). The platform logs the error and rolls back the order cancellation operation.
1throw new Error('Tax provider unavailable');| Constant | Description |
|---|---|
| extensionPointAppCalculateTax: String = “sfcc.app.tax.calculate” | The extension point name sfcc.app.tax.calculate. |
| extensionPointAppCancelTax: String = “sfcc.app.tax.cancel” | The extension point name sfcc.app.tax.cancel. |
| extensionPointAppCommitTax: String = “sfcc.app.tax.commit” | The extension point name sfcc.app.tax.commit. |
This class does not have a constructor, so you cannot create it directly.
| Method | Description |
|---|---|
| calculate(LineItemCtnr) | The function is called by extension point extensionPointAppCalculateTax. |
| cancel(Order) | The function is called by extension point extensionPointAppCancelTax during OrderMgr.failOrder() or OrderMgr.cancelOrder(). |
| commit(Order) | The function is called by extension point extensionPointAppCommitTax during order creation in the order creation transaction. |
assign, create, create, defineProperties, defineProperty, entries, freeze, fromEntries, getOwnPropertyDescriptor, getOwnPropertyNames, getOwnPropertySymbols, getPrototypeOf, hasOwnProperty, is, isExtensible, isFrozen, isPrototypeOf, isSealed, keys, preventExtensions, propertyIsEnumerable, seal, setPrototypeOf, toLocaleString, toString, valueOf, values
The extension point name sfcc.app.tax.calculate.
The extension point name sfcc.app.tax.cancel.
The extension point name sfcc.app.tax.commit.
The function is called by extension point extensionPointAppCalculateTax. It calculates tax amounts for the basket line items during basket calculation. This hook fires on every basket operation (e.g., adding items, changing quantities, updating shipping), not only before order creation.
Note: If the dw.order.calculate hook is overridden, the platform's automatic tax
hook selection is bypassed. You must manually invoke this hook from within your custom
dw.order.calculate implementation if you want to use Commerce App tax providers.
Error Handling: Both returning a Status.ERROR and throwing an exception will
prevent the basket calculation from completing successfully. The platform logs the error and halts the current
basket operation. Since order creation requires a successful basket calculation, this also prevents orders from
being created with incorrect tax amounts.
SCAPI Behavior: When ScapiHookExecutionEnabled is disabled, SCAPI requests bypass
this hook and use default platform tax calculation.
Sample Implementation:
1function calculate(basket) {
2 var TaxMgr = require('dw/order/TaxMgr');
3 var Status = require('dw/system/Status');
4 var HTTPClient = require('dw/net/HTTPClient');
5
6 // 1. Extract shipping address and line items
7 var shipment = basket.getDefaultShipment();
8 var shippingAddress = shipment.getShippingAddress();
9
10 // 2. Build request for external tax provider
11 var taxRequest = {
12 addresses: {
13 shipTo: {
14 line1: shippingAddress.getAddress1(),
15 city: shippingAddress.getCity(),
16 region: shippingAddress.getStateCode(),
17 country: shippingAddress.getCountryCode().getValue(),
18 postalCode: shippingAddress.getPostalCode()
19 }
20 },
21 lines: []
22 };
23
24 // Add product line items
25 var pliIterator = basket.getProductLineItems().iterator();
26 while (pliIterator.hasNext()) {
27 var pli = pliIterator.next();
28 taxRequest.lines.push({
29 itemCode: pli.getProductID(),
30 quantity: pli.getQuantityValue(),
31 amount: pli.getAdjustedPrice().getValue(),
32 taxCode: pli.getTaxClassID() // Product tax category
33 });
34 }
35
36 // 3. Call external tax service
37 var httpClient = new HTTPClient();
38 httpClient.open('POST', 'https://api.taxprovider.com/calculate');
39 httpClient.setRequestHeader('Authorization', 'Bearer ' + apiKey);
40 httpClient.send(JSON.stringify(taxRequest));
41
42 if (httpClient.statusCode !== 200) {
43 return new Status(Status.ERROR, 'TAX_CALC_FAILED', 'Tax calculation failed: ' + httpClient.errorText);
44 }
45
46 var taxResponse = JSON.parse(httpClient.text);
47
48 // 4. Apply tax amounts to basket line items using TaxMgr
49 taxResponse.lines.forEach(function(line, index) {
50 var pli = basket.getProductLineItems()[index];
51 TaxMgr.setProductLineTax(pli, line.tax);
52 });
53
54 // Set shipping tax if applicable
55 if (taxResponse.shippingTax) {
56 TaxMgr.setShippingTax(shipment, taxResponse.shippingTax);
57 }
58
59 return new Status(Status.OK);
60}
61
62exports.calculate = calculate;Common APIs used: dw.order.TaxMgr (setProductLineTax, setShippingTax),
dw.net.HTTPClient, dw.order.LineItemCtnr (getProductLineItems, getShipments),
dw.order.ProductLineItem (getProductID, getTaxClassID), dw.order.OrderAddress
(getAddress1, getCity, getStateCode).
Parameters:
Returns:
Status.OK or null for success; Status.ERROR to block the basket
calculation with details about the failure. Throwing an exception will also block the basket calculation.The function is called by extension point extensionPointAppCancelTax during OrderMgr.failOrder() or OrderMgr.cancelOrder(). It notifies the Commerce App tax provider that the order has been cancelled or has failed, and that previously committed tax amounts should be voided or cancelled in the tax provider.
Error Handling:
Status.ERROR. The platform logs the error as a warning and continues with the order lifecycle. Use this when the tax provider is temporarily unavailable but the order cancellation should still proceed.
SCAPI Behavior: When ScapiHookExecutionEnabled is disabled, SCAPI requests bypass
this hook.
Sample Implementation:
1function cancel(order) {
2 var Status = require('dw/system/Status');
3 var HTTPClient = require('dw/net/HTTPClient');
4
5 // 1. Retrieve the external transaction ID stored during commit
6 var taxProviderTransactionId = order.custom.taxProviderTransactionId;
7
8 if (!taxProviderTransactionId) {
9 // No transaction to cancel - tax was never committed
10 return new Status(Status.OK);
11 }
12
13 // 2. Build void/cancel request for external tax provider
14 var cancelRequest = {
15 code: order.getOrderNo(),
16 type: 'SalesInvoice'
17 };
18
19 // 3. Call external tax service to void/cancel the transaction
20 var httpClient = new HTTPClient();
21 httpClient.open('POST', 'https://api.taxprovider.com/transactions/' + taxProviderTransactionId + '/void');
22 httpClient.setRequestHeader('Authorization', 'Bearer ' + apiKey);
23 httpClient.send(JSON.stringify(cancelRequest));
24
25 if (httpClient.statusCode !== 200 && httpClient.statusCode !== 204) {
26 // Non-blocking error: log warning but allow order cancellation to proceed
27 return new Status(Status.ERROR, 'TAX_CANCEL_FAILED',
28 'Failed to void tax transaction in provider, order cancellation will proceed. Error: ' + httpClient.errorText);
29 }
30
31 return new Status(Status.OK);
32}
33
34exports.cancel = cancel;Common APIs used: dw.net.HTTPClient, dw.order.Order (getOrderNo, custom
attributes), dw.system.Status.
Parameters:
Returns:
Status.OK or null for success; Status.ERROR to log a warning
without blocking the order cancellation. Throwing an exception will roll back the order cancellation
operation.The function is called by extension point extensionPointAppCommitTax during order creation in the order
creation transaction. It notifies the Commerce App tax provider that the order has been successfully created and
that tax amounts should be committed to the tax provider. The order is in CREATED status at this
point (before being placed).
Error Handling:
Status.ERROR. The platform logs the error as a warning and continues with the order lifecycle. Use this when the tax provider is temporarily unavailable but the order should still be created.
SCAPI Behavior: When ScapiHookExecutionEnabled is disabled, SCAPI requests bypass
this hook.
Sample Implementation:
1function commit(order) {
2 var Transaction = require('dw/system/Transaction');
3 var Status = require('dw/system/Status');
4 var HTTPClient = require('dw/net/HTTPClient');
5
6 // 1. Build commit request for external tax provider
7 var commitRequest = {
8 code: order.getOrderNo(), // Use order number as unique transaction ID
9 type: 'SalesInvoice',
10 companyCode: 'DEFAULT',
11 date: order.getCreationDate(),
12 customerCode: order.getCustomerNo(),
13 addresses: {
14 shipTo: {
15 line1: order.getDefaultShipment().getShippingAddress().getAddress1(),
16 city: order.getDefaultShipment().getShippingAddress().getCity(),
17 region: order.getDefaultShipment().getShippingAddress().getStateCode(),
18 country: order.getDefaultShipment().getShippingAddress().getCountryCode().getValue(),
19 postalCode: order.getDefaultShipment().getShippingAddress().getPostalCode()
20 }
21 },
22 lines: [],
23 commit: true // Tell provider to commit the transaction
24 };
25
26 // Add order line items
27 var pliIterator = order.getProductLineItems().iterator();
28 while (pliIterator.hasNext()) {
29 var pli = pliIterator.next();
30 commitRequest.lines.push({
31 itemCode: pli.getProductID(),
32 quantity: pli.getQuantityValue(),
33 amount: pli.getAdjustedPrice().getValue(),
34 tax: pli.getAdjustedTax().getValue()
35 });
36 }
37
38 // 2. Call external tax service to commit transaction
39 var httpClient = new HTTPClient();
40 httpClient.open('POST', 'https://api.taxprovider.com/transactions');
41 httpClient.setRequestHeader('Authorization', 'Bearer ' + apiKey);
42 httpClient.send(JSON.stringify(commitRequest));
43
44 if (httpClient.statusCode !== 200 && httpClient.statusCode !== 201) {
45 // Non-blocking error: log warning but allow order to proceed
46 return new Status(Status.ERROR, 'TAX_COMMIT_FAILED',
47 'Failed to commit tax to provider, order will proceed. Error: ' + httpClient.errorText);
48 }
49
50 var commitResponse = JSON.parse(httpClient.text);
51
52 // 3. Store external transaction ID in order custom attribute for later reference (cancel/refund)
53 Transaction.wrap(function() {
54 order.custom.taxProviderTransactionId = commitResponse.id;
55 });
56
57 return new Status(Status.OK);
58}
59
60exports.commit = commit;Common APIs used: dw.system.Transaction, dw.net.HTTPClient, dw.order.Order
(getOrderNo, getProductLineItems, getDefaultShipment, custom attributes), dw.order.ProductLineItem
(getAdjustedTax).
Parameters:
Returns:
Status.OK or null for success; Status.ERROR to log a warning
without blocking the order. Throwing an exception will roll back the order creation.