---
title: "Create groups"
method: POST
path: "/v2/groups/"
tags: ["Groups"]
---

# Create groups

`POST /v2/groups/`

Create up to BATCH_MAX_ITEMS groups in a single request.

Each item is processed independently — a failure on one row does not abort
the rest. Response is 200 if all items succeed, 207 if any fail, 400 if
the request envelope is empty or over the cap.

Within-batch duplicate detection is first-wins on ``name``: the first
occurrence of a name is processed; subsequent occurrences are pre-marked
as ``duplicate_in_batch`` without reaching the service.

See ``api_v2/docs/batch-responses.md`` for the 200/207/400 status
convention and per-item error code vocabulary.

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

## Request body

- GroupCreateRequestEnvelope — JSON:API envelope for POST /v2/groups/. The ``data`` field is always an array — single-create is a list of one. Cap enforcement (<= DEFAULT_BATCH_MAX_ITEMS items) lives in the endpoint, NOT here — that gives us HTTP 400 via ``ValidationError`` instead of Pydantic's 422, matching the contract established by ACCEL-358 / ACCEL-359.
  - `data` GroupCreateData[], required — List of group items to create.
    - `type` 'groups', required — Must be "groups".
    - `attributes` GroupCreateRequest, required — Request schema for creating a new group.
      - `name` string, required — Group name. Must be unique within the organization (case-sensitive).
      - `rule_email_domains` string[] — Email domains that auto-add students to this group on signup. Each entry is a bare domain (e.g. ``example.com``); duplicates are collapsed.
      - `send_course_enrollment_email` boolean, nullable — Whether to send course enrollment emails to members of this group.
      - `category_id` string, nullable — Obfuscated id of an existing StudentGroupCategory. The category must belong to the same organization or the item fails with ``not_found``.

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