---
title: "Remove visibility overrides for a group"
method: DELETE
path: "/v2/groups/{id}/relationships/published-course-visibility/"
tags: ["Groups"]
---

# Remove visibility overrides for a group

`DELETE /v2/groups/{id}/relationships/published-course-visibility/`

Remove visibility overrides for the group.

Items identify rows by ``(published_course_id, is_visible)``. Each item
is processed in its own ``transaction.atomic()`` block so a per-row
failure does not abort the rest (no outer atomic wrapping; each per-row
block opens a fresh transaction). Within-batch dedup is first-wins on
the same tuple.

Returns 404 if the group is not in the caller's organization.

The ``id`` field on ``BatchDeletedItem`` echoes the
``published_course_id`` from the request (not the override's own
obfuscated id), so clients can correlate inputs to outcomes without
keeping a separate lookup table.

The group lookup runs **before** the envelope guard so a missing group
is reported as 404 regardless of body content (consistent with the
GET / POST relationship endpoints).

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

## Path parameters

- `id` string, required

## Request body

- VisibilityOverrideRemoveRequestEnvelope — JSON:API envelope for DELETE visibility-overrides.
  - `data` VisibilityOverrideRemoveData[], required — List of visibility-override items to remove.
    - `type` 'visibility-overrides', required — Must be "visibility-overrides".
    - `attributes` VisibilityOverrideRemoveRequest, required — Request attributes for an item in DELETE visibility-overrides. Mirrors :class:`VisibilityOverrideAddRequest` — DELETE identifies a row by the same ``(published_course_id, is_visible)`` tuple that POST uses, so clients that hold a list of resources can round-trip the same attributes through DELETE.
      - `published_course_id` string, required — Obfuscated id of the PublishedCourse whose override should be removed.
      - `is_visible` boolean — True to remove an allowlist override; False to remove a blocklist override. Defaults to True to mirror POST; clients managing both allow and block rows for the same course must be explicit. See ``api_v2/docs/groups.md`` section: is_visible default on DELETE.

## Response `200`

OK

- BatchDeleteResultEnvelope — 207 Multi-Status response envelope for batch-delete operations. Distinct from ``BatchResultEnvelope`` so the generic ``T`` on the latter stays bound to a real resource type and consumers reading ``BatchSucceededItem.result`` keep their non-null contract. Items appear in the same order as the request inputs. ``summary.succeeded`` counts ``BatchDeletedItem`` rows — the field name reflects "operation did not fail" rather than the verb-specific outcome (which is on every item's own ``status`` discriminator).
  - `data` union[], required — Per-item results in request order.
    - union
      - BatchDeletedItem — Wrapper for a successfully deleted item in a 207 batch-delete response. The ``status`` discriminator is ``"deleted"`` (not ``"succeeded"``) so the outcome is explicit on every row without inspecting the rest of the object. There is no ``result`` field: the row has been removed and has no current resource representation to echo. ``id`` semantics depend on the endpoint: - **Resource-keyed deletes** (e.g. ``DELETE /v2/groups/``): the deleted resource's own obfuscated id, echoed from the request. - **Relationship sub-resource deletes** (e.g. ``DELETE /v2/groups/{id}/relationships/published-course-visibility/``): the related-resource id (here, ``published_course_id``), echoed from the request. The deleted ``PublishedCourseGroupVisibility`` row's own obfuscated id is not surfaced because clients identify these rows by the relationship tuple, not by their own id. See ``api_v2/docs/groups.md`` §"Visibility overrides (relationship sub-resource)" for the rationale on the relationship variant.
        - `status` 'deleted'
        - `id` string, required — Obfuscated id echoed from the request. For resource-keyed deletes this is the deleted resource's own id; for relationship sub-resource deletes this echoes the related-resource id (e.g. ``published_course_id``).
      - 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
- `404` — Not Found
- `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)
