Develop Custom SCAPI REST endpoints with api.json routes, schema.yaml definitions, and OAuth scope configuration. Use this skill whenever the user needs to create a custom API on the Commerce platform, define OpenAPI 3.0 schemas for request/response, structure the rest-apis cartridge folder, or debug endpoint registration and 404 issues. Also use when building headless commerce integrations, choosing between Shopper (`ShopperToken`) and Admin (`AmOAuth2`) APIs, or troubleshooting why a Custom API endpoint isn't appearing or returning 404 in `b2c scapi custom status` — even if they just say 'custom REST endpoint', 'expose my script as an API', or 'my admin custom API isn't registering'.
Develop Custom SCAPI REST endpoints with api.json routes, schema.yaml definitions, and OAuth scope configuration. Use this skill whenever the user needs to create a custom API on the Commerce platform, define OpenAPI 3.0 schemas for request/response, structure the rest-apis cartridge folder, or debug endpoint registration and 404 issues. Also use when building headless commerce integrations, choosing between Shopper (`ShopperToken`) and Admin (`AmOAuth2`) APIs, or troubleshooting why a Custom API endpoint isn't appearing or returning 404 in `b2c scapi custom status` — even if they just say 'custom REST endpoint', 'expose my script as an API', or 'my admin custom API isn't registering'.
Custom API Development Skill
This skill guides you through developing Custom APIs for Salesforce B2C Commerce. Custom APIs let you expose custom script code as REST endpoints under the SCAPI framework.
Tip: If b2c CLI is not installed globally, use npx @salesforce/b2c-cli instead (e.g., npx @salesforce/b2c-cli code deploy).
Scope & grounding
This skill provides CLI-specific workflows and quickstart patterns for Custom API development. It covers OpenAPI 3.0 contract structure, OAuth scope configuration, cartridge-path resolution rules, and circuit breaker behavior. However, platform-specific validation rules, operational limits, security scheme requirements, and Script API integration patterns can drift across Commerce Cloud releases. Before answering questions that reference specific API versions or framework behavior, or before emitting code the user will run, confirm current platform specifics against the official documentation via b2c docs search / b2c docs read (CLI) or docs_search / docs_read (MCP). The official documentation is the authoritative source for Custom API contract specifications, runtime behavior, and B2C Commerce platform details not covered here.
Use ShopperToken for Shopper APIs (requires siteId), AmOAuth2 for Admin APIs
Custom scopes must start with c_, max 25 chars
Custom parameters must have c_ prefix
Cartridge path requirements (where the platform looks up your rest-apis/ folder)
Illustrative of platform cartridge resolution rules; confirm current runtime behavior and site context handling with b2c docs read commerce-api/custom-apis.
Call shape
Cartridge path searched
Shopper API (ShopperToken) — always site-scoped
The storefront site's cartridge path (the site that issued the SLAS token)
Admin API (AmOAuth2) with siteId=<storefront-site>
That storefront site's cartridge path
Admin API (AmOAuth2) with siteId=Sites-Site (the special BM/organization site)
The Business Manager cartridge path
Admin API (AmOAuth2) with siteId omitted
The Business Manager cartridge path
Admin APIs can be invoked in either site or organization context — the siteId parameter is optional, and one special value addresses the org context explicitly:
Passing a real storefront site ID (e.g. siteId=RefArch) runs the call in that site's context and resolves the cartridge against that site's cartridge path.
Passing siteId=Sites-Site is the literal way to invoke the Admin API against the Business Manager / organization site. Sites-Site is not a real storefront — it's the system-defined site that represents BM/org-level operations. The platform resolves the cartridge through the BM cartridge path.
Omitting siteId entirely is equivalent to org context and also resolves through the BM cartridge path.
The BM cartridge path is the common gotcha: if your Admin API is intended for org-level operations (called with siteId=Sites-Site or with siteId omitted), the cartridge containing rest-apis/must be on the BM cartridge path. A typical symptom is "registers fine when called with a storefront siteId but 404s in org context," or never appears in b2c scapi custom status for the org context.
Manage cartridge paths with the CLI (no BM clicks needed):
# Inspect the current BM cartridge path
b2c sites cartridges list --bm
# Add a cartridge to BM for org-context Admin APIs
b2c sites cartridges add my_admin_api_cartridge --bm --position first
# Add a cartridge to a storefront site (for Shopper APIs or site-scoped Admin APIs)
b2c sites cartridges add my_api_cartridge --site-id RefArch --position first
After updating any cartridge path, re-activate the code version (b2c code deploy --reload or b2c code activate <version>) so the platform re-registers the endpoints.
To set the BM cartridge path manually in Business Manager: Administration > Sites > Manage Sites > Business Manager (link in the header) > Settings > Cartridges.
See Contract Reference for full schema examples and Shopper vs Admin API differences.
Component 2: Implementation (script.js)
Illustrative Script API usage; confirm current Custom API integration patterns, RESTResponseMgr requirements, and request object methods with b2c docs read commerce-api/custom-api-components-references and Script API docs for dw.system.RESTResponseMgr / dw.system.Request.
varRESTResponseMgr = require('dw/system/RESTResponseMgr');
exports.getMyData = function() {
var myParam = request.getHttpParameterMap().get('c_my_param').getStringValue();
var result = { data: 'my data', param: myParam };
RESTResponseMgr.createSuccess(result).render();
};
exports.getMyData.public = true; // Required
Key requirements:
Mark exported functions with .public = true
Use RESTResponseMgr.createSuccess() for responses
Use RESTResponseMgr.createError() for error responses (RFC 9457 format)
Important: Implementation name must NOT include file extension.
Development Workflow
Create cartridge with rest-apis/{api-name}/ structure
Define contract (schema.yaml) with endpoints and security
Implement logic (script.js) with exported functions
Create mapping (api.json) binding endpoints to implementation
Deploy and activate the code version (--reload) to register endpoints — required on first registration and any contract (schema.yaml / api.json) change
Check registration status and test
For subsequent edits to script.js of an already-registered endpoint, redeploy without --reload — re-activation isn't needed for implementation-only changes
Deployment
# Deploy and activate to (re-)register endpoints
b2c code deploy ./my-cartridge --reload
# Deploy without re-activation (fine for implementation-only edits to already-registered endpoints)
b2c code deploy ./my-cartridge
# Check registration status
b2c scapi custom status --tenant-id zzpq_013
# Show failed registrations with error reasons
b2c scapi custom status --tenant-id zzpq_013 --status not_registered --columns apiName,endpointPath,errorReason
When you need to re-activate the code version (--reload)
Custom API endpoint registration is rebuilt on code-version activation, not on every file upload. That means:
Change
Re-activation required?
New endpoint, new API, or first-time registration
Yes
Edits to schema.yaml (paths, params, security, scopes, request/response shapes)
Yes
Edits to api.json (endpoint → implementation mapping)
Yes
Adding/removing the cartridge from a site or BM cartridge path
Yes
Edits to script.js (or any implementation/library code) for an already-registered endpoint
No — the new code is picked up live; just deploy without --reload
So during normal iteration on the implementation of an endpoint that's already registered, you can deploy repeatedly without paying the re-activation cost. Reach for --reload (or b2c code activate <version>) only when the contract changes or when an endpoint isn't registering yet.
Configure your custom scope (c_my_admin_scope) on the Account Manager API Client (Role: "Salesforce Commerce API")
Obtain a token via Account Manager OAuth with both required scope types:
Tenant scope: SALESFORCE_COMMERCE_API:<tenant_id> — grants access to the tenant
Custom Admin scope(s): c_my_admin_scope — as declared in schema.yaml
Omit siteId from requests (or use siteId=Sites-Site) for org context
# b2c auth token accepts multiple scopes (repeat --auth-scope or comma-separate).# It does NOT auto-inject the tenant scope, so list it explicitly:
TOKEN=$(b2c auth token \
--auth-scope "SALESFORCE_COMMERCE_API:zzpq_013" \
--auth-scope c_my_admin_scope)
Why the tenant scope matters: the SCAPI subcommands (b2c scapi custom status, b2c scapi schemas list) inject SALESFORCE_COMMERCE_API:<tenant_id> for you, but b2c auth token and raw curl send only the scopes you pass. A token missing the tenant scope returns 403 against any Admin API (custom or system).
Verify scope in token. For Admin APIs the token needs bothSALESFORCE_COMMERCE_API:<tenant_id> and your custom scope(s)
404 Not Found
Not registered
Check b2c scapi custom status
500 Internal Error
Script error
Check b2c logs get --level ERROR
503 Service Unavailable
Circuit breaker open
Fix errors, wait for reset
Registration Issues
Shopper-API endpoint not appearing: verify the cartridge is on the site's cartridge path (b2c sites cartridges list --site-id <site>), then re-activate the code version.
Admin-API endpoint called with a storefront siteId: verify the cartridge is on that site's cartridge path.
Admin-API endpoint called with siteId=Sites-Site (or with siteId omitted) returns 404 / never registers: the cartridge must be on the Business Manager cartridge path. Check with b2c sites cartridges list --bm and add it via b2c sites cartridges add <cartridge> --bm --position first. Re-activate the code version after. See Cartridge path requirements above.
Check logs: Use b2c logs get or filter Log Center with CustomApiRegistry
Related Skills
b2c-cli:b2c-code - Deploying cartridges and activating code versions
b2c-cli:b2c-scapi-custom - Checking Custom API registration status
b2c-cli:b2c-slas - Creating SLAS clients for testing Shopper APIs
b2c:b2c-webservices - Service configuration for external calls