> Portal Navigation:
> 
> - Append `.md` to any URL under `https://dev.wix.com/docs/` to get its markdown version.
> - Pages are either content pages (article or reference text) or menu pages (a list of links to child pages).
> - To get a menu page, truncate any URL to a parent path and append `.md` (e.g. `https://dev.wix.com/docs/sdk.md`, `https://dev.wix.com/docs/sdk/core-modules.md`).
> - Top-level index of all portals: https://dev.wix.com/docs/llms.txt
> - Full concatenated docs: https://dev.wix.com/docs/llms-full.txt

# BulkAssignCategoriesToProgram

# Package: onlinePrograms

# Namespace: CategoriesService

# Method link: https://dev.wix.com/docs/api-reference/business-management/online-programs/categories/bulk-assign-categories-to-program.md

## Permission Scopes:
Manage Online Programs: SCOPE.CHALLENGES.MANAGE

## Introduction

Assigns or unassigns Categories for a Program.

This is the recommended operation for routine Program-centric assignment changes. It updates each Category's `assignedTo` list and asynchronously synchronizes the Program's `categoryIds` list. Assignments persist across Program lifecycle states until explicitly removed.

A Program supports up to 10 assigned Categories. Including the same Category ID in both request lists fails the whole request with `CATEGORY_ASSIGNMENT_LISTS_OVERLAP` before any Category is changed. An increasing result above 10 fails with `PROGRAM_CATEGORY_LIMIT_EXCEEDED` before any Category is changed. This count check is best-effort: concurrent changes and other assignment methods can still exceed the limit.

Repeated IDs within a request list are processed once. Missing Category IDs produce per-item `CATEGORY_NOT_FOUND` failures in `results[].itemMetadata.error`; existing IDs can still succeed in the same request. Use `itemMetadata.id` to correlate results with requested IDs. Only successfully processed IDs are sent for asynchronous Program synchronization. This method does not verify that the Program exists.

If both request lists are empty, the method returns a successful no-op response. Cross-service relationship updates are eventually consistent, so an immediate read from the Programs API may briefly return the previous assignment state.

---

## REST API

### Schema

```
 Method: bulkAssignCategoriesToProgram
 Description: Assigns or unassigns Categories for a Program.  This is the recommended operation for routine Program-centric assignment changes. It updates each Category's `assignedTo` list and asynchronously synchronizes the Program's `categoryIds` list. Assignments persist across Program lifecycle states until explicitly removed.  A Program supports up to 10 assigned Categories. Including the same Category GUID in both request lists fails the whole request with `CATEGORY_ASSIGNMENT_LISTS_OVERLAP` before any Category is changed. An increasing result above 10 fails with `PROGRAM_CATEGORY_LIMIT_EXCEEDED` before any Category is changed. This count check is best-effort: concurrent changes and other assignment methods can still exceed the limit.  Repeated GUIDs within a request list are processed once. Missing Category GUIDs produce per-item `CATEGORY_NOT_FOUND` failures in `results[].itemMetadata.error`; existing GUIDs can still succeed in the same request. Use `itemMetadata.id` to correlate results with requested GUIDs. Only successfully processed GUIDs are sent for asynchronous Program synchronization. This method does not verify that the Program exists.  If both request lists are empty, the method returns a successful no-op response. Cross-service relationship updates are eventually consistent, so an immediate read from the Programs API may briefly return the previous assignment state.
 URL: https://www.wixapis.com/_api/program-categories-service/v3/categories/bulk-assign-to-program
 Method: POST
 # Note: If the parameter `a.b` is listed under required parameters, `b` is only required if `a` is also present.
 Required parameters:  programId
 Method parameters: 
   param name: categoriesToAssign | type: array<categoriesToAssign> | description: Category GUIDs to assign to the Program.  | validation: maxItems 10, format GUID
   param name: categoriesToUnassign | type: array<categoriesToUnassign> | description: Category GUIDs to unassign from the Program.  | validation: maxItems 10, format GUID
   param name: programId | type: programId | description: GUID of the Program whose Category assignments are changing. | required: true | validation: format GUID
   param name: returnEntity | type: returnEntity | description: Whether to return the updated Categories in the response.  Default: `false`.  
 Return type: BulkAssignCategoriesToProgramResponse
  - name: results | type: array<BulkAssignCategoryResult> | description: Results for the processed Categories, including per-item failures.  
     - name: action | type: Action | description: Legacy action label. Currently returns `ASSIGN_PROGRAMS` for both assignment and unassignment results.  
         - enum:
         -     UNKNOWN: Unknown action.
         -     ASSIGN_PROGRAMS: Assigns or unassigns Programs from a Category.
     - name: itemMetadata | type: ItemMetadata | description: Result metadata. Use `id` for correlation, including failures. `originalIndex` isn't a stable correlation to either request list.  
        - name: id | type: string | description: Item GUID, when available. May be absent if creation fails.  | validation: format GUID
        - name: originalIndex | type: integer | description: Index of the item within the bulk create request array. For Bulk Assign Categories to Program, correlate results by `id` instead; the index does not identify an item in either request list.  
        - name: success | type: boolean | description: Whether the requested action was successful for this item. When `false`, the `error` field is populated.  
        - name: error | type: ApplicationError | description: Details about the error in case of failure.  
           - name: code | type: string | description: Error code.  
           - name: description | type: string | description: Description of the error.  
           - name: data | type: object | description: Data related to the error.  
     - name: item | type: Category | description: Returned only when `returnEntity` is `true` in the request.  
        - name: id | type: string | description: Category GUID.  | read-only: true | validation: format GUID
        - name: revision | type: string | description: Revision number, which increments by 1 each time the Category is updated. To prevent conflicting changes, the current `revision` must be passed when updating the Category.  | read-only: true | validation: format int64
        - name: createdDate | type: string | description: Date and time the Category was created.  | read-only: true | validation: format date-time
        - name: updatedDate | type: string | description: Date and time the Category was last updated.  | read-only: true | validation: format date-time
        - name: label | type: string | description: Category's display label. The primary-language label must be unique within the site. Localized reads return the Wix Multilingual translation when one exists, and otherwise fall back to the primary label.  | validation: maxLength 100
        - name: assignedTo | type: array<string> | description: IDs of Programs assigned to this Category. For routine assignment changes, use [Bulk Assign Categories to Program](https://dev.wix.com/docs/api-reference/business-management/online-programs/categories/bulk-assign-categories-to-program.md), whose 10-Category-per-Program check is best-effort. Direct writes to `assignedTo` through Create Category, Bulk Create Categories, or Update Category bypass that check; callers using them must keep each Program at or below 10 Categories. Relationship updates are eventually consistent across the Program Categories and Programs APIs.  | validation: maxItems 200, format GUID
        - name: extendedFields | type: ExtendedFields | description: Custom field data for the Category. [Extended fields](https://dev.wix.com/docs/rest/articles/getting-started/extended-fields.md) must be configured in the app dashboard for `wix.achievements.categories.v3.category` before they can be accessed with API calls.  
           - name: namespaces | type: object | description: Extended field data. Each key corresponds to the namespace of the app that created the extended fields. The value of each key is structured according to the schema defined when the extended fields were configured.  You can only access fields for which you have the appropriate permissions.  Learn more about [extended fields](https://dev.wix.com/docs/rest/articles/getting-started/extended-fields.md).  | validation: format map
  - name: bulkActionMetadata | type: BulkActionMetadata | description: Summary of the assignment and unassignment results.  
     - name: totalSuccesses | type: integer | description: Number of items that were successfully processed.  
     - name: totalFailures | type: integer | description: Number of items that couldn't be processed.  
     - name: undetailedFailures | type: integer | description: Number of failures without details because detailed failure threshold was exceeded.  

 Possible Errors:
   HTTP Code: 400 | Status Code: INVALID_ARGUMENT | Application Code: CATEGORY_ASSIGNMENT_LISTS_OVERLAP | Description: The same Category GUID appears in both request lists. Remove the GUID from one list and retry.
   HTTP Code: 428 | Status Code: FAILED_PRECONDITION | Application Code: PROGRAM_CATEGORY_LIMIT_EXCEEDED | Description: An increase would leave more than 10 Categories assigned to this Program. Reduce the requested assignments or include Categories to unassign.


```

### Examples

### Assign and unassign program categories
Assigns one Category and unassigns another for a Program. Program synchronization is asynchronous.

```curl
curl -X POST \
'https://www.wixapis.com/online-programs/v3/categories/bulk-assign-to-program' \
-H 'Authorization: <AUTH>' \
-H 'Content-Type: application/json' \
-d '{
  "programId": "f68c8cf0-95aa-4949-984e-efe800ede364",
  "categoriesToAssign": [
    "f69516df-6a8d-4fb7-894e-5c8291c23573"
  ],
  "categoriesToUnassign": [
    "1e2d8c90-6ff8-4a03-9abe-03cc6968c7d5"
  ],
  "returnEntity": true
}'
```

