# Configurations API

> Create, list, get, update, and delete configuration groups and their nested configuration values over the integrator API.

Configuration groups represent test-matrix axes (for example "Browser", "Operating System") and their nested configuration values are the individual cells on that axis (for example "Chrome", "Firefox"). Groups and values are project-scoped, soft-deletable, and carry server-assigned ULIDs.

## Configuration groups

### Create a group

`POST /api/v1/projects/{projectId}/configuration-groups`

`{projectId}` is the project **code** (for example `ACME`).

#### Request body

| Field  | Required | Notes                                |
| ------ | -------- | ------------------------------------ |
| `name` | yes      | Non-empty string, max 120 characters |

Client-supplied `ulid` fields are rejected.

#### Response

`201` with the created configuration group object. See [Group response fields](#group-response-fields).

Duplicate live name within the project returns `409 conflict`. Empty `name` returns `422 validation_failed`.

#### Example

```bash
curl -sS -X POST \
  -H "Authorization: Bearer $PROBARA_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"Browser"}' \
  "https://app.probara.net/api/v1/projects/ACME/configuration-groups"
```

### List groups

`GET /api/v1/projects/{projectId}/configuration-groups`

Returns the live (non-deleted) configuration groups for the project.

#### Query parameters

| Parameter  | Notes                                                            |
| ---------- | ---------------------------------------------------------------- |
| `page`     | Page number (1-based, default `1`)                               |
| `pageSize` | Items per page (default `20`)                                    |
| `include`  | Pass `values` to embed nested configuration values in each group |

#### Response

`200` with `{ items, page, pageSize, total }`. When `include=values`, each item embeds a `values` array.

#### Example

```bash
curl -sS \
  -H "Authorization: Bearer $PROBARA_API_TOKEN" \
  "https://app.probara.net/api/v1/projects/ACME/configuration-groups?include=values"
```

### Get a group

`GET /api/v1/configuration-groups/{groupUlid}`

Returns a single live configuration group scoped to the active organization. Add `?include=values` to embed the nested values.

Returns `404 not_found` when the group is outside the active organization or has been deleted.

#### Example

```bash
curl -sS \
  -H "Authorization: Bearer $PROBARA_API_TOKEN" \
  "https://app.probara.net/api/v1/configuration-groups/01JXXXXXXXXXXXXXXXXXXXXXXXXX"
```

### Update a group

`PATCH /api/v1/configuration-groups/{groupUlid}`

Partial update. At least one field must be provided; an empty body returns `422 validation_failed`.

#### Request body

| Field  | Required | Notes                                |
| ------ | -------- | ------------------------------------ |
| `name` | no       | Non-empty string, max 120 characters |

Duplicate live name within the project returns `409 conflict`. Returns `404 not_found` when the group is outside the active organization.

#### Example

```bash
curl -sS -X PATCH \
  -H "Authorization: Bearer $PROBARA_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"Web Browser"}' \
  "https://app.probara.net/api/v1/configuration-groups/01JXXXXXXXXXXXXXXXXXXXXXXXXX"
```

### Delete a group

`DELETE /api/v1/configuration-groups/{groupUlid}`

Soft-deletes the configuration group and all its nested configuration values. Returns `204` on success. Subsequent `GET` returns `404 not_found` and the group is excluded from list results.

Returns `404 not_found` when the group is outside the active organization.

#### Example

```bash
curl -sS -X DELETE \
  -H "Authorization: Bearer $PROBARA_API_TOKEN" \
  "https://app.probara.net/api/v1/configuration-groups/01JXXXXXXXXXXXXXXXXXXXXXXXXX"
```

### Group response fields

All mutating endpoints (`POST`, `PATCH`) and `GET /api/v1/configuration-groups/{groupUlid}` return a single configuration group object with the following fields.

| Field         | Type          | Notes                             |
| ------------- | ------------- | --------------------------------- |
| `ulid`        | string (ULID) | Server-assigned unique identifier |
| `projectUlid` | string (ULID) | The project this group belongs to |
| `name`        | string        | Display name                      |
| `position`    | number        | Relative sort order               |
| `createdAt`   | number        | Unix epoch milliseconds           |
| `updatedAt`   | number        | Unix epoch milliseconds           |

When `include=values` is used, each group also carries a `values` array of [configuration value objects](#value-response-fields).

---

## Configuration values

Configuration values are nested under a configuration group.

### Create a value

`POST /api/v1/configuration-groups/{groupUlid}/configurations`

#### Request body

| Field  | Required | Notes                                |
| ------ | -------- | ------------------------------------ |
| `name` | yes      | Non-empty string, max 120 characters |

Client-supplied `ulid` fields are rejected.

#### Response

`201` with the created configuration value object. See [Value response fields](#value-response-fields).

Duplicate live name within the group returns `409 conflict`. Empty `name` returns `422 validation_failed`.

#### Example

```bash
curl -sS -X POST \
  -H "Authorization: Bearer $PROBARA_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"Chrome"}' \
  "https://app.probara.net/api/v1/configuration-groups/01JXXXXXXXXXXXXXXXXXXXXXXXXX/configurations"
```

### List values

`GET /api/v1/configuration-groups/{groupUlid}/configurations`

Returns all live configuration values for the group, in position order.

#### Response

`200` with `{ items, page, pageSize, total }`.

#### Example

```bash
curl -sS \
  -H "Authorization: Bearer $PROBARA_API_TOKEN" \
  "https://app.probara.net/api/v1/configuration-groups/01JXXXXXXXXXXXXXXXXXXXXXXXXX/configurations"
```

### Update a value

`PATCH /api/v1/configurations/{configurationUlid}`

Partial update. At least one field must be provided; an empty body returns `422 validation_failed`.

#### Request body

| Field  | Required | Notes                                |
| ------ | -------- | ------------------------------------ |
| `name` | no       | Non-empty string, max 120 characters |

Duplicate live name within the group returns `409 conflict`. Returns `404 not_found` when the value is outside the active organization.

#### Example

```bash
curl -sS -X PATCH \
  -H "Authorization: Bearer $PROBARA_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"Google Chrome"}' \
  "https://app.probara.net/api/v1/configurations/01JXXXXXXXXXXXXXXXXXXXXXXXXX"
```

### Delete a value

`DELETE /api/v1/configurations/{configurationUlid}`

Soft-deletes the configuration value. Returns `204` on success. Subsequent `GET` returns `404 not_found`.

Returns `404 not_found` when the value is outside the active organization.

#### Example

```bash
curl -sS -X DELETE \
  -H "Authorization: Bearer $PROBARA_API_TOKEN" \
  "https://app.probara.net/api/v1/configurations/01JXXXXXXXXXXXXXXXXXXXXXXXXX"
```

### Value response fields

| Field         | Type          | Notes                                         |
| ------------- | ------------- | --------------------------------------------- |
| `ulid`        | string (ULID) | Server-assigned unique identifier             |
| `groupUlid`   | string (ULID) | The configuration group this value belongs to |
| `projectUlid` | string (ULID) | The project this value belongs to             |
| `name`        | string        | Display name                                  |
| `position`    | number        | Relative sort order within the group          |
| `createdAt`   | number        | Unix epoch milliseconds                       |
| `updatedAt`   | number        | Unix epoch milliseconds                       |

## Tagging a run with configurations

A run may carry a combination of configuration values — for example `Chrome` + `Windows` — set at create time or replaced later, on any run (with or without a linked test plan).

### Create with configurations

`POST /api/v1/projects/{projectId}/runs` accepts an optional `configurationUlids` array (at most 20 entries, no duplicates):

```bash
curl -sS -X POST \
  -H "Authorization: Bearer $PROBARA_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Smoke — Chrome / Windows",
    "caseUlids": ["01J...CASE"],
    "configurationUlids": ["01J...CHROME", "01J...WINDOWS"]
  }' \
  "https://app.probara.net/api/v1/projects/ACME/runs"
```

Each supplied ULID must resolve to a **live** configuration value in the run's own project; an unknown, soft-deleted, cross-project, or cross-organization ULID returns `404 not_found` and no run is created. At most one value per configuration group is allowed — two values from the same group return `422 validation_failed` with `details.code = "duplicate_group"`.

### Replace on update

`PATCH /api/v1/runs/{runUlid}` accepts the same `configurationUlids` field, applied as a **replace-set**:

- A non-empty array replaces the run's entire combination with exactly those values.
- `[]` clears every configuration from the run.
- Omitting the property leaves the run's configurations untouched.

The same resolution and one-per-group rules apply. A configuration-only `PATCH` is accepted on an **open** or a **closed non-aborted** run; an **aborted** run rejects it with `409 conflict`, exactly like every other metadata mutation.

### Response shape

Every `RunResponse` carries a `configurations` array — see [Run response shape](https://docs.probara.net/en/developers/api-reference/#run-response-shape).

## Audit events

Configuration mutations emit the following events on the organization activity feed:

- `configuration_group.created`, `configuration_group.updated`, `configuration_group.deleted`
- `configuration.created`, `configuration.updated`, `configuration.deleted`

See [Audit events](https://docs.probara.net/en/developers/api/audit-events/).
