sfcc-ocapi-scapi
Included with Lifetime
$97 forever
Integrate with Salesforce Commerce Cloud's headless APIs (OCAPI and Shopper APIs) to build custom storefronts and mobile commerce experiences
platform-salesforce-ccsalesforce-commerce-cloudsfccocapiscapishopper-apiheadlessb2cjwt
What this skill does
# SFCC OCAPI and Shopper APIs
## Overview
Salesforce B2C Commerce provides two API families: the legacy Open Commerce API (OCAPI) using Basic Auth or OAuth and the modern Commerce API (SCAPI/Shopper APIs) using SLAS (Shopper Login and API Access Service) tokens. SCAPI is the recommended approach for headless storefronts, PWA Kit, and third-party integrations. OCAPI remains the primary Data API for server-side admin operations (product import, order management, promotion management). The Composable Storefront (formerly PWA Kit) is built entirely on SCAPI.
## When to Use This Skill
- When building a headless B2C storefront using SFCC as the commerce backend
- When implementing the Salesforce PWA Kit (Composable Storefront) with custom API calls
- When integrating a mobile app with SFCC product catalog, cart, and checkout
- When building server-side order management integrations using OCAPI Data API
- When migrating an existing OCAPI integration to the newer SCAPI endpoints
- When implementing SLAS token management for customer authentication flows
## Core Instructions
1. **Understand the API landscape**
| API | Auth | Use Case |
|-----|------|----------|
| SCAPI Shopper APIs | SLAS guest/customer token | Headless storefront, product search, cart, checkout |
| OCAPI Shop API | Basic/OAuth | Storefront operations from trusted server contexts |
| OCAPI Data API | Client credentials | Admin operations: product import, order management, promotions |
| SCAPI Admin APIs | Client credentials | Modern admin operations (gradually replacing OCAPI Data API) |
Base URL pattern: `https://{shortCode}.api.commercecloud.salesforce.com/`
2. **Authenticate with SLAS (Shopper Login and API Access Service)**
```typescript
// lib/sfcc-auth.ts
const SLAS_BASE = `https://${process.env.SFCC_SHORT_CODE}.api.commercecloud.salesforce.com/shopper/auth/v1`;
const ORG_ID = process.env.SFCC_ORG_ID!; // f_ecom_xxx format
const CLIENT_ID = process.env.SFCC_SLAS_CLIENT_ID!;
// Step 1: Get PKCE code challenge for guest token
function generateCodeChallenge(): { verifier: string; challenge: string } {
const nodeCrypto = require("crypto");
const verifier = nodeCrypto.randomBytes(32).toString("hex");
const hash = nodeCrypto.createHash("sha256").update(verifier).digest("base64url");
return { verifier, challenge: hash };
}
// Get a guest access token
export async function getGuestToken(): Promise<{ access_token: string; refresh_token: string }> {
const { verifier, challenge } = generateCodeChallenge();
// Step 1: Authorize (get auth code)
const authorizeUrl = new URL(`${SLAS_BASE}/organizations/${ORG_ID}/oauth2/authorize`);
authorizeUrl.searchParams.set("client_id", CLIENT_ID);
authorizeUrl.searchParams.set("channel_id", process.env.SFCC_SITE_ID!);
authorizeUrl.searchParams.set("redirect_uri", process.env.SFCC_SLAS_REDIRECT_URI!);
authorizeUrl.searchParams.set("response_type", "code");
authorizeUrl.searchParams.set("code_challenge", challenge);
authorizeUrl.searchParams.set("hint", "guest");
// SFCC returns a redirect — extract the code from the Location header
const authResponse = await fetch(authorizeUrl.toString(), { redirect: "manual" });
const location = authResponse.headers.get("location") ?? "";
const code = new URL(location).searchParams.get("code") ?? "";
// Step 2: Exchange code for token
const tokenResponse = await fetch(
`${SLAS_BASE}/organizations/${ORG_ID}/oauth2/token`,
{
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({
grant_type: "authorization_code_pkce",
code,
code_verifier: verifier,
client_id: CLIENT_ID,
redirect_uri: process.env.SFCC_SLAS_REDIRECT_URI!,
channel_id: process.env.SFCC_SITE_ID!,
}),
}
);
return tokenResponse.json();
}
// Refresh an access token
export async function refreshToken(refreshToken: string) {
const response = await fetch(`${SLAS_BASE}/organizations/${ORG_ID}/oauth2/token`, {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({
grant_type: "refresh_token",
refresh_token: refreshToken,
client_id: CLIENT_ID,
}),
});
return response.json();
}
```
3. **Query the product catalog with Shopper Products API**
```typescript
// lib/sfcc-products.ts
const API_BASE = `https://${process.env.SFCC_SHORT_CODE}.api.commercecloud.salesforce.com`;
const ORG_ID = process.env.SFCC_ORG_ID!;
const SITE_ID = process.env.SFCC_SITE_ID!;
// Search products
export async function searchProducts(params: {
q?: string;
categoryId?: string;
start?: number;
count?: number;
sortKey?: string;
}, accessToken: string) {
const url = new URL(`${API_BASE}/search/shopper-search/v1/organizations/${ORG_ID}/product-search`);
url.searchParams.set("siteId", SITE_ID);
if (params.q) url.searchParams.set("q", params.q);
if (params.categoryId) url.searchParams.set("refine", `cgid=${params.categoryId}`);
url.searchParams.set("start", (params.start ?? 0).toString());
url.searchParams.set("count", (params.count ?? 20).toString());
if (params.sortKey) url.searchParams.set("sort", params.sortKey);
url.searchParams.set("expand", "images,prices,availability,variations");
const response = await fetch(url.toString(), {
headers: { Authorization: `Bearer ${accessToken}` },
});
return response.json();
}
// Get product by ID
export async function getProduct(productId: string, accessToken: string) {
const url = `${API_BASE}/product/shopper-products/v1/organizations/${ORG_ID}/products/${productId}?siteId=${SITE_ID}&expand=images,prices,availability,variations,promotions`;
const response = await fetch(url, {
headers: { Authorization: `Bearer ${accessToken}` },
});
return response.json();
}
```
4. **Manage cart and checkout with Shopper Baskets API**
```typescript
// lib/sfcc-basket.ts
// Create a basket
export async function createBasket(accessToken: string) {
const response = await fetch(
`${API_BASE}/checkout/shopper-baskets/v1/organizations/${ORG_ID}/baskets?siteId=${SITE_ID}`,
{
method: "POST",
headers: {
Authorization: `Bearer ${accessToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ customerInfo: { email: null } }),
}
);
return response.json(); // { basketId: "xxx", ... }
}
// Add item to basket
export async function addItemToBasket(
basketId: string,
productId: string,
quantity: number,
accessToken: string
) {
const response = await fetch(
`${API_BASE}/checkout/shopper-baskets/v1/organizations/${ORG_ID}/baskets/${basketId}/items?siteId=${SITE_ID}`,
{
method: "POST",
headers: {
Authorization: `Bearer ${accessToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify([{ productId, quantity }]),
}
);
return response.json();
}
// Set shipping address
export async function setShipmentAddress(
basketId: string,
shipmentId = "me",
address: Record<string, string>,
accessToken: string
) {
const response = await fetch(
`${API_BASE}/checkout/shopper-baskets/v1/organizations/${ORG_ID}/baskets/${basketId}/shipments/${shipmentId}/shipping-address?siteId=${SITE_ID}`,
{
method: "PUT",
headers: {
Authorization: `Bearer ${accessToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify(address),
Related in platform-salesforce-cc
sfcc-business-manager
IncludedConfigure Salesforce Commerce Cloud via Business Manager — manage catalogs, promotions, site preferences, and run XML import/export jobs
platform-salesforce-cc
sfcc-cartridge-development
IncludedBuild SFRA-based Salesforce Commerce Cloud cartridges with controllers, ISML templates, and hooks to customize storefront behavior
platform-salesforce-cc