# Asset Group API V3 — Developer Guide

- **Applies to:** Sprinklr Asset Group API V3 (`/api/v3/asset-group`)
- **V2 API reference:** [Asset Group | Sprinklr Developer Portal](https://dev.sprinklr.com/asset-group)


## 1. Overview

An **asset group** is a grouping of entities in Sprinklr. For example, an **Account Group** is a grouping of multiple accounts created either by individually selecting accounts to add (static) or based on one or more properties (dynamic). Another example is a **User Group**, which comprises multiple users at the Workspace level. The Asset Group APIs let you perform CRUD operations on these groups programmatically [doc:turn1doc4].

**Supported asset groups (V2 portal listing):** Account Groups, User Groups, Topic Groups, Workspace Groups [doc:turn1doc4].

Asset Group V3 exposes full CRUD across two paths, differentiated by HTTP method:

| Operation | Method | Path | `operationId` |
|  --- | --- | --- | --- |
| Create asset group | `POST` | `/api/v3/asset-group` | `AssetGroupApiV3_createAssetGroup` |
| Fetch asset group by id | `GET` | `/api/v3/asset-group/{groupId}` | `AssetGroupApiV3_getAssetGroup` |
| Update asset group | `PUT` | `/api/v3/asset-group/{groupId}` | `AssetGroupApiV3_updateAssetGroup` |
| Delete asset group | `DELETE` | `/api/v3/asset-group/{groupId}` | `AssetGroupApiV3_deleteAssetGroup` |


This is the central design change from V2, which used `POST /api/v2/asset-group` for creation and the same `/api/v2/asset-group/{groupId}` resource for read, update, and delete. In V3 the paths are identical in shape but sit under `/api/v3`, return the V3 response envelope, and are backed by formal request/response schemas.

### 1.1 The asset group data model

| Layer | Object / field group | What it holds |
|  --- | --- | --- |
| Identity | `id`, `name`, `description` | Group identity and label |
| Membership | `assetIds[]` | The asset identifiers that belong to the group |
| Classification | `groupType`, `assetType` | How the group is populated, and what kind of asset it contains |
| Custom data | `clientCustomFields` / `partnerCustomFields` (request), `clientCustomProperties` / `partnerCustomProperties` (response) | Client- and partner-level custom fields, each a map of key → list of string values |
| Governance | `assetPermissions[]`, `subscribers[]` | Who can act on the assets, and who is subscribed to the group |
| System | `createdTime`, `modifiedTime`, `ownerUserId`, `spaceId`, `deleted` | Server-managed metadata |


> ⚠️ **Naming asymmetry.** The request schema (`AssetGroupRequest`) uses `clientCustomFields` and `partnerCustomFields`. The response schema (`AssetGroup`) returns the same data as `clientCustomProperties` and `partnerCustomProperties`. Do not assume round-trip symmetry when mapping objects in your client code.


### 1.2 Addressing an asset group

An asset group is addressed by its Sprinklr identifier only:

- **Path parameter `groupId`** — type `String`, required, described as "Group id" in the specification. Example from the V3 create response: `6a8d7eebb1f9c0f214fd4011`.


There is no fetch-by-name, bulk-fetch, or search operation for asset groups in the V3 specification.

## 2. Base URLs and environments

All V3 API calls are sent to:

```
https://api3.sprinklr.com/{env}/api/v3
```

So the asset group resource is:

```
https://api3.sprinklr.com/{env}/api/v3/asset-group
https://api3.sprinklr.com/{env}/api/v3/asset-group/{groupId}
```

Replace `{env}` with your assigned environment identifier. The specification declares the `env` server variable with default `prod` and the following enumerated values:

`prod`, `prod0`, `prod2`, `prod3`, `prod4`, `prod5`, `prod6`, `prod8`, `prod11`, `prod12`, `prod15`, `prod16`, `prod17`, `prod18`, `prod19`, `prod21`, `prod25`

See [APIs | Sprinklr Developer Portal](https://dev.sprinklr.com/apis) for the published environment list [doc:turn1doc11].

## 3. Authentication and common headers

All Asset Group API calls are authenticated with OAuth 2.0.

| Header | Value | Purpose | Required on |
|  --- | --- | --- | --- |
| `Authorization` | `Bearer {{accessToken}}` | Credential used by the API to authenticate a user with the server. For generating the authorization token, refer to the **Authorize** section on the developer portal. | All requests |
| `Key` | `{{apiKey}}` | API key that authenticates the application with the server. For generating an API key, refer to the **Getting Started** guide. | All requests |
| `Content-Type` | `application/json` | Representation header that determines the type of data (media/resource) present in the request body | `POST`, `PUT` |
| `Accept` | `application/json` | Determines the acceptable response type from the server | All requests |


**Permissions.** `AssetGroupApiV3` was updated to **require `MANAGE` permission for create and edit**. A caller without the required permission receives `403 Forbidden`.

Sprinklr's API governance model inherits the calling user's roles and permissions: all permissions tied to a user are equally applied to that user's API key, so a `403` almost always indicates a governance gap rather than a malformed request [doc:turn1doc9].

## 4. Write operations

### 4.1 Create an asset group

**`POST /api/v3/asset-group`**

Creates an asset group. The response returns the group `id` and the other related objects.

Endpoint as documented in the V3 source document:

```
https://api3.sprinklr.com/{env}/api/v3/asset-group/
```

#### Request body — `AssetGroupRequest`

Required properties per the specification: **`name`, `groupType`, `assetType`**.

| Parameter | Sub-parameter | Required | Type | Description |
|  --- | --- | --- | --- | --- |
| `name` |  | Required | String | Name of the asset group |
| `description` |  | Optional | String | Description of the asset group |
| `clientId` |  | Required *(per V3 doc)* | Integer (`int64`) | Client id of the group — the client in which to make the changes |
| `assetIds` |  | Required *(per V3 doc)* | List[String] | Asset ids in the group |
|  | `assetIds[]` | Required | String | Unique identifier of an asset to be added to the group |
| `clientCustomFields` |  | Optional | Object (map of String → List[String]) | Client-level custom fields of the group |
| `partnerCustomFields` |  | Optional | Object (map of String → List[String]) | Partner-level custom fields of the group |
| `groupType` |  | Required | String (`GroupType`) | Type of group, for example `DEFINED`, `DYNAMIC` |
| `assetType` |  | Required | String (`AssetType`) | Type of asset in the group. Enum: `USER`, `BRAND`, `ACCOUNT`, `CLIENT` |
| `assetPermissions` |  | Optional | List[Object] (`AssetShareConfig`) | Asset permissions assigned to the group |
|  | `type` | Required | String | Type of entity receiving the permission, for example `USER`, `GLOBAL`, `CLIENT` |
|  | `ids` | Optional | List[String] | Ids based on the specified `type` |
| `subscribers` |  | Optional | List[Object] (`Subscriber`) | Subscribers of the group |
|  | `type` | Required | String | Type of subscriber, for example `USER`, `GLOBAL`, `CLIENT` |
|  | `ids` | Optional | List[String] | Ids based on the specified `type` |


> **Required-field conflict.** The OpenAPI schema marks only `name`, `groupType`, and `assetType` as required; the V3 source document marks `clientId` and `assetIds` as Required, and `assetPermissions[].ids` / `subscribers[].ids` as Required, while the schema marks the nested `ids` as optional. Treat the schema as authoritative for validation and see [§10](#10-questions-for-the-api-owner).


#### Request

```bash
curl --location 'https://api3.sprinklr.com/{env}/api/v3/asset-group/' \
--header 'Authorization: Bearer {{accessToken}}' \
--header 'Key: {{apiKey}}' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
  "name": "Santhosh Asset Group8",
  "description": "Asset Group created via V3 API",
  "clientId": 66000002,
  "assetIds": [
    "600054962"
  ],
  "groupType": "DEFINED",
  "assetType": "ACCOUNT",
  "assetPermissions": [
    {
      "type": "USER",
      "ids": [
        "600037831"
      ]
    }
  ],
  "subscribers": [
    {
      "type": "USER",
      "ids": [
        "600037831"
      ]
    }
  ]
}'
```

#### Response

```json
{
  "data": {
    "id": "6a8d7eebb1f9c0f214fd4011",
    "name": "Santhosh Asset Group8",
    "description": "Asset Group created via V3 API",
    "assetIds": [
      "600054962"
    ],
    "createdTime": 1787657963670,
    "modifiedTime": 1787657963670,
    "ownerUserId": 66015421,
    "spaceId": 66001165,
    "deleted": false,
    "groupType": "DEFINED",
    "assetType": "ACCOUNT",
    "assetPermissions": [
      {
        "type": "USER",
        "ids": [
          "600037831"
        ]
      }
    ],
    "subscribers": [
      {
        "type": "USER",
        "ids": [
          "600037831"
        ]
      }
    ]
  },
  "errors": []
}
```

#### Response parameters

| Parameter | Sub-parameter | Required | Type | Description |
|  --- | --- | --- | --- | --- |
| `data` |  | Required | Object (`AssetGroup`) | Details of the created asset group |
|  | `id` | Required | String | Unique identifier of the asset group |
|  | `name` | Required | String | Name of the asset group |
|  | `description` | Optional | String | Description of the asset group |
|  | `assetIds` | Required | List[String] | Identifiers of assets included in the asset group |
|  | `assetIds[]` | Required | String | Unique identifier of an asset included in the group |
|  | `clientCustomProperties` | Optional | Object (map of String → List[String]) | Client-level custom fields of the group |
|  | `partnerCustomProperties` | Optional | Object (map of String → List[String]) | Partner-level custom fields of the group |
|  | `createdTime` | Required | Long (epoch ms) | When the asset group was created |
|  | `modifiedTime` | Required | Long (epoch ms) | When the asset group was last modified |
|  | `ownerUserId` | Required | Long | Identifier of the user who owns the asset group |
|  | `spaceId` | Required | Long | Identifier of the space (client id) associated with the group |
|  | `deleted` | Required | Boolean | Whether the asset group has been deleted |
|  | `groupType` | Required | String | Type of asset group |
|  | `assetType` | Required | String | Type of assets contained in the group |
|  | `assetPermissions` | Optional | List[Object] | Permissions configured for the assets in the group |
|  | `assetPermissions[].type` | Required | String | Type of entity to which permissions are assigned |
|  | `assetPermissions[].ids` | Required | List[String] | Identifiers of entities granted permissions |
|  | `subscribers` | Optional | List[Object] | Subscribers associated with the asset group |
|  | `subscribers[].type` | Required | String | Type of entity subscribed to the group |
|  | `subscribers[].ids` | Required | List[String] | Identifiers of entities subscribed to the group |
| `errors` |  | Required | List[Object] | Errors encountered while processing the request. An empty array indicates no errors occurred. |


Schema-required fields on `AssetGroup` are **`id`, `name`, `assetType`**.

### 4.2 Update an asset group

**`PUT /api/v3/asset-group/{groupId}`**

Updates an existing asset group and returns the updated objects.

Endpoint as documented in the V3 source document:

```
https://api3.sprinklr.com/{env}/api/v3/asset-group/id={{assetGroupId}}
```

#### Path parameters

| Parameter | Required/Optional | Description | Type |
|  --- | --- | --- | --- |
| `groupId` | Required | Id of the group | String |


#### Request body — `AssetGroupRequest`

`PUT` takes the same `AssetGroupRequest` schema as `POST`. The V3 source document lists the following required/optional split for the update body:

| Parameter | Required/Optional | Description | Type |
|  --- | --- | --- | --- |
| `name` | Required | Name of the asset group | String |
| `description` | Required *(per V3 doc; Optional in schema)* | Description of the asset group | String |
| `clientId` | Required | The client id in which to make the changes | String *(per V3 doc; Integer `int64` in schema)* |
| `assetIds` | Required | Asset ids to be included in the group | Array of String |
| `groupType` | Required | Type of the group. Example: `DEFINED`. | String |
| `assetType` | Required | Asset type of the group. Example: `ACCOUNT`. | String |
| `assetPermissions` | Optional | Asset permissions assigned to the group | Array of Object |
| `assetPermissions[].type` | Required | Type of entity receiving the asset permission. Example: `USER`, `GLOBAL`, `CLIENT`. | String |
| `assetPermissions[].ids` | Optional | Ids based on the specified type | Array of String |
| `subscribers` | Optional | Subscribers of the asset group | Array of Object |
| `subscribers[].type` | Required | Type of subscriber. Example: `USER`, `GLOBAL`, `CLIENT`. | String |
| `subscribers[].ids` | Optional | Ids based on the specified type | Array of String |


#### Request

```bash
curl --location --request PUT 'https://api3.sprinklr.com/{env}/api/v3/asset-group/id={{assetGroupId}}' \
--header 'Authorization: Bearer {{accessToken}}' \
--header 'Key: {{apiKey}}' \
--header 'Content-Type: application/json' \
--data '{
  "name": "Santhosh Asset Group7 Updated",
  "description": "Asset Group updated via V3 API",
  "clientId": 66000002,
  "assetIds": ["600054962"],
  "groupType": "DEFINED",
  "assetType": "ACCOUNT",
  "assetPermissions": [
    {
      "type": "USER",
      "ids": ["600037831"]
    }
  ],
  "subscribers": [
    {
      "type": "USER",
      "ids": ["600037831"]
    }
  ]
}'
```

#### Response

```
204 No Content
```

#### `PUT` replaces — it does not merge

`PUT` sends the full `AssetGroupRequest` document. There is no `PATCH` operation for asset groups in V3, so **any field you omit from the body is at risk of being cleared**. Read the group with `GET` first, apply your changes to the returned object, and send the complete document back.

### 4.3 Delete an asset group

**`DELETE /api/v3/asset-group/{groupId}`**

Deletes an asset group by group id.

```
https://api3.sprinklr.com/{env}/api/v3/asset-group/{groupId}
```

#### Path parameters

| Parameter | Required/Optional | Description | Type |
|  --- | --- | --- | --- |
| `groupId` | Required | Id of the group | String |


#### Request

```bash
curl --location --request DELETE 'https://api3.sprinklr.com/{env}/api/v3/asset-group/{groupId}' \
--header 'Authorization: Bearer {{accessToken}}' \
--header 'Key: {{apiKey}}' \
--header 'Accept: application/json'
```

#### Response

```
HTTP Status: 204 No Content
```

## 5. Read operations

### 5.1 Fetch an asset group by id

**`GET /api/v3/asset-group/{groupId}`**

Fetches an asset group's details and all related objects, using the group id.

```
https://api3.sprinklr.com/{env}/api/v3/asset-group/{groupId}
```

#### Request parameters

| Parameter | Required/Optional | Description | Type |
|  --- | --- | --- | --- |
| `groupId` | Required | Unique identifier of the asset group whose details are being retrieved. *(The V3 source document names this parameter `assetGroupId` in its parameter table; the specification and URL template name it `groupId`.)* | String |


#### Request

```bash
curl --location 'https://api3.sprinklr.com/{env}/api/v3/asset-group/{groupId}' \
--header 'Authorization: Bearer {{accessToken}}' \
--header 'Key: {{apiKey}}'
```

#### Response

```json
{
  "data": [
    {
      "id": "6a8d8262b1f9c0f214fd420f",
      "name": "Santhosh Asset Group9",
      "description": "Asset Group created via V3 API",
      "assetIds": [
        "600054962"
      ],
      "createdTime": 1787658850242,
      "modifiedTime": 1787658850242,
      "ownerUserId": 66015421,
      "spaceId": 66001165,
      "deleted": false,
      "groupType": "DEFINED",
      "assetType": "ACCOUNT"
    }
  ],
  "errors": []
}
```

#### Response parameters

| Parameter | Required | Type | Description |
|  --- | --- | --- | --- |
| `data` | Required | List[Object] | List of asset groups returned by the API |
| `data[].id` | Required | String | Unique identifier of the asset group |
| `data[].name` | Required | String | Name of the asset group |
| `data[].description` | Optional | String | Description of the asset group |
| `data[].assetIds` | Required | List[String] | Identifiers of assets included in the asset group |
| `data[].assetIds[]` | Required | String | Unique identifier of an asset included in the group |
| `data[].createdTime` | Required | Long (epoch ms) | When the asset group was created |
| `data[].modifiedTime` | Required | Long (epoch ms) | When the asset group was last modified |
| `data[].ownerUserId` | Required | Long | Identifier of the user who owns the asset group |
| `data[].spaceId` | Required | Long | Identifier of the space associated with the asset group |
| `data[].deleted` | Required | Boolean | Whether the asset group has been deleted |
| `data[].groupType` | Required | String | Type of asset group |
| `data[].assetType` | Required | String | Type of assets contained in the asset group |
| `errors` | Required | List[Object] | Errors encountered while processing the request. An empty array indicates no errors occurred. |


## 6. Response format and status codes

### 6.1 The V3 envelope

Asset Group V3 responses use the standard V3 envelope:

```json
{
  "data": { },
  "errors": []
}
```

The error envelope (`ErrorResponse`) used by all `4xx` responses is:

| Field | Type | Description |
|  --- | --- | --- |
| `data` | Object, nullable | Null on error |
| `errors` | Array[Error] | One entry per error |
| `errors[].id` | String | 24-character hex ObjectId (**required**) |
| `errors[].code` | Integer | Error code (**required**) |
| `errors[].message` | String | Dotted error key, for example `account.not.found` (**required**) |
| `metadata` | Object | Response metadata |


### 6.2 Response codes

| HTTP Code | Declared by | Scenario | Description |
|  --- | --- | --- | --- |
| `200 OK` | OpenAPI spec (all four operations) | Success | `POST` and `GET` return the `AssetGroup` object; `PUT` and `DELETE` declare a `string` body |
| `204 No Content` | V3 source documents (`PUT`, `DELETE`) | Success | Operation succeeded; no response body returned |
| `400 Bad Request` | OpenAPI spec | Bad request | Malformed request or invalid parameters. Body: `ErrorResponse` |
| `401 Unauthorized` | OpenAPI spec | Missing or invalid authentication | Invalid or missing `Authorization` token or `Key`. Body: `ErrorResponse` |
| `403 Forbidden` | OpenAPI spec | Insufficient permissions | Caller lacks the required permission (`MANAGE` for create and edit). Body: `ErrorResponse` |
| `404 Not Found` | OpenAPI spec | Resource not found | No asset group exists for the supplied `groupId`. Body: `ErrorResponse` |


## 7. V2 → V3 migration

### 7.1 Endpoint mapping

| V2 | V3 |
|  --- | --- |
| `POST /api/v2/asset-group` (create) [doc:turn1doc8] | `POST /api/v3/asset-group` |
| `GET /api/v2/asset-group/{groupId}` (read) | `GET /api/v3/asset-group/{groupId}` |
| `PUT /api/v2/asset-group/{groupId}` (update) | `PUT /api/v3/asset-group/{groupId}` |
| `DELETE /api/v2/asset-group/{groupId}` (delete) | `DELETE /api/v3/asset-group/{groupId}` |


The four V2 endpoints listed above are the exact set named as the parity scope for V3.

The path shapes are unchanged. The migration work is in the **base path**, the **response envelope**, the **field names**, and the **enum surface** — not in the routing.

### 7.2 Field and behaviour mapping

| Aspect | API V2 | API V3 | Impact |
|  --- | --- | --- | --- |
| Base path | `/api/v2/asset-group` | `/api/v3/asset-group` | Update base URL only; resource paths are identical |
| Response structure | Flat asset group object at the response root [doc:turn1doc8] | `{"data": ..., "errors": []}` envelope | Access the group via `response.data`, not the root |
| Error handling | HTTP status only | Structured `errors[]` array with `id`, `code`, `message` | Parse `errors[]` for granular failure reasons |
| Custom fields on read | `clientCustomFields`, `partnerCustomFields` in the V2 response [doc:turn1doc8] | `clientCustomProperties`, `partnerCustomProperties` in the V3 `AssetGroup` response | Rename on the read path. Request-side names (`clientCustomFields`, `partnerCustomFields`) are unchanged. |
| Client id on read | V2 response example includes `clientId` [doc:turn1doc8] | V3 `AssetGroup` exposes `spaceId` (described as "Client id of the group"); `clientId` remains a **request** field | Map `spaceId` → your V2 `clientId` consumer |
| `assetType` enum | `USER`, `BRAND`, `ACCOUNT`, `CLIENT`, `BENCHMARKING_ACCOUNT` [doc:turn1doc8] | `USER`, `BRAND`, `ACCOUNT`, `CLIENT` | **`BENCHMARKING_ACCOUNT` is not in the V3 enum.** Audit existing groups before cutover — see [§10](#10-questions-for-the-api-owner). |
| `groupType` | Documented as "Type of the group (Static/Dynamic)" [doc:turn1doc8]; V2 example uses `DYNAMIC` | Free-form string; spec description "Type of group e.g. DEFINED, DYNAMIC"; V3 examples use `DEFINED` | Not a closed enum in V3. Verify accepted values with the API owner. |
| `description` | Required [doc:turn1doc8] | Optional in the `AssetGroupRequest` schema | Existing payloads remain valid |
| Required request fields | `name`, `description`, `clientId`, `assetId`, `groupType`, `assetType` [doc:turn1doc8] | `name`, `groupType`, `assetType` (schema) | Fewer schema-mandated fields; see the conflict note in [§4.1](#41-create-an-asset-group) |
| Permissions | Governed by the calling user's roles [doc:turn1doc9] | Create and edit explicitly require `MANAGE` | A key that worked on V2 writes may return `403` on V3 |
| Success status on `PUT`/`DELETE` | Not specified in the V2 reference | `204 No Content` observed; `200` declared in the spec | Accept both |


### 7.3 Migration steps

1. **Update the base URL.** Point at `https://api3.sprinklr.com/{env}/api/v3/asset-group`.
2. **Unwrap the envelope.** Read the group from `response.data` instead of the response root, and tolerate `data` being an object (`POST`) or a single-element array (`GET`).
3. **Handle the new error format.** Inspect `response.errors[]` and log `errors[].code` and `errors[].message`.
4. **Rename read-side custom fields.** `clientCustomFields` → `clientCustomProperties`, `partnerCustomFields` → `partnerCustomProperties`. Leave the request-side names as-is.
5. **Remap `clientId` on read** to `spaceId`.
6. **Audit `assetType` values.** Any integration that sends or expects `BENCHMARKING_ACCOUNT` must be resolved before cutover.
7. **Confirm `groupType` values.** V2 documentation says Static/Dynamic; V2 examples use `DYNAMIC`; V3 examples use `DEFINED`.
8. **Grant `MANAGE` permission** to the API user used for create and update calls.
9. **Accept both `200` and `204`** as success on `PUT` and `DELETE`, and do not assume a JSON body.
10. **Read-modify-write on updates.** V3 has no `PATCH`; send the complete document on every `PUT`.


## 8. Reference — enums and reusable objects

### 8.1 `AssetType`

| Value | Notes |
|  --- | --- |
| `USER` | User assets |
| `BRAND` | Brand assets |
| `ACCOUNT` | Account assets — used in all V3 examples |
| `CLIENT` | Client assets |


`BENCHMARKING_ACCOUNT`, present in the V2 documentation [doc:turn1doc8], is **not** part of the V3 `AssetType` enum.

### 8.2 `GroupType`

Typed as a plain `string` in the specification, described as "Type of Group" (request-side description: "Type of group e.g. DEFINED, DYNAMIC"). It is **not** a closed enum in V3. Values seen in documented examples: `DEFINED` (V3), `DYNAMIC` (V2).

### 8.3 `AssetShareConfig` (used by `assetPermissions[]`)

| Field | Required | Type | Description |
|  --- | --- | --- | --- |
| `type` | Required | String | Type, for example `USER`, `GLOBAL`, `CLIENT` |
| `ids` | Optional | List[String] | Ids based on `type` |


### 8.4 `Subscriber` (used by `subscribers[]`)

| Field | Required | Type | Description |
|  --- | --- | --- | --- |
| `type` | Required | String | Type, for example `USER`, `GLOBAL`, `CLIENT` |
| `ids` | Optional | List[String] | Ids based on `type` |


Both objects are structurally identical but are separate components in the specification. There is also an unrelated `AssetPermission` component (holding `shareConfigs[]` and `grants[]`) that is **not** referenced by any asset group operation — do not confuse it with the `assetPermissions` array on `AssetGroup`/`AssetGroupRequest`.

## 9. Use cases and best practices

### 9.1 Create an account group for a campaign

`POST /api/v3/asset-group` with `assetType: "ACCOUNT"`, `groupType: "DEFINED"`, and the account ids in `assetIds[]`. Grant access at creation time via `assetPermissions[]` and notify owners via `subscribers[]`.

### 9.2 Add an asset to an existing group

There is no incremental-add operation. Call `GET /api/v3/asset-group/{groupId}`, append the new id to `assetIds[]` from the returned object, and send the complete document back with `PUT`.

### 9.3 Reconcile groups from an external system of record

Where your external system is authoritative, `PUT` is the correct verb — it replaces the whole document, so removals in the source system propagate. Where it is not authoritative, always read first.

### 9.4 Decommission a group

`DELETE /api/v3/asset-group/{groupId}`. Expect `204 No Content` (or `200` per the spec) and no body — do not attempt to parse the response as JSON.

### Best practices

**Identifiers**

- `groupId` is a String (24-character hex ObjectId in all documented examples, for example `6a8d8262b1f9c0f214fd420f`). Do not coerce it to a number.
- `assetIds[]`, `assetPermissions[].ids[]`, and `subscribers[].ids[]` are **arrays of strings**, even when the underlying ids are numeric (`"600054962"`).
- `clientId` on the request is an **integer** (`int64`, for example `66000002`), while the corresponding response field `spaceId` is also a Long. The V3 update document describes `clientId` as String — the schema types it as an integer.


**Updates**

- V3 has no `PATCH` for asset groups. Every update is a full replace.
- Do not rely on the `?id=` query parameter shown in the update document; the specification defines only the path parameter.


**Enums and casing**

- `assetType` values are uppercase and case-sensitive: `USER`, `BRAND`, `ACCOUNT`, `CLIENT`.
- `type` values inside `assetPermissions[]` and `subscribers[]` are documented as `USER`, `GLOBAL`, `CLIENT`.


**Timestamps**

- `createdTime` and `modifiedTime` are epoch milliseconds as 64-bit integers (for example `1787657963670`). Do not parse them as seconds.


**Permissions**

- Provision `MANAGE` for the API user before migrating write traffic; a `403` on V3 where V2 succeeded is the expected symptom of a missing grant.


**Error handling**

- Always inspect the `errors` array even on a `2xx` response — the envelope carries `errors` on success responses too (empty in the documented examples).


**Credentials**

- All tokens and keys in this guide are placeholders (`{{accessToken}}`, `{{apiKey}}`). Never commit or log real keys.