---
title: "Update groups"
method: PATCH
path: "/v2/groups/"
tags: ["Groups"]
---

# Update groups

`PATCH /v2/groups/`

Update up to BATCH_MAX_ITEMS groups in a single request.

Each item identifies a group via ``id`` (obfuscated, required). Updatable
attributes: ``name``, ``rule_email_domains``, ``send_course_enrollment_email``,
``category_id``. At least one mutating field per item is required (enforced
by the schema).

Within-batch duplicate detection is first-wins on ``id``: the first
occurrence of an id is processed; subsequent occurrences are pre-marked
as ``duplicate_in_batch`` without reaching the service. This matches the
POST endpoint's first-wins semantics on ``name``.

A ``null`` value for ``category_id`` is meaningful — it clears the category
assignment. Distinguishing "not provided" from "explicitly null" uses
Pydantic's ``model_fields_set``.

See ``api_v2/docs/batch-responses.md`` for the envelope shape.

**Required OAuth scope:** `student-groups:write`

## Request body

- GroupUpdateRequestEnvelope — JSON:API envelope for PATCH /v2/groups/ batch update.
  - `data` GroupUpdateData[], required — List of group items to update.
    - `type` 'groups', required — Must be "groups".
    - `id` string, required — Obfuscated group resource id.
    - `attributes` GroupUpdateRequest, required — Request attributes for PATCH /v2/groups/. Updatable fields are ``name``, ``rule_email_domains``, ``send_course_enrollment_email``, and ``category_id``. All are optional individually; at least one must be provided per item. ``category_id`` may be set to ``null`` explicitly to clear the category assignment. Distinguishing "not provided" from "explicitly null" uses Pydantic's ``model_fields_set`` (see ``_GroupUpdateData``).
      - `name` string, nullable — New group name. Must remain unique within the organization (case-sensitive).
      - `rule_email_domains` string[], nullable — Replacement list of auto-add email domains. Replaces the entire array.
      - `send_course_enrollment_email` boolean, nullable — Whether to send course enrollment emails to members of this group.
      - `category_id` string, nullable — Obfuscated id of a StudentGroupCategory to assign, or ``null`` to clear the assignment. Distinguishing 'not provided' from 'explicit null' uses ``model_fields_set``.

## Response `200`

OK

- BatchResultEnvelopeGroupResource
  - `data` union[], required — Per-item results in request order.
    - union
      - BatchSucceededItemGroupResource
        - `status` 'succeeded'
        - `id` string, nullable — Resource ID of the created or updated resource.
        - `result` GroupResource, required — JSON:API resource object for a group.
          - `type` 'groups' — Always "groups".
          - `id` string, required — Opaque group ID. Use in URL paths.
          - `attributes` GroupAttributes, required — Attributes of a group resource object.
            - `name` string, required — Group name.
            - `rule_email_domains` string[], required — Email domains that auto-add students to this group on signup.
            - `send_course_enrollment_email` boolean, nullable — Whether to send course enrollment emails to members of this group.
            - `category_id` string, nullable — Obfuscated id of the assigned StudentGroupCategory, or null if no category is set.
            - `created_at` string, date-time, required — Timestamp when the group was created.
            - `updated_at` string, date-time, required — Timestamp when the group was last updated.
      - BatchFailedItem — Wrapper for a failed item in a 207 batch response.
        - `status` 'failed'
        - `id` string, nullable — Echoed resource ID if the input identified a row.
        - `error` BatchItemError, required — Per-item error inside a 207 batch response. Aligned with JSON:API ``ErrorObject`` field naming (``code`` rather than ``reason``) so consumers can reuse error-handling logic across document-level errors (``ErrorObject`` in ``ErrorEnvelope``) and per-item errors (here). Differences from ``ErrorObject``: ``status``/``title`` are omitted because they're redundant for the 207-batch context (HTTP status is on the envelope, and the title is derivable from ``code``).
          - `code` 'duplicate_email' | 'duplicate_in_batch' | 'duplicate_name' | 'validation_error' | 'not_found' | 'internal_error' | 'not_in_domain' | 'already_enrolled' | 'already_published', required — Machine-readable error code.
          - `source` object, nullable — Pointer to the offending input slot, e.g. {"pointer": "/data/0/attributes/email"}.
          - `detail` string, nullable — Human-readable explanation of the error.
  - `summary` BatchSummary, required — Aggregate counts for a 207 batch response. Invariant: ``succeeded + failed == total``. Enforced by ``@model_validator``.
    - `total` integer, required — Total number of items submitted.
    - `succeeded` integer, required — Number of items that succeeded.
    - `failed` integer, required — Number of items that failed.

## Other responses

- `207` — Multi-Status
- `400` — Bad Request
- `401` — Unauthorized
- `403` — Forbidden
- `422` — Unprocessable Entity

---

[API](https://skmtc.net/skilljar/apis/skilljar-api-v2.md) · [All operations](https://skmtc.net/skilljar/apis/skilljar-api-v2/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/skilljar/skilljar-api-v2/revisions/f8025de20169/schema)