---

## JavaScript SDK

### Schema

```
 Method: wixClientAdmin.onlinePrograms.categories.bulkAssignCategoriesToProgram(programId, options)
 Description: Assigns or unassigns Categories for a Program.  This is the recommended operation for routine Program-centric assignment changes. It updates each Category's `assignedTo` list and asynchronously synchronizes the Program's `categoryIds` list. Assignments persist across Program lifecycle states until explicitly removed.  A Program supports up to 10 assigned Categories. Including the same Category GUID in both request lists fails the whole request with `CATEGORY_ASSIGNMENT_LISTS_OVERLAP` before any Category is changed. An increasing result above 10 fails with `PROGRAM_CATEGORY_LIMIT_EXCEEDED` before any Category is changed. This count check is best-effort: concurrent changes and other assignment methods can still exceed the limit.  Repeated GUIDs within a request list are processed once. Missing Category GUIDs produce per-item `CATEGORY_NOT_FOUND` failures in `results[].itemMetadata.error`; existing GUIDs can still succeed in the same request. Use `itemMetadata.id` to correlate results with requested GUIDs. Only successfully processed GUIDs are sent for asynchronous Program synchronization. This method does not verify that the Program exists.  If both request lists are empty, the method returns a successful no-op response. Cross-service relationship updates are eventually consistent, so an immediate read from the Programs API may briefly return the previous assignment state.
 # Note: If the parameter `a.b` is listed under required parameters, `b` is only required if `a` is also present.
 Required parameters:  programId
 Method parameters: 
   param name: options | type: BulkAssignCategoriesToProgramOptions  none  
        - name: categoriesToAssign | type: array<string> | description: Category GUIDs to assign to the Program.  | validation: maxItems 10, format GUID
        - name: categoriesToUnassign | type: array<string> | description: Category GUIDs to unassign from the Program.  | validation: maxItems 10, format GUID
        - name: returnEntity | type: boolean | description: Whether to return the updated Categories in the response.  Default: `false`.  
   param name: programId | type: string | description: GUID of the Program whose Category assignments are changing. | required: true | validation: format GUID
 Return type: PROMISE<BulkAssignCategoriesToProgramResponse>
  - name: results | type: array<BulkAssignCategoryResult> | description: Results for the processed Categories, including per-item failures.  
     - name: action | type: Action | description: Legacy action label. Currently returns `ASSIGN_PROGRAMS` for both assignment and unassignment results.  
         - enum:
         -     UNKNOWN: Unknown action.
         -     ASSIGN_PROGRAMS: Assigns or unassigns Programs from a Category.
     - name: itemMetadata | type: ItemMetadata | description: Result metadata. Use `id` for correlation, including failures. `originalIndex` isn't a stable correlation to either request list.  
        - name: _id | type: string | description: Item GUID, when available. May be absent if creation fails.  | validation: format GUID
        - name: originalIndex | type: integer | description: Index of the item within the bulk create request array. For Bulk Assign Categories to Program, correlate results by `id` instead; the index does not identify an item in either request list.  
        - name: success | type: boolean | description: Whether the requested action was successful for this item. When `false`, the `error` field is populated.  
        - name: error | type: ApplicationError | description: Details about the error in case of failure.  
           - name: code | type: string | description: Error code.  
           - name: description | type: string | description: Description of the error.  
           - name: data | type: object | description: Data related to the error.  
     - name: item | type: Category | description: Returned only when `returnEntity` is `true` in the request.  
        - name: _id | type: string | description: Category GUID.  | read-only: true | validation: format GUID
        - name: revision | type: string | description: Revision number, which increments by 1 each time the Category is updated. To prevent conflicting changes, the current `revision` must be passed when updating the Category.  | read-only: true | validation: format int64
        - name: _createdDate | type: Date | description: Date and time the Category was created.  | read-only: true 
        - name: _updatedDate | type: Date | description: Date and time the Category was last updated.  | read-only: true 
        - name: label | type: string | description: Category's display label. The primary-language label must be unique within the site. Localized reads return the Wix Multilingual translation when one exists, and otherwise fall back to the primary label.  | validation: maxLength 100
        - name: assignedTo | type: array<string> | description: IDs of Programs assigned to this Category. For routine assignment changes, use [Bulk Assign Categories to Program](https://dev.wix.com/docs/api-reference/business-management/online-programs/categories/bulk-assign-categories-to-program.md), whose 10-Category-per-Program check is best-effort. Direct writes to `assignedTo` through Create Category, Bulk Create Categories, or Update Category bypass that check; callers using them must keep each Program at or below 10 Categories. Relationship updates are eventually consistent across the Program Categories and Programs APIs.  | validation: maxItems 200, format GUID
        - name: extendedFields | type: ExtendedFields | description: Custom field data for the Category. [Extended fields](https://dev.wix.com/docs/rest/articles/getting-started/extended-fields.md) must be configured in the app dashboard for `wix.achievements.categories.v3.category` before they can be accessed with API calls.  
           - name: namespaces | type: object | description: Extended field data. Each key corresponds to the namespace of the app that created the extended fields. The value of each key is structured according to the schema defined when the extended fields were configured.  You can only access fields for which you have the appropriate permissions.  Learn more about [extended fields](https://dev.wix.com/docs/rest/articles/getting-started/extended-fields.md).  | validation: format map
  - name: bulkActionMetadata | type: BulkActionMetadata | description: Summary of the assignment and unassignment results.  
     - name: totalSuccesses | type: integer | description: Number of items that were successfully processed.  
     - name: totalFailures | type: integer | description: Number of items that couldn't be processed.  
     - name: undetailedFailures | type: integer | description: Number of failures without details because detailed failure threshold was exceeded.  

 Possible Errors:
   HTTP Code: 400 | Status Code: INVALID_ARGUMENT | Application Code: CATEGORY_ASSIGNMENT_LISTS_OVERLAP | Description: The same Category GUID appears in both request lists. Remove the GUID from one list and retry.
   HTTP Code: 428 | Status Code: FAILED_PRECONDITION | Application Code: PROGRAM_CATEGORY_LIMIT_EXCEEDED | Description: An increase would leave more than 10 Categories assigned to this Program. Reduce the requested assignments or include Categories to unassign.


```

### Examples

### Replace a category assignment
```javascript
import { categories } from "@wix/online-programs";

async function bulkAssignCategoriesToProgramExample() {
  const result = await categories.bulkAssignCategoriesToProgram(
    "f68c8cf0-95aa-4949-984e-efe800ede364",
    {
      categoriesToAssign: ["0a4314a1-5237-4b7f-992f-d8ecdcbe73fc"],
      categoriesToUnassign: ["89f218e9-f0c9-40da-863e-2e7e042e1c2d"],
      returnEntity: true,
    },
  );
  return result;
}

/* Promise resolves to (captured response; Date values serialized as ISO strings):
{
  "results": [
    {
      "action": "ASSIGN_PROGRAMS",
      "itemMetadata": {
        "originalIndex": 0,
        "success": true,
        "_id": "0a4314a1-5237-4b7f-992f-d8ecdcbe73fc"
      },
      "item": {
        "revision": "3",
        "label": "Health and Fitness",
        "assignedTo": [
          "f68c8cf0-95aa-4949-984e-efe800ede364"
        ],
        "_id": "0a4314a1-5237-4b7f-992f-d8ecdcbe73fc",
        "_createdDate": "2026-10-15T08:16:44.427Z",
        "_updatedDate": "2026-10-15T08:28:13.425Z"
      }
    },
    {
      "action": "ASSIGN_PROGRAMS",
      "itemMetadata": {
        "originalIndex": 1,
        "success": true,
        "_id": "89f218e9-f0c9-40da-863e-2e7e042e1c2d"
      },
      "item": {
        "revision": "3",
        "label": "Nutrition",
        "assignedTo": [],
        "_id": "89f218e9-f0c9-40da-863e-2e7e042e1c2d",
        "_createdDate": "2026-10-15T08:18:25.301Z",
        "_updatedDate": "2026-10-15T08:28:13.425Z"
      }
    }
  ],
  "bulkActionMetadata": {
    "totalSuccesses": 2,
    "totalFailures": 0,
    "undetailedFailures": 0
  }
}
*/

```

### bulkAssignCategoriesToProgram (self-hosted)
Self-hosted SDK calls require you to [create a client](https://dev.wix.com/docs/sdk/articles/work-with-the-sdk/about-the-wix-client.md).

```javascript
import { createClient } from '@wix/sdk';
import { categories } from '@wix/online-programs';
// Import the auth strategy for the relevant access type
// Import the relevant host module if needed

const myWixClient = createClient ({
  modules: { categories },
  // Include the auth strategy and host as relevant
});


async function bulkAssignCategoriesToProgram(programId,options) {
  const response = await myWixClient.categories.bulkAssignCategoriesToProgram(programId,options);
};
```

---