Skip to content

Commit 1afc1cf

Browse files
committed
adding new b2c plugin with custom api development skill
1 parent e6e4149 commit 1afc1cf

3 files changed

Lines changed: 344 additions & 0 deletions

File tree

.claude-plugin/marketplace.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,17 @@
1717
"source": "./plugins/b2c-cli",
1818
"category": "productivity",
1919
"strict": false
20+
},
21+
{
22+
"name": "b2c",
23+
"description": "B2C Commerce development skills including Custom API development guides.",
24+
"author": {
25+
"name": "Salesforce"
26+
},
27+
"license": "Apache-2.0",
28+
"source": "./plugins/b2c",
29+
"category": "productivity",
30+
"strict": false
2031
}
2132
]
2233
}

plugins/README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ These skills follow the [Agent Skills](https://agentskills.io/home) format and c
99
| Plugin | Description |
1010
|--------|-------------|
1111
| `b2c-cli` | Skills for Salesforce Commerce Cloud B2C CLI operations |
12+
| `b2c` | B2C Commerce development skills including Custom API development guides |
1213

1314
## Installation
1415

@@ -68,6 +69,21 @@ plugins/b2c-cli/skills/
6869
└── b2c-webdav/SKILL.md # WebDAV commands
6970
```
7071

72+
## Plugin: b2c
73+
74+
The `b2c` plugin provides skills for B2C Commerce development practices and patterns. When installed, Claude can help you with:
75+
76+
- **Custom API Development** (`b2c-custom-api-development`) - Build SCAPI Custom APIs with contracts, implementations, and mappings
77+
78+
### Skills
79+
80+
Each skill is defined in the `b2c/skills/` directory:
81+
82+
```
83+
plugins/b2c/skills/
84+
└── b2c-custom-api-development/SKILL.md # Custom API development guide
85+
```
86+
7187
## For Contributors
7288

7389
When modifying CLI commands, update the corresponding skill in `plugins/b2c-cli/skills/b2c-<topic>/SKILL.md` to keep documentation in sync.
Lines changed: 317 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,317 @@
1+
---
2+
name: b2c-custom-api-development
3+
description: Guide for developing SCAPI Custom APIs on Salesforce B2C Commerce
4+
---
5+
6+
# Custom API Development Skill
7+
8+
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.
9+
10+
## Overview
11+
12+
A Custom API URL has this structure:
13+
14+
```
15+
https://{shortCode}.api.commercecloud.salesforce.com/custom/{apiName}/{apiVersion}/organizations/{organizationId}/{endpointPath}
16+
```
17+
18+
Three components are required to create a Custom API:
19+
20+
1. **API Contract** - An OAS 3.0 schema file (YAML)
21+
2. **API Implementation** - A script using the B2C Commerce Script API
22+
3. **API Mapping** - An `api.json` file binding endpoints to implementations
23+
24+
## Cartridge Structure
25+
26+
Custom APIs are defined within cartridges. Create a `rest-apis` folder in the cartridge directory with subdirectories for each API:
27+
28+
```
29+
/my-cartridge
30+
/cartridge
31+
package.json
32+
/rest-apis
33+
/my-api-name # API name (lowercase alphanumeric and hyphens only)
34+
api.json # Mapping file
35+
schema.yaml # OAS 3.0 contract
36+
script.js # Implementation
37+
/scripts
38+
/controllers
39+
```
40+
41+
**Important:** API directory names can only contain alphanumeric lowercase characters and hyphens.
42+
43+
## Component 1: API Contract (schema.yaml)
44+
45+
The API contract defines endpoints using OAS 3.0 format:
46+
47+
```yaml
48+
openapi: 3.0.0
49+
info:
50+
version: 1.0.0 # API version (1.0.0 becomes v1 in URL)
51+
title: My Custom API
52+
components:
53+
securitySchemes:
54+
ShopperToken: # For Shopper APIs (requires siteId)
55+
type: oauth2
56+
flows:
57+
clientCredentials:
58+
tokenUrl: https://{shortCode}.api.commercecloud.salesforce.com/shopper/auth/v1/organizations/{organizationId}/oauth2/token
59+
scopes:
60+
c_my_scope: Description of my scope
61+
AmOAuth2: # For Admin APIs (no siteId)
62+
type: oauth2
63+
flows:
64+
clientCredentials:
65+
tokenUrl: https://account.demandware.com/dwsso/oauth2/access_token
66+
scopes:
67+
c_my_admin_scope: Description of my admin scope
68+
parameters:
69+
siteId:
70+
name: siteId
71+
in: query
72+
required: true
73+
schema:
74+
type: string
75+
minLength: 1
76+
locale:
77+
name: locale
78+
in: query
79+
required: false
80+
schema:
81+
type: string
82+
minLength: 1
83+
paths:
84+
/my-endpoint:
85+
get:
86+
summary: Get something
87+
operationId: getMyData # Must match function name in script
88+
parameters:
89+
- $ref: '#/components/parameters/siteId'
90+
- in: query
91+
name: c_my_param # Custom params must start with c_
92+
required: true
93+
schema:
94+
type: string
95+
responses:
96+
'200':
97+
description: Success
98+
content:
99+
application/json:
100+
schema:
101+
type: object
102+
security:
103+
- ShopperToken: ['c_my_scope'] # Global security (or per-operation)
104+
```
105+
106+
### Contract Requirements
107+
108+
- **Version:** Defined in `info.version`, transformed to URL version (e.g., `1.0.1` becomes `v1`)
109+
- **Security Scheme:** Use `ShopperToken` for Shopper APIs or `AmOAuth2` for Admin APIs
110+
- **Custom Scopes:** Must start with `c_`, contain only alphanumeric/hyphen/period/underscore, max 25 chars
111+
- **Parameters:** All request parameters must be defined; custom params must have `c_` prefix
112+
- **System Parameters:** `siteId` and `locale` must have `type: string` and `minLength: 1`
113+
- **No additionalProperties:** The `additionalProperties` attribute is not allowed in request body schemas
114+
115+
### Shopper vs Admin APIs
116+
117+
| Aspect | Shopper API | Admin API |
118+
|--------|-------------|-----------|
119+
| Security Scheme | `ShopperToken` | `AmOAuth2` |
120+
| `siteId` Parameter | Required | Must omit |
121+
| Max Runtime | 10 seconds | 60 seconds |
122+
| Max Request Body | 5 MiB | 20 MB |
123+
| Activity Type | STOREFRONT | BUSINESS_MANAGER |
124+
125+
## Component 2: Implementation (script.js)
126+
127+
The implementation script exports functions matching `operationId` values:
128+
129+
```javascript
130+
var RESTResponseMgr = require('dw/system/RESTResponseMgr');
131+
132+
exports.getMyData = function() {
133+
// Get query parameters
134+
var myParam = request.getHttpParameterMap().get('c_my_param').getStringValue();
135+
136+
// Get path parameters (for paths like /items/{itemId})
137+
var itemId = request.getSCAPIPathParameters().get('itemId');
138+
139+
// Get request body (for POST/PUT/PATCH)
140+
var requestBody = JSON.parse(request.httpParameterMap.requestBodyAsString);
141+
142+
// Business logic here...
143+
var result = {
144+
data: 'my data',
145+
param: myParam
146+
};
147+
148+
// Return success response
149+
RESTResponseMgr.createSuccess(result).render();
150+
};
151+
exports.getMyData.public = true; // Required: mark function as public
152+
153+
// Error response example
154+
exports.getMyDataWithError = function() {
155+
RESTResponseMgr
156+
.createError(404, 'not-found', 'Resource Not Found', 'The requested resource was not found.')
157+
.render();
158+
};
159+
exports.getMyDataWithError.public = true;
160+
```
161+
162+
### Implementation Best Practices
163+
164+
- Always return JSON format responses
165+
- Use RFC 9457 error format with at least the `type` field
166+
- Mark all exported functions with `.public = true`
167+
- Handle errors gracefully to avoid circuit breaker activation
168+
- GET requests cannot commit transactions
169+
170+
### Caching Responses
171+
172+
Enable Page Caching for the site, then use:
173+
174+
```javascript
175+
// Cache for 60 seconds
176+
response.setExpires(Date.now() + 60000);
177+
178+
// Personalized caching
179+
response.setVaryBy('price_promotion');
180+
```
181+
182+
### Remote Includes
183+
184+
Include responses from other SCAPI endpoints:
185+
186+
```javascript
187+
var include = dw.system.RESTResponseMgr.createScapiRemoteInclude(
188+
'custom', 'other-api', 'v1', 'endpointPath',
189+
dw.web.URLParameter('siteId', 'MySite')
190+
);
191+
192+
var response = {
193+
data: 'my data',
194+
included: [include]
195+
};
196+
RESTResponseMgr.createSuccess(response).render();
197+
```
198+
199+
## Component 3: Mapping (api.json)
200+
201+
The mapping file binds endpoints to implementations:
202+
203+
```json
204+
{
205+
"endpoints": [
206+
{
207+
"endpoint": "getMyData",
208+
"schema": "schema.yaml",
209+
"implementation": "script"
210+
},
211+
{
212+
"endpoint": "getMyDataV2",
213+
"schema": "schema_v2.yaml",
214+
"implementation": "script_v2"
215+
}
216+
]
217+
}
218+
```
219+
220+
**Important:**
221+
- Implementation name must NOT include file extension
222+
- Schema and implementation files must be in the same folder as api.json
223+
- No relative paths allowed
224+
225+
## Endpoint Registration
226+
227+
Endpoints are registered when **activating the code version** containing the API definitions. After uploading your cartridge:
228+
229+
1. **Upload the cartridge** to your B2C instance
230+
2. **Activate the code version** to trigger registration
231+
3. **Check registration status** to verify endpoints are active
232+
233+
For Shopper APIs, the cartridge must be in the site's cartridge path. For Admin APIs, the cartridge must be in the Business Manager site's cartridge path.
234+
235+
## Circuit Breaker Protection
236+
237+
Custom APIs have a circuit breaker that blocks requests when error rate exceeds 50%:
238+
239+
1. Circuit opens after 50+ errors in 100 requests
240+
2. Requests return 503 for 60 seconds
241+
3. Circuit enters half-open state, testing next 10 requests
242+
4. If >5 fail, circuit reopens; otherwise closes
243+
244+
**Prevention:** Write robust code with error handling and avoid long-running remote calls.
245+
246+
## Troubleshooting
247+
248+
When endpoints return 404 or fail to register:
249+
250+
1. **Check registration status** using the Custom API status report
251+
2. **Review error reasons** in the status report for specific guidance
252+
3. **Verify cartridge structure:** `rest-apis/{api-name}/` contains all files
253+
4. **Check code version:** Ensure the active version contains your API
254+
5. **Verify site assignment:** Cartridge must be in site's cartridge path
255+
6. **Review logs** in Log Center with LCQL filter `CustomApiRegistry`
256+
257+
### Common Errors
258+
259+
| Error | Cause | Solution |
260+
|-------|-------|----------|
261+
| 400 Bad Request | Contract violation (unknown/invalid params) | Define all params in schema |
262+
| 401 Unauthorized | Invalid/missing token | Check token validity and header |
263+
| 403 Forbidden | Missing scope | Verify scope in token matches contract |
264+
| 404 Not Found | Endpoint not registered | Check status report, verify structure |
265+
| 500 Internal Error | Script error | Check logs for `CustomApiInvocationException` |
266+
| 503 Service Unavailable | Circuit breaker open | Fix script errors, wait for reset |
267+
268+
## Authentication Setup
269+
270+
### For Shopper APIs (ShopperToken)
271+
272+
1. Configure custom scope in SLAS Admin UI
273+
2. Obtain token via Shopper Login (SLAS)
274+
3. Include `siteId` in requests
275+
276+
### For Admin APIs (AmOAuth2)
277+
278+
1. Configure custom scope in Account Manager
279+
2. Obtain token via Account Manager OAuth
280+
3. Omit `siteId` from requests
281+
282+
### Custom API Status Report Access
283+
284+
To query the Custom API status report, use an Account Manager token with scope:
285+
- `sfcc.custom-apis` (read-only)
286+
- `sfcc.custom-apis.rw` (read-write)
287+
288+
## Development Workflow
289+
290+
1. **Create cartridge** with `rest-apis/{api-name}/` structure
291+
2. **Define contract** (schema.yaml) with endpoints and security
292+
3. **Implement logic** (script.js) with exported functions
293+
4. **Create mapping** (api.json) binding endpoints to implementation
294+
5. **Upload cartridge** to your B2C instance
295+
6. **Activate code version** to register endpoints
296+
7. **Check status** to verify registration
297+
8. **Test endpoints** with appropriate authentication
298+
9. **Monitor logs** for errors during development
299+
10. **Iterate** on implementation as needed
300+
301+
## HTTP Methods Supported
302+
303+
- GET (no transaction commits)
304+
- POST
305+
- PUT
306+
- PATCH
307+
- DELETE
308+
- HEAD
309+
- OPTIONS
310+
311+
## Limitations
312+
313+
- Maximum 50 remote includes per request
314+
- Schema attribute `additionalProperties` is not allowed
315+
- Only local `$ref` references supported in schemas (no remote/URL refs)
316+
- Custom parameters must have `c_` prefix
317+
- Custom scope names max 25 characters

0 commit comments

Comments
 (0)