Custom APIs

B2C Commerce provides powerful tools to customize shopper experiences. Today SCAPI can be customized via Hooks, where developers use the B2C Commerce Script API to add filters or modify responses before they get sent back to the calling application.

To leverage even further the existing development tools, we now provide a framework enabling developers to write custom script code, such as controllers, and expose this functionality as a custom REST API under the SCAPI framework.

A Custom API URL has the following structural format:

https://{shortCode}.api.commercecloud.salesforce.com/custom/{apiName}/{apiVersion}/organizations/{organizationId}/{endpointPath}

The term custom must be used as API family. The parameters apiName, apiVersion, and endpointPath can be defined as described below.

In order to create a Custom API, three components are required:

  • The API contract as an OAS 3.0 schema file.
  • The API implementation as a script using the B2C Commerce Script API.
  • The API mapping defined in an api.json file.

In this guide, we will look at an example called Loyalty Info API that can be used to retrieve the loyalty status for a given customer. This graphic shows the required components and their relationship:

Associated diagram

The components will be further explained in the next sections. For now, please note the following details from the diagram:

  • A dashed line shows where this URL segment is defined.
  • The blue parameter is the endpoint identifier. It is used to bind the endpoint to the implementation and appears in all three components.

Custom APIs are defined within custom code cartridges. In the cartridge directory, a new folder rest-apis must be created which is the root folder for all APIs in that cartridge.

In the rest-apis folder, subdirectories represent the actual APIs. The names of these directories represent the API names as they are addressed by the URL. Each directory contains the files for the three components representing this API.

Example: The structure for the example API called loyalty-info is expected to look like this:

API directory names can only contain alphanumeric lowercase characters and hyphens.

Due to the registration process, it is recommended to start implementing Custom API endpoints in a new code version.

The API contract must be provided by an OAS 3.0 schema file in YAML format. For more information about OAS 3.0, refer to the OAS 3.0 specification.

In this schema file, the API version and the endpoints are defined. The API version is located in the info.version field and is transformed into a URL version by using the major version segment and prepending it with v (for example, 1.0.1v1).

The endpoints are defined as part of the paths object and can implement multiple operations (i.e. HTTP methods). Each operation is required to have a property called operationId, which must be unique within the schema file. It is used for mapping the endpoint to the implementation. The path of the endpoint becomes the endpointPath in the URL structure.

In order to secure the endpoint, a valid security scheme must be defined as a shared component and applied at the endpoint or global level. See Authentication for more details.

Example: The schema for a /customers?c_customer_id={id} endpoint in version v1 is expected to look like this:

The API implementation is provided by a script file using the B2C Commerce Script API. The function name must match the value of the endpoint’s operationId in the contract.

Example: A valid implementation for /customers?c_customer_id={id} based on the definition in the contract could look like this:

It is strongly recommended to always return responses in JSON format. Errors should additionally adhere to the SCAPI error format as described in RFC 9457, with at least the type field being present. Response bodies are subject to validation in the future and may be declined if they don’t meet these requirements.

Please make sure that the implementation contains high quality, well-tested code with sufficient error handling. In order to protect the platform, Custom APIs use a Circuit Breaker mechanism that will block API requests when the implementation throws too many errors. See Circuit Breaker for more information.

To learn how to create JSON responses in your scripts with ease, have a look at the documentation of the Script API class RESTResponseMgr.

The API mapping is provided by an api.json file. It contains a list of endpoints, and for each entry the endpoint name, its schema file, and the name of the implementing script is defined.

Example: A valid mapping for /customers?c_customer_id={id} based on the definitions in the contract and implementation is expected to look like this:

Relative paths are not supported. The schema and implementation must be located at the same level as the corresponding api.json.

The implementation name must be provided without the file extension.

When the Custom API endpoints have been correctly defined as described earlier, they must be registered in order to be accessible.

The registration is triggered by activating the code version containing the new API definitions. Whenever changes to an API are required, it is recommended to work in a new code version and to switch the version when ready.

Custom API versions are represented in two different formats, the API version and the URL version.

The API version is defined in the contract as part of the info.version field and applies to all endpoints defined in this file. The value must be numeric but can have multiple segments separated by a dot.

In the URL, the version is transformed by using the major version segment and prepending it with v . For example, this list shows valid API versions and their corresponding URL versions:

  • 1 → v1
  • 1.0 → v1
  • 2.0 → v2
  • 2.1.1 → v2

It is recommended to introduce breaking changes in a new major version. Please see the SCAPI Change Policy for details.

The following system query parameters exist and can be used when defined in the contract:

  • siteId - The site of the current request
  • locale - The locale of the current request

Please be aware of the meaning of these parameters and when to use them. The siteId is used to identify the site context and is processed in this way by the system. Therefore, using this parameter only makes sense in a shopper context. In a merchant context that needs a site (for example, an API that returns objects filtered by site), use a custom query parameter like c_siteId. Additionally, it is important to note that the site is a query parameter instead of a path parameter - as this is different than other ways of customization, such as using controllers and hooks. The parameter locale is used to set the locale of the request, behaving in the same way as the Script API method dw.system.Request#setLocale.

If the siteId is not provided, it will default to the Business Manager site. Also, if the locale is not present in a request, it will default to the site’s default locale.

The parameter siteId is also used to register a Custom API. This means that if the cartridge containing a Custom API is not added to a site cartridge path, any request to it with that siteId will result in a 404 response.

Please also note that using a shopper token in a Business Manager site context is not allowed. An AmOAuth2 token should be used in such scenarios.

Example 1: Defining the system query parameter with the name siteId and the type string. If the parameter is not a valid string, the request is declined.

Example 2: Defining the system query parameter with the name locale and the type string. If the parameter is not a valid string, the request is declined.

Example 3: Making a Custom API request with system query parameters:

System query parameters must be defined with the correct schema field as shown above. Setting required to false indicates that the value is optional, whereas true will lead to the request being declined when the parameter is missing or empty.

All request parameters must be defined in the contract as requests with unknown parameters are declined. Custom query parameters must be prefixed with c_. System query parameters must be added to the contract if used.

Example: Defining a mandatory query parameter with the name c_status and the type integer. If the parameter is not present or is not a valid integer, the request is declined.

To get access to this repository, please complete the trail Tools & Resources for Salesforce B2C Commerce Developers.

Our community is maintaining a Custom API collection within the Sample Hooks Collection, providing the functionality earlier offered with hooks as new Custom APIs. Here are a few APIs available with this collection:

  • URL Resolution
  • URL List API
  • Guest Order Look Up
  • Customer Groups API
  • Mini Product
  • Send Mail API
  • Geo IP API

For more information, check out the Custom APIs Collection on the Salesforce Commerce Cloud GitHub repository.

The following limitations are in place:

  • Maximum request runtime of 10 seconds.
  • Transactions can’t be committed in the case of GET requests.
  • Currently, only HTTP GET requests are supported.