mirror of
https://github.com/forcedotcom/afv-library.git
synced 2026-07-30 03:09:50 +08:00
feat: add segmenting-datacloud-api skill for REST API segment management
Adds a new skill covering the Data Cloud Connect REST API segments endpoints via `sf api request rest`. Complements the existing segmenting-datacloud skill (which uses the sf data360 plugin) with full endpoint schemas, request/response examples, and error codes. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
5c8e05d530
commit
36f7a19206
5
skills/segmenting-datacloud-api/CREDITS.md
Normal file
5
skills/segmenting-datacloud-api/CREDITS.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# Credits & Acknowledgments
|
||||||
|
|
||||||
|
Author: Matthew Lieber
|
||||||
|
|
||||||
|
This skill provides a REST API-first approach to Data Cloud segment management, complementing the `segmenting-datacloud` skill which uses the `sf data360` CLI plugin.
|
||||||
35
skills/segmenting-datacloud-api/README.md
Normal file
35
skills/segmenting-datacloud-api/README.md
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
# segmenting-datacloud-api
|
||||||
|
|
||||||
|
Manage Salesforce Data Cloud segments via the Connect REST API (`sf api request rest`), without requiring the `sf data360` community plugin.
|
||||||
|
|
||||||
|
## Use this skill for
|
||||||
|
|
||||||
|
- creating, updating, and deleting segments via REST API
|
||||||
|
- publishing and deactivating segments
|
||||||
|
- getting segment details and member lists
|
||||||
|
- counting segment populations
|
||||||
|
- full endpoint schema reference (request/response bodies, query params, error codes)
|
||||||
|
|
||||||
|
## Example requests
|
||||||
|
|
||||||
|
```text
|
||||||
|
"Create a Dbt segment targeting individuals who purchased in the last 30 days"
|
||||||
|
"List all active waterfall segments in my org"
|
||||||
|
"Publish segment 1sgxx00000000PpAAI"
|
||||||
|
"Get the members of my High_Value_Customers segment"
|
||||||
|
"Delete the old test segment and recreate it on accounts"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Common commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sf api request rest "/services/data/v65.0/ssot/segments" -o myorg
|
||||||
|
sf api request rest "/services/data/v65.0/ssot/segments" -X POST -H "Content-Type:application/json" -b @/tmp/segment.json -o myorg
|
||||||
|
sf api request rest "/services/data/v65.0/ssot/segments/My_Segment/actions/publish" -X POST -H "Content-Type:application/json" -b '{}' -o myorg
|
||||||
|
sf api request rest "/services/data/v65.0/ssot/segments/My_Segment/members?limit=100" -o myorg
|
||||||
|
```
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
- [SKILL.md](SKILL.md)
|
||||||
|
- [CREDITS.md](CREDITS.md)
|
||||||
341
skills/segmenting-datacloud-api/SKILL.md
Normal file
341
skills/segmenting-datacloud-api/SKILL.md
Normal file
@ -0,0 +1,341 @@
|
|||||||
|
---
|
||||||
|
name: segmenting-datacloud-api
|
||||||
|
description: "Manage Salesforce Data Cloud segments via the Connect REST API using `sf api request rest`. Use this skill when the user wants to create, list, get, update, delete, publish, deactivate, or count segments in Data Cloud — even if they say \"Data 360\", \"CDP segments\", or just \"segments\". Also use when the user asks about segment members or segment status. TRIGGER when: user manages segments via REST API, needs full endpoint schemas, or wants to bypass the sf data360 plugin. DO NOT TRIGGER when: user explicitly uses sf data360 CLI commands (use segmenting-datacloud), or the task is DMO/mapping/identity-resolution/activation work."
|
||||||
|
compatibility: "Requires an org with Data Cloud enabled and the sf CLI installed"
|
||||||
|
metadata:
|
||||||
|
version: "1.0"
|
||||||
|
---
|
||||||
|
|
||||||
|
# Data Cloud Segments — REST API via SF CLI
|
||||||
|
|
||||||
|
This skill manages Data Cloud segments through the Salesforce Connect API Segments endpoints, executed via `sf api request rest`.
|
||||||
|
|
||||||
|
## Authentication
|
||||||
|
|
||||||
|
All Segments endpoints require the **Core Salesforce token** (not the CDP token). The `sf api request rest` command handles authentication automatically using the target org.
|
||||||
|
|
||||||
|
Always include `-o <org-alias>` or rely on the default target org. The user's current default org is shown in the `sf api request rest --help` output.
|
||||||
|
|
||||||
|
## API Base Path
|
||||||
|
|
||||||
|
All endpoints live under `/services/data/v65.0/ssot/segments`. When calling `sf api request rest`, pass the full path starting with `/services/data/v65.0/`.
|
||||||
|
|
||||||
|
## Command Pattern
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# GET request (no body)
|
||||||
|
sf api request rest "/services/data/v65.0/ssot/segments" -o <org>
|
||||||
|
|
||||||
|
# POST/PATCH with inline body
|
||||||
|
sf api request rest "/services/data/v65.0/ssot/segments" -X POST \
|
||||||
|
-H "Content-Type:application/json" \
|
||||||
|
-b '{"field":"value"}' \
|
||||||
|
-o <org>
|
||||||
|
|
||||||
|
# POST/PATCH with body from file
|
||||||
|
sf api request rest "/services/data/v65.0/ssot/segments" -X POST \
|
||||||
|
-H "Content-Type:application/json" \
|
||||||
|
-b @/tmp/segment-body.json \
|
||||||
|
-o <org>
|
||||||
|
|
||||||
|
# DELETE (requires empty JSON body due to sf CLI quirk)
|
||||||
|
sf api request rest "/services/data/v65.0/ssot/segments/MySegment" -X DELETE \
|
||||||
|
-H "Content-Type:application/json" \
|
||||||
|
-b '{}' \
|
||||||
|
-o <org>
|
||||||
|
```
|
||||||
|
|
||||||
|
**Important sf CLI quirks:**
|
||||||
|
- DELETE requests require `-H "Content-Type:application/json" -b '{}'` — the CLI errors without a body.
|
||||||
|
- POST endpoints that accept no body (publish, deactivate) also need `-H "Content-Type:application/json" -b '{}'`.
|
||||||
|
- For complex JSON bodies, prefer writing to a temp file first and using `-b @/tmp/file.json` to avoid shell quoting issues.
|
||||||
|
|
||||||
|
## Operations
|
||||||
|
|
||||||
|
### 1. List Segments
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sf api request rest "/services/data/v65.0/ssot/segments?batchSize=20&offset=0" -o <org>
|
||||||
|
```
|
||||||
|
|
||||||
|
**Query parameters** (all optional):
|
||||||
|
| Parameter | Type | Description |
|
||||||
|
|-----------|------|-------------|
|
||||||
|
| `batchSize` | integer | 1-200, default 20 |
|
||||||
|
| `offset` | integer | Number of segments to skip |
|
||||||
|
| `orderby` | string | Sort field + direction, e.g. `Name ASC`, `MarketSegmentType DESC` |
|
||||||
|
| `dataspace` | string | Data space name (default data space if omitted) |
|
||||||
|
| `filters` | string | Up to 10 filters joined by AND. See Filters section below |
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"batchSize": 20,
|
||||||
|
"offset": 0,
|
||||||
|
"orderByExpression": "[Name asc]",
|
||||||
|
"segments": [ ... ],
|
||||||
|
"totalSize": 42
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Each segment object in the array contains: `apiName`, `dataSpace`, `description`, `displayName`, `lastModifiedDate`, `marketSegmentDefinitionId`, `marketSegmentId`, `publishInterval`, `segmentOnApiName`, `segmentOnId`, `segmentStatus`, `segmentType`.
|
||||||
|
|
||||||
|
#### List Filters
|
||||||
|
|
||||||
|
Filterable fields: `Name` (displayName), `SegmentStatus`, `MarketSegmentType` (segmentType), `SegmentOn` (segmentOnApiName), `LastPublishedEndDateTime`.
|
||||||
|
|
||||||
|
Operators: `eq`, `contains`, `in` (comma-separated values), `!=`.
|
||||||
|
|
||||||
|
```
|
||||||
|
filters=Name contains MySegment AND SegmentStatus eq Active
|
||||||
|
filters=MarketSegmentType in Dbt,Waterfall AND SegmentOn eq individual
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Create Segment
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sf api request rest "/services/data/v65.0/ssot/segments" -X POST \
|
||||||
|
-H "Content-Type:application/json" \
|
||||||
|
-b @/tmp/create-segment.json \
|
||||||
|
-o <org>
|
||||||
|
```
|
||||||
|
|
||||||
|
**Required fields:**
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| `description` | string | Segment description |
|
||||||
|
| `displayName` | string | Segment display name |
|
||||||
|
| `segmentOnApiName` | string | API name of the entity to segment on (e.g. `ssot__Individual__dlm`, `ssot__Account__dlm`) |
|
||||||
|
| `segmentType` | string | One of: `Dbt`, `Dynamic`, `Lookalike`, `Realtimez`, `Waterfall`. **Default to `Dbt` when the user does not specify a type.** |
|
||||||
|
|
||||||
|
**Optional fields:**
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| `developerName` | string | API name for the segment (required for POST) |
|
||||||
|
| `additionalMetadata` | object | Map of additional metadata |
|
||||||
|
| `dataSpace` | string | Data space (use `dataspace` query param in v59+) |
|
||||||
|
| `publishSchedule` | string | Enum: `NoRefresh`, `One`, `Two`, `Four`, `Six`, `Twelve`, `TwentyFour` (hours) |
|
||||||
|
| `publishScheduleStartDateTime` | string | ISO datetime for schedule start — **must be in the future** |
|
||||||
|
| `publishScheduleEndDate` | string | ISO datetime for schedule end — despite the name, use full `yyyy-MM-dd'T'HH:mm:ss.SSS'Z'` format |
|
||||||
|
| `includeDbt` | object | SQL-based segment definition for Dbt segments. Structure: `{"models": {"models": [{"name": "m1", "sql": "..."}]}}`. Note the nested `models.models` — the outer `models` is an object, the inner `models` is an array of model objects each with `name` and `sql`. The SQL SELECT must include both the primary key (`ssot__Id__c`) and the key qualifier (`KQ_Id__c`) of the segmentOn entity. See [Data Cloud SQL Reference](https://developer.salesforce.com/docs/data/data-cloud-query-guide/guide/dc-query-section.html) for query syntax |
|
||||||
|
| `lookalikeCriteria` | object | Lookalike criteria |
|
||||||
|
| `lookbackPeriod` | string | Lookback period |
|
||||||
|
|
||||||
|
**Example — create a Dbt segment (default type):**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"description": "Customers with more than 5 purchases in the last 30 days",
|
||||||
|
"displayName": "Frequent Recent Buyers",
|
||||||
|
"developerName": "Frequent_Recent_Buyers",
|
||||||
|
"segmentOnApiName": "ssot__Individual__dlm",
|
||||||
|
"segmentType": "Dbt",
|
||||||
|
"additionalMetadata": {},
|
||||||
|
"includeDbt": {
|
||||||
|
"models": {
|
||||||
|
"models": [
|
||||||
|
{
|
||||||
|
"name": "m1",
|
||||||
|
"sql": "SELECT ssot__Individual__dlm.ssot__Id__c, ssot__Individual__dlm.KQ_Id__c FROM ssot__Individual__dlm WHERE ssot__Individual__dlm.ssot__Id__c IN (SELECT IndividualId__c FROM ssot__SalesOrder__dlm WHERE CreatedDate__c >= DATEADD(day, -30, CURRENT_DATE) GROUP BY IndividualId__c HAVING COUNT(*) > 5)"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"publishSchedule": "TwentyFour",
|
||||||
|
"publishScheduleStartDateTime": "2026-04-17T00:00:00.000Z",
|
||||||
|
"publishScheduleEndDate": "2026-05-17T23:59:59.000Z"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Important notes on Dbt SQL:**
|
||||||
|
- The SQL SELECT must include both the primary key (`ssot__Id__c`) and the key qualifier (`KQ_Id__c`) of the segmentOn entity, or the API will return an `ENTITY_SAVE_ERROR`.
|
||||||
|
- The `includeDbt` structure uses nested `models.models` — the outer `models` is an object, the inner `models` is an array of model objects each with `name` (e.g. `"m1"`) and `sql`.
|
||||||
|
- The GET response flattens this to `includeDbt.models: [...]` (single-level array), but the POST body requires the nested `models.models` structure.
|
||||||
|
- The SQL must follow Data Cloud SQL syntax. See the [Data Cloud SQL Reference](https://developer.salesforce.com/docs/data/data-cloud-query-guide/guide/dc-query-section.html) for supported functions, operators, and DMO querying patterns.
|
||||||
|
|
||||||
|
**Response (200):** Returns the full segment object with `apiName`, `marketSegmentId`, `marketSegmentDefinitionId`, `segmentStatus` (typically `PROCESSING`), and all provided fields.
|
||||||
|
|
||||||
|
**Error responses:**
|
||||||
|
- 400: Invalid segment type, empty developerName/displayName, parse error
|
||||||
|
- 409: Segment already exists
|
||||||
|
|
||||||
|
### 3. Get Segment
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sf api request rest "/services/data/v65.0/ssot/segments/<segmentApiNameOrId>" -o <org>
|
||||||
|
```
|
||||||
|
|
||||||
|
Pass either the segment API name (developerName) or the segment ID.
|
||||||
|
|
||||||
|
**Response (200):**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"segments": [ { ...segment object... } ]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Update Segment
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sf api request rest "/services/data/v65.0/ssot/segments/<segmentApiName>" -X PATCH \
|
||||||
|
-H "Content-Type:application/json" \
|
||||||
|
-b @/tmp/update-segment.json \
|
||||||
|
-o <org>
|
||||||
|
```
|
||||||
|
|
||||||
|
Uses the same body schema as Create, with these differences:
|
||||||
|
- `developerName` is **not supported** for PATCH (can't rename the API name)
|
||||||
|
- `segmentType` is **not supported** for PATCH (can't change type after creation)
|
||||||
|
- `additionalMetadata` is **not supported** for PATCH
|
||||||
|
|
||||||
|
Include only the fields you want to change. The required fields (`description`, `displayName`, `segmentOnApiName`) must still be present.
|
||||||
|
|
||||||
|
**Example — update description and publish schedule:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"description": "Updated description",
|
||||||
|
"displayName": "Recent High Value Customers",
|
||||||
|
"segmentOnApiName": "ssot__Individual__dlm",
|
||||||
|
"publishSchedule": "TwentyFour"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. Delete Segment
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sf api request rest "/services/data/v65.0/ssot/segments/<segmentApiName>" -X DELETE \
|
||||||
|
-H "Content-Type:application/json" \
|
||||||
|
-b '{}' \
|
||||||
|
-o <org>
|
||||||
|
```
|
||||||
|
|
||||||
|
Returns **204 No Content** on success (empty output).
|
||||||
|
|
||||||
|
### 6. Publish Segment
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sf api request rest "/services/data/v65.0/ssot/segments/<segmentId>/actions/publish" -X POST \
|
||||||
|
-H "Content-Type:application/json" -b '{}' \
|
||||||
|
-o <org>
|
||||||
|
```
|
||||||
|
|
||||||
|
Uses the segment **ID** (not API name). No request body.
|
||||||
|
|
||||||
|
**Response (200):**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"errors": [],
|
||||||
|
"jobId": "1f8f521f-0616-4bdf-a515-d95192475c95",
|
||||||
|
"partitionId": "1sgxx00000000Pp_6157146b-...",
|
||||||
|
"publishStatus": "PUBLISHING",
|
||||||
|
"segmentId": "1sgxx00000000PpAAI",
|
||||||
|
"success": true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7. Count Segment
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sf api request rest "/services/data/v65.0/ssot/segments/<segmentApiName>/actions/count" -X POST \
|
||||||
|
-H "Content-Type:application/json" \
|
||||||
|
-b '{"preferApproxCount": true}' \
|
||||||
|
-o <org>
|
||||||
|
```
|
||||||
|
|
||||||
|
**Request body:**
|
||||||
|
| Field | Type | Required | Description |
|
||||||
|
|-------|------|----------|-------------|
|
||||||
|
| `preferApproxCount` | boolean | yes | `true` for approximate count (faster), `false` for exact |
|
||||||
|
|
||||||
|
**Response (200):**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"errors": [],
|
||||||
|
"segmentId": "1sgxx00000000MbAAI",
|
||||||
|
"success": true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 8. Deactivate Segment
|
||||||
|
|
||||||
|
By API name:
|
||||||
|
```bash
|
||||||
|
sf api request rest "/services/data/v65.0/ssot/segments/<segmentApiName>/actions/deactivate" -X POST \
|
||||||
|
-H "Content-Type:application/json" -b '{}' \
|
||||||
|
-o <org>
|
||||||
|
```
|
||||||
|
|
||||||
|
By segment ID:
|
||||||
|
```bash
|
||||||
|
sf api request rest "/services/data/v65.0/ssot/segments/<segmentId>/actions/deactivate" -X POST \
|
||||||
|
-H "Content-Type:application/json" -b '{}' \
|
||||||
|
-o <org>
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response (200):**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"errors": [],
|
||||||
|
"segmentApiName": "TestFilter",
|
||||||
|
"segmentId": "1sgxx00000000UfAAI",
|
||||||
|
"success": true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 9. Get Segment Members
|
||||||
|
|
||||||
|
**The segment must be published before you can retrieve members.** If the segment has never been published, the API will return a 404 `ITEM_NOT_FOUND` error.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sf api request rest "/services/data/v65.0/ssot/segments/<segmentApiName>/members?limit=100&offset=0" -o <org>
|
||||||
|
```
|
||||||
|
|
||||||
|
**Query parameters** (all optional):
|
||||||
|
| Parameter | Type | Description |
|
||||||
|
|-----------|------|-------------|
|
||||||
|
| `fields` | string | Comma-separated: `Id__c`, `KQ_Id__c`, `Delta_Type__c`, `Segment_Id__c`, `Parent_Segment_Id__c`, `Snapshot_Type__c`, `Timestamp__c`, `Version_Stamp__c` |
|
||||||
|
| `filters` | string | e.g. `Delta_Type__c IN ('New','Existing') AND Timestamp__c IN 2026-04-09T14:12:41.111Z` |
|
||||||
|
| `limit` | integer | 1-1000, default 100 |
|
||||||
|
| `offset` | integer | Rows to skip |
|
||||||
|
| `orderBy` | string | e.g. `Timestamp__c DESC` |
|
||||||
|
|
||||||
|
**Response (200):**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"data": [ ... ],
|
||||||
|
"endTime": "2025-04-11T15:16:10.000Z",
|
||||||
|
"filter": "Delta_Type__c in ( new , existing )",
|
||||||
|
"limit": 100,
|
||||||
|
"offSet": 0,
|
||||||
|
"orderBy": "Id__c asc",
|
||||||
|
"rowCount": 5,
|
||||||
|
"startTime": "2025-04-11T15:16:10.000Z",
|
||||||
|
"totalCount": 5
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Common Segment Entity API Names
|
||||||
|
|
||||||
|
| Entity | API Name |
|
||||||
|
|--------|----------|
|
||||||
|
| Individual | `ssot__Individual__dlm` |
|
||||||
|
| Account | `ssot__Account__dlm` |
|
||||||
|
|
||||||
|
When the user says "segment on individuals" or "segment on accounts", use these API names.
|
||||||
|
|
||||||
|
## Workflow: Create and Publish a Segment
|
||||||
|
|
||||||
|
A typical end-to-end flow:
|
||||||
|
|
||||||
|
1. **Create** the segment (POST) — returns `marketSegmentId`
|
||||||
|
2. **Get** the segment to confirm it was created and check status
|
||||||
|
3. **Publish** the segment using the `marketSegmentId` from step 1
|
||||||
|
4. **Check status** by getting the segment again — look at `segmentStatus`
|
||||||
|
5. **Count** the segment to trigger population count
|
||||||
|
6. **Get members** to see who's in the segment
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
- **401 Unauthorized**: Run `sf org login web -a <alias>` to re-authenticate
|
||||||
|
- **404 Not Found**: Check the segment API name is correct (case-sensitive)
|
||||||
|
- **400 Bad Request**: Validate required fields are present; check `segmentType` enum values
|
||||||
|
- **409 Conflict**: Segment with that `developerName` already exists
|
||||||
Loading…
Reference in New Issue
Block a user