AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified Apache-2.0 Self-run

B2c Custom Objects

skill-salesforcecommercecloud-b2c-developer-tooling-b2c-custom-objects · by SalesforceCommerceCloud

Store and query custom business data using CustomObjectMgr, OCAPI Data API, and Shopper Custom Objects API. Use this skill whenever the user needs to create, read, update, or search custom object instances, build processing queues with status fields, choose between site-scoped and organization-scoped storage, or query custom objects with bool/term filters. Also use when persisting non-standard da…

No reviews yet
0 installs
20 views
0.0% view→install

Install

$ agentstack add skill-salesforcecommercecloud-b2c-developer-tooling-b2c-custom-objects

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access Used
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-salesforcecommercecloud-b2c-developer-tooling-b2c-custom-objects)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
1mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of B2c Custom Objects? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

B2C Custom Objects

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.

When to Use Custom Objects

| 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 Object Types

Custom objects are defined in Business Manager under Administration > Site Development > Custom Object Types. Each type has:

  • ID: Unique identifier (e.g., CustomConfig)
  • Key Attribute: Primary key field for lookups
  • Attributes: Custom attributes for data storage
  • Scope: Site-scoped or organization-scoped (global)

Script API (CustomObjectMgr)

Getting Custom Objects

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;
}

Creating Custom Objects

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;
});

Querying Custom Objects

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();

Deleting Custom Objects

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);
    }
});

Getting All Objects of a Type

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();

CustomObjectMgr API Reference

| 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 |

OCAPI Data API

Get Custom Object

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.

Create Custom Object

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
}

Update Custom Object

PATCH /s/-/dw/data/v25_6/custom_objects/{object_type}/{key}
Authorization: Bearer {token}
Content-Type: application/json

{
    "c_configValue": "updatedValue"
}

Delete Custom Object

DELETE /s/-/dw/data/v25_6/custom_objects/{object_type}/{key}
Authorization: Bearer {token}

Search Custom Objects

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
}

Search Query Types

| 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 | {} |

Shopper Custom Objects API (SCAPI)

For read-only access from storefronts, use the Shopper Custom Objects API. This requires specific OAuth scopes.

Get Custom Object (Shopper)

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}

Required Scopes

For the Shopper Custom Objects API, configure these scopes in your SLAS client:

  • sfcc.shopper-custom-objects - Global read access to all custom object types
  • sfcc.shopper-custom-objects.{objectType} - Type-specific read access

Note: 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.

Searchable System Fields

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 value
  • key_value_integer - Integer key value
  • site_id - Site identifier (for site-scoped objects)

Best Practices

Do

  • Use transactions for create/update/delete operations
  • Close query iterators when done (objects.close())
  • Use meaningful key values for efficient lookups
  • Index frequently queried attributes
  • Use site-scoped objects for site-specific data
  • Use organization-scoped objects for shared configuration

Don't

  • Store sensitive data without encryption
  • Create excessive custom object types
  • Use custom objects for high-volume transactional data
  • Forget to handle null returns from getCustomObject()
  • Leave query iterators open (causes resource leaks)

Common Patterns

Configuration Store

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);
    });
}

Processing Queue

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();
}

Detailed References

  • [OCAPI Search Queries](references/OCAPI-SEARCH.md) - Full search query syntax and examples

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.