# Create discount site group mapping

`POST /api/configuration/discount/sitegroups`

- **Products:** Operator (`FOH`)
- **Features:** Front of House Generic Access (`FOHGENERIC`)

HTML version: [Create discount site group mapping](https://support.gladstonesoftware.cloud/reference/configuration/create-discount-site-group-mapping)

## Overview

Records which [site groups](../../guides/glossary.md) a membership discount applies to. The discounts involved are the percentage discounts held against membership types — the ones created by [Create a discount](create-a-discount.md) — and a site group is a named collection of sites. Each mapping this endpoint creates is one discount paired with one site group.

The request takes two lists and writes **every combination of them**. Three discounts and two site groups produce six mappings, not three; there is no positional pairing between the arrays.

The response is `201 Created` with a body of the form `{"discountSiteGroupMappingIds": [1, 2, 3]}` — the identifiers of the mappings just created, assigned by the system and returned in the order the combinations were built (site group outer, discount inner). You cannot choose them. The `Location` header is empty, so read them from the body.

**A pair that already exists is a `409`, and it fails the whole request.** Every combination is checked against the existing mappings before anything is saved, and the first clash is reported with `The Site Group Id {siteGroupId} already exists with a Discount Id {discountId}`. Nothing is saved when that happens, so a `409` never leaves you half-mapped — but equally, one pre-existing pair blocks all the new ones in the same call. Retrying a call that already succeeded returns `409` rather than creating duplicates. To change an existing set of mappings rather than add to it, use [Update discount site group mapping](update-discount-site-group-mapping.md); to see what is already mapped, use [Get discount site group mapping by discount ID](get-discount-site-group-mapping-by-discount-id.md).

Each pair of discount and site group can be mapped only once. Two identical requests running at the same time can both pass the duplicate check; one of them then fails with `500` rather than `409`. Serialise your configuration writes if that matters to you.

## Endpoint

`POST {base_url}/api/configuration/discount/sitegroups`

`{base_url}` is the environment URL issued to your integration. See [Authenticating with Gladstone APIs](../../guides/authenticating-with-gladstone-apis.md).

## Request body

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `discountIds` | array of integer | Yes | The membership discounts to map, given as the integer identifiers returned by [Create a discount](create-a-discount.md) and listed by [Retrieves all active discounts](retrieves-all-active-discounts-with-their-configuration-details.md). Required in practice even though it is not marked as required: an absent, null or empty array fails with `400`. The same identifier must not appear twice in the array — duplicates within the request are rejected with `400` before any lookup. Every identifier is checked against the discounts that exist, and any that do not resolve are listed back in one `400`. |
| `siteGroupIds` | array of string | Yes | The site groups to map those discounts to, given as site group identifiers of up to 15 characters — the `id` values returned by [Retrieves all site groups](retrieves-all-site-groups-with-their-configuration-details.md), or by [Create site group](create-site-group.md). Required for this endpoint: an absent, null or empty array fails with `400`. As with `discountIds`, repeating a value inside the array is rejected with `400`, and identifiers that match no site group are listed back in one `400`. Site groups are not created for you. |

## Sample request

```bash title="cURL"
curl -X POST '{base_url}/api/configuration/discount/sitegroups' \
  -H 'Authorization: Bearer {accessToken}' \
  -H 'X-Use-SSO: true' \
  -H 'Content-Type: application/json' \
  -d '{
  "discountIds": [
    12345
  ],
  "siteGroupIds": [
    "string"
  ]
}'
```

## Errors

Failures come back as a plain JSON string holding the message below, not a problem document. The exception is a malformed body, which returns a validation problem document (`application/problem+json`) with an `errors` map keyed by field name.

| Status | Meaning | When |
|--------|---------|------|
| `400` | Bad request | The body is missing, is not valid JSON, or a value is of the wrong type — for example a non-numeric entry in `discountIds`. The request is rejected before any other check runs, with a validation problem document (`application/problem+json`) whose `errors` map is keyed by field name. |
| `400` | Bad request | `discountIds` is absent, null or an empty array — `No Discount Id is provided.` |
| `400` | Bad request | `siteGroupIds` is absent, null or an empty array — `No Site Group Id is provided.` |
| `400` | Bad request | The same discount identifier appears more than once in `discountIds` — `Duplicate Discount Ids found in the request: {ids}.` |
| `400` | Bad request | The same site group identifier appears more than once in `siteGroupIds` — `Duplicate Site Group Ids found in the request: {ids}.` |
| `400` | Bad request | One or more discount identifiers do not exist. All of them are named — `Discount Ids {ids} not found.` |
| `400` | Bad request | One or more site group identifiers do not exist. All of them are named — `Site Group Ids {ids} not found.` |
| `403` | Forbidden | The request carries a member token or an anonymous token. This endpoint is not reachable with member-scoped credentials. |
| `409` | Conflict | One of the discount and site group pairs the request would produce is already mapped — `The Site Group Id {siteGroupId} already exists with a Discount Id {discountId}`. Nothing is saved, including the pairs that were new. |
| `500` | Internal server error | An unexpected server-side failure while saving, including the clash two concurrent identical requests can produce. All mappings are saved in a single operation, so a `500` while saving means no mappings were added. |
