From b2c
Manages custom objects in B2C Commerce using Script API and OCAPI for CRUD operations, queries, site/global data storage, and business data persistence.
npx claudepluginhub salesforcecommercecloud/b2c-developer-tooling --plugin b2cThis skill uses the workspace's default tool permissions.
Custom objects store business data that doesn't fit into standard system objects. They support both site-scoped and organization-scoped (global) data, with full CRUD operations via Script API and OCAPI.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Checks Next.js compilation errors using a running Turbopack dev server after code edits. Fixes actionable issues before reporting complete. Replaces `next build`.
Custom objects store business data that doesn't fit into standard system objects. They support both site-scoped and organization-scoped (global) data, with full CRUD operations via Script API and OCAPI.
| Use Case | Example |
|---|---|
| Business configuration | Store configuration per site or globally |
| Integration data | Cache external system responses |
| Custom entities | Loyalty tiers, custom promotions, vendor data |
| Temporary processing | Job processing queues, import staging |
Custom objects are defined in Business Manager under Administration > Site Development > Custom Object Types. Each type has:
CustomConfig)var CustomObjectMgr = require('dw/object/CustomObjectMgr');
// Get a single custom object by type and key
var config = CustomObjectMgr.getCustomObject('CustomConfig', 'myConfigKey');
if (config) {
var value = config.custom.configValue;
}
var CustomObjectMgr = require('dw/object/CustomObjectMgr');
var Transaction = require('dw/system/Transaction');
Transaction.wrap(function() {
// Create new custom object (type, keyValue)
var obj = CustomObjectMgr.createCustomObject('CustomConfig', 'newKey');
obj.custom.configValue = 'myValue';
obj.custom.isActive = true;
});
var CustomObjectMgr = require('dw/object/CustomObjectMgr');
// Query with attribute filter
var objects = CustomObjectMgr.queryCustomObjects(
'CustomConfig', // Type
'custom.isActive = {0}', // Query (uses positional params)
'creationDate desc', // Sort order
true // Parameter value for {0}
);
while (objects.hasNext()) {
var obj = objects.next();
// Process object
}
objects.close();
var CustomObjectMgr = require('dw/object/CustomObjectMgr');
var Transaction = require('dw/system/Transaction');
Transaction.wrap(function() {
var obj = CustomObjectMgr.getCustomObject('CustomConfig', 'keyToDelete');
if (obj) {
CustomObjectMgr.remove(obj);
}
});
var CustomObjectMgr = require('dw/object/CustomObjectMgr');
// Get all objects of a type
var allConfigs = CustomObjectMgr.getAllCustomObjects('CustomConfig');
while (allConfigs.hasNext()) {
var config = allConfigs.next();
// Process
}
allConfigs.close();
| Method | Description |
|---|---|
getCustomObject(type, keyValue) | Get single object by type and key |
createCustomObject(type, keyValue) | Create new object (within transaction) |
remove(object) | Delete object (within transaction) |
queryCustomObjects(type, query, sortString, ...args) | Query with filters |
getAllCustomObjects(type) | Get all objects of a type |
describe(type) | Get metadata about the custom object type |
GET /s/-/dw/data/v25_6/custom_objects/{object_type}/{key}
Authorization: Bearer {token}
Note: Use /s/{site_id}/dw/data/v25_6/custom_objects/... for site-scoped objects, or /s/-/dw/data/v25_6/custom_objects/... for organization-scoped (global) objects.
PUT /s/-/dw/data/v25_6/custom_objects/{object_type}/{key}
Authorization: Bearer {token}
Content-Type: application/json
{
"key_property": "myKey",
"c_configValue": "myValue",
"c_isActive": true
}
PATCH /s/-/dw/data/v25_6/custom_objects/{object_type}/{key}
Authorization: Bearer {token}
Content-Type: application/json
{
"c_configValue": "updatedValue"
}
DELETE /s/-/dw/data/v25_6/custom_objects/{object_type}/{key}
Authorization: Bearer {token}
POST /s/-/dw/data/v25_6/custom_object_search/{object_type}
Authorization: Bearer {token}
Content-Type: application/json
{
"query": {
"bool_query": {
"must": [
{ "term_query": { "field": "c_isActive", "value": true } }
]
}
},
"select": "(**)",
"sorts": [{ "field": "creation_date", "sort_order": "desc" }],
"start": 0,
"count": 25
}
| Query Type | Description | Example |
|---|---|---|
term_query | Exact match | {"field": "c_status", "value": "active"} |
text_query | Full-text search | {"fields": ["c_name"], "search_phrase": "test"} |
range_query | Range comparison | {"field": "c_count", "from": 1, "to": 10} |
bool_query | Combine queries | {"must": [...], "should": [...], "must_not": [...]} |
match_all_query | Match all records | {} |
For read-only access from storefronts, use the Shopper Custom Objects API. This requires specific OAuth scopes.
GET https://{shortCode}.api.commercecloud.salesforce.com/custom-object/shopper-custom-objects/v1/organizations/{organizationId}/custom-objects/{objectType}/{key}?siteId={siteId}
Authorization: Bearer {shopper_token}
For the Shopper Custom Objects API, configure these scopes in your SLAS client:
sfcc.shopper-custom-objects - Global read access to all custom object typessfcc.shopper-custom-objects.{objectType} - Type-specific read accessNote: SLAS clients can have a maximum of 20 custom object scopes.
The custom object type must also be enabled for shopper access in Business Manager.
All custom objects have these system fields available for OCAPI search queries:
creation_date - When the object was created (Date)last_modified - When the object was last modified (Date)key_value_string - String key valuekey_value_integer - Integer key valuesite_id - Site identifier (for site-scoped objects)objects.close())getCustomObject()var CustomObjectMgr = require('dw/object/CustomObjectMgr');
var Site = require('dw/system/Site');
function getConfig(key, defaultValue) {
var configKey = Site.current.ID + '_' + key;
var obj = CustomObjectMgr.getCustomObject('SiteConfig', configKey);
if (obj && obj.custom.value !== null) {
return JSON.parse(obj.custom.value);
}
return defaultValue;
}
function setConfig(key, value) {
var Transaction = require('dw/system/Transaction');
var configKey = Site.current.ID + '_' + key;
Transaction.wrap(function() {
var obj = CustomObjectMgr.getCustomObject('SiteConfig', configKey);
if (!obj) {
obj = CustomObjectMgr.createCustomObject('SiteConfig', configKey);
}
obj.custom.value = JSON.stringify(value);
});
}
var CustomObjectMgr = require('dw/object/CustomObjectMgr');
var Transaction = require('dw/system/Transaction');
// Add to queue
function enqueue(data) {
var key = 'job_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
Transaction.wrap(function() {
var obj = CustomObjectMgr.createCustomObject('JobQueue', key);
obj.custom.data = JSON.stringify(data);
obj.custom.status = 'pending';
});
}
// Process queue
function processQueue() {
var pending = CustomObjectMgr.queryCustomObjects(
'JobQueue',
'custom.status = {0}',
'creationDate asc',
'pending'
);
while (pending.hasNext()) {
var job = pending.next();
Transaction.wrap(function() {
job.custom.status = 'processing';
});
try {
var data = JSON.parse(job.custom.data);
processJob(data);
Transaction.wrap(function() {
CustomObjectMgr.remove(job);
});
} catch (e) {
Transaction.wrap(function() {
job.custom.status = 'failed';
job.custom.error = e.message;
});
}
}
pending.close();
}