From storefront-next
End-to-end workflow for consuming custom SCAPI endpoints from a Storefront Next project: adding typed clients, discovering schemas, and calling from loaders/actions/useScapiFetcher.
How this skill is triggered — by the user, by Claude, or both
Slash command
/storefront-next:sfnext-custom-apisThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
This skill covers the end-to-end workflow for implementing and consuming custom SCAPI endpoints from a Storefront Next project.
This skill covers the end-to-end workflow for implementing and consuming custom SCAPI endpoints from a Storefront Next project.
Custom APIs let you define your own REST endpoints on B2C Commerce. In a Storefront Next project, you call these from loaders and actions just like standard SCAPI clients — with full type safety.
Create custom API → Deploy & register → Add typed client → Discover schema → Call from loader
(cartridge) (b2c code deploy) (sfnext scapi add) (scapi schemas) (createApiClients)
A custom API consists of three files in a cartridge:
my-cartridge/cartridge/rest-apis/my-loyalty-api/
├── schema.yaml # OpenAPI 3.0 schema (endpoints, params, responses)
├── api.json # API metadata (version, security scheme)
└── script.js # Implementation (controller script)
For full details on writing these files, see the b2c:b2c-custom-api-development skill.
Key choices that affect the client:
| Choice | Impact |
|---|---|
Directory name (my-loyalty-api) | Becomes the API name for scapi add |
type in api.json (shopper or admin) | Determines auth scheme and whether siteId is required |
| Paths in schema.yaml | Become the methods on the typed client |
Deploy the cartridge and verify the custom API is registered:
# deploy the cartridge
b2c code deploy ./my-cartridge --activate
# verify registration
b2c scapi custom status
A successful registration shows status: active for your endpoints. If you see not_registered, debug with:
b2c scapi custom status --status not_registered --columns type,apiName,endpointPath,errorReason
See b2c-cli:b2c-scapi-custom for full diagnostics.
Once registered, add the custom API to your Storefront Next project:
b2c sfnext scapi add custom my-loyalty-api v1
This generates typed client code. The client becomes available as:
const clients = createApiClients(context);
clients.myLoyaltyApi.getPoints({...});
Use schema browsing to understand your custom API's endpoints and response types:
# list endpoints
b2c scapi schemas get custom my-loyalty-api v1 --list-paths
# expand a specific endpoint
b2c scapi schemas get custom my-loyalty-api v1 \
--expand-paths /loyalty/points/{customerId}
This shows you the exact parameter names and response shape to use in your loader.
import { createApiClients } from '@/lib/api-clients';
export function loader({ params, context }: LoaderFunctionArgs) {
const clients = createApiClients(context);
return {
loyaltyPoints: clients.myLoyaltyApi.getPoints({
params: {
path: { customerId: params.customerId },
query: { siteId: context.siteId }
}
}).then(({ data }) => data),
};
}
import { data } from 'react-router';
import { createApiClients } from '@/lib/api-clients';
export async function action({ request, context }: ActionFunctionArgs) {
const formData = await request.formData();
const clients = createApiClients(context);
try {
await clients.myLoyaltyApi.redeemPoints({
params: {
path: { customerId: formData.get('customerId') as string },
query: { siteId: context.siteId },
body: { points: Number(formData.get('points')) }
}
});
return data({ success: true });
} catch (error) {
return data({ success: false, error: error.message }, { status: 400 });
}
}
For on-demand fetching triggered by user interactions:
import { useScapiFetcher } from '@/hooks/use-scapi-fetcher';
export function useLoyaltyPoints(customerId: string) {
const parameters = useMemo(
() => ({
params: {
path: { customerId },
query: { siteId: getSiteId() }
}
}),
[customerId]
);
const fetcher = useScapiFetcher(
'myLoyaltyApi',
'getPoints',
parameters
);
return {
points: fetcher.data,
isLoading: fetcher.state === 'loading',
refresh: () => fetcher.load(),
};
}
| Issue | Cause | Solution |
|---|---|---|
| Client property not available | Forgot sfnext scapi add | Run b2c sfnext scapi add custom <name> <version> |
| 404 from custom endpoint | API not registered | Check b2c scapi custom status; redeploy with --activate |
| 401 Unauthorized | Wrong security scheme | Shopper APIs use ShopperToken; Admin APIs use BearerToken |
Missing siteId error | Shopper custom APIs require siteId | Always include siteId in query params for Shopper APIs |
| Schema returns empty | API not yet registered | Deploy and activate the cartridge first, then browse schemas |
| Types outdated after schema change | Stale generated types | Re-run b2c sfnext scapi add custom <name> <version> --force |
The API directory name maps to a camelCase property on createApiClients():
| Directory Name | Client Property | Example Call |
|---|---|---|
my-loyalty-api | clients.myLoyaltyApi | clients.myLoyaltyApi.getPoints({...}) |
order-status | clients.orderStatus | clients.orderStatus.getStatus({...}) |
inventory-check | clients.inventoryCheck | clients.inventoryCheck.checkStock({...}) |
| Aspect | Shopper API | Admin API |
|---|---|---|
| Auth scheme | ShopperToken (SLAS) | BearerToken (Account Manager) |
Requires siteId | Yes | No |
| Called from | Storefront loaders/actions | Admin tools, batch jobs |
| Typical use | Customer-facing features | Back-office operations |
Most Storefront Next custom APIs are Shopper type since they serve storefront pages.
| Pitfall | Problem | Solution |
|---|---|---|
| Using admin auth for a shopper endpoint | 401 errors in storefront context | Set type: "shopper" in api.json |
| Forgetting to redeploy after schema changes | Stale endpoints | Redeploy cartridge and re-add client with --force |
Not including siteId for shopper APIs | Request rejected | Always pass siteId in query params |
| Calling custom API before registration completes | Intermittent 404s | Wait for status: active in b2c scapi custom status |
storefront-next:sfnext-scapi-management - Managing typed clients (add/remove/list)storefront-next:sfnext-data-fetching - Loader/action/useScapiFetcher patternsb2c:b2c-custom-api-development - Creating the custom API cartridge (schema + script + mapping)b2c-cli:b2c-scapi-custom - Checking custom API registration statusb2c-cli:b2c-scapi-schemas - Schema discovery commandsb2c-cli:b2c-code - Deploying and activating code versionsnpx claudepluginhub salesforcecommercecloud/b2c-developer-tooling --plugin storefront-nextManages typed SCAPI clients in Storefront Next projects: add, remove, list clients, and browse API schemas to discover endpoints before writing loaders.
Develops Custom SCAPI REST endpoints with api.json routes, schema.yaml definitions, and OAuth scope configuration. Helps debug endpoint registration and 404 issues for Salesforce B2C Commerce.
Documents OCAPI Shop and Data API endpoints, authentication, pagination, and SCAPI migration guide for maintaining legacy Salesforce B2C Commerce integrations.