> ## Documentation Index
> Fetch the complete documentation index at: https://docs.joinmarkt.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Merchant groups

> Create, update, and delete product groups with a Bearer API key.

All routes require:

```txt theme={null}
Authorization: Bearer mk_live_<your_key>
```

Paths are store-scoped. The key must include the matching group scope **and** access to that shop. Dashboard permission ceilings still apply (`manageGroups`).

Groups bundle products for the storefront. They are not categories.

## List

```http theme={null}
GET /api/merchant/v1/stores/{storeId}/groups?page=1&limit=50
```

Scope: `group:read`

```json theme={null}
{
  "groups": [
    {
      "id": "clxyz...",
      "name": "Starter bundle",
      "image": null,
      "visibility": "public",
      "storeId": "cm...",
      "productCount": 2,
      "products": [],
      "createdAt": "2026-09-21T00:00:00.000Z",
      "updatedAt": "2026-09-21T00:00:00.000Z"
    }
  ],
  "page": 1,
  "limit": 50,
  "total": 1
}
```

`limit` max is 100. List rows omit member products (`products` is `[]`); use GET one for membership.

## Create

```http theme={null}
POST /api/merchant/v1/stores/{storeId}/groups
```

Scope: `group:create` · `201`

```json theme={null}
{
  "name": "Starter bundle",
  "visibility": "public",
  "image": null,
  "products": [123456]
}
```

| Field | Notes |
| - | - |
| `name` | Required, unique per shop |
| `visibility` | `public` (default), `private`, or `unlisted` |
| `image` | Optional URL |
| `products` | Optional array of numeric `productId` values in this shop |

`storeId` in the JSON body is ignored.

## Get / update / delete

```http theme={null}
GET    /api/merchant/v1/stores/{storeId}/groups/{groupId}
PATCH  /api/merchant/v1/stores/{storeId}/groups/{groupId}
PUT    /api/merchant/v1/stores/{storeId}/groups/{groupId}
DELETE /api/merchant/v1/stores/{storeId}/groups/{groupId}
```

Scopes: `group:read` · `group:update` · `group:delete`

GET includes membership:

```json theme={null}
{
  "id": "clxyz...",
  "name": "Starter bundle",
  "visibility": "public",
  "productCount": 1,
  "products": [
    { "id": "clprod...", "productId": 123456, "name": "Premium key" }
  ]
}
```

PATCH any subset of `name`, `image`, `visibility`, `products`. Omitting `products` leaves membership unchanged. Sending `products: []` unlinks every product. Sending numeric IDs replaces membership.

A group that belongs to another shop returns `404`. Unknown product IDs return `400`. Duplicate names return `400`.

DELETE unlinks products, then removes the group.

## Errors

| Status | Meaning |
| - | - |
| 400 | Invalid JSON, duplicate name, or products not in this shop |
| 401 | Missing, invalid, expired, or revoked token |
| 403 | Scope, shop, or `manageGroups` ceiling |
| 404 | Group not in this store |
| 429 | Rate limit exceeded |

## Related

* [Merchant products](/api/merchant-products)
* [Merchant categories](/api/merchant-categories)
* [API keys](/developers/api-keys)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.