---
title: "Creates or updates one brand's configuration. The row is created on the first save of any kind, including one that switches the feature off."
method: PUT
path: "/v1/admin/genai/config"
tags: ["GenAiConfig"]
---

# Creates or updates one brand's configuration. The row is created on the first save of any kind, including one that switches the feature off.

`PUT /v1/admin/genai/config`

Validate-then-write throughout: brand access is checked here, and the service refuses an
unhonourable trigger object or an enable with no knowledge base before anything is
persisted. The server-managed identity pointer has no property on the request DTO; a save
that switches the feature ON establishes it (once per brand, reused forever after), and any
other save preserves it.

## Request body

- UpdateGenAiConfigDto — Write DTO for the gen-ai interactive support agent configuration, posted by the admin settings card via `PUT /v1/admin/genai/config`. It mirrors Infoset.Types.Models.Admin.GenAiConfigDto minus everything the server owns: <list type="bullet"><item>`AccountId` — comes from the JWT, never from the body.</item><item>`AiBotId` — the identity pointer, written only by the bot seeder. Absent here so a client cannot re-point a brand's AI identity, and so an unrelated save preserves it instead of nulling it.</item><item>`SelectedDeskIds` — resolved from the brand's copilot row; knowledge-base scope has exactly one owner and this is not it.</item></list> The one tuning field is nullable, and null means "inherit the brand's copilot row" rather than zero. That is what lets a brand be saved without pinning today's defaults into its row forever, and — because the upsert writes it straight through — what lets an override be cleared back to inherited by posting null. `[Range]` is skipped when the value is null, so "null means inherit" and the bounds check coexist — do not add a manual null check, it would defeat exactly that.
  - `departmentId` integer — Brand this configuration targets. Mandatory and > 0: there is no account-level gen-ai row, so a payload without a brand has no valid target.
  - `enabled` boolean, required
  - `maxResponseTokens` integer, nullable
  - `idleWarningMinutes` integer, nullable — Minutes of complete silence before the agent asks the visitor whether they are still there. Null inherits the service default, like every tuning field here. The lower bound is 1 and not 0: zero would mean "warn immediately", which in a live chat is the assistant interrupting its own answer. Switching the behaviour off is not expressed as a zero here — see the remarks on Infoset.Types.Models.Admin.UpdateGenAiConfigDto.IdleCloseMinutes.
  - `idleCloseMinutes` integer, nullable — Further minutes of silence after the warning before the conversation is closed as solved. The 1440-minute (24 h) ceiling is not arbitrary: a room the agent still holds is a room no human is looking at, so an unbounded value would let conversations accumulate forever in a state where nobody is responsible for them.

## Response `204`

No Content

## Other responses

- `400` — Bad Request
- `401` — Unauthorized
- `403` — Forbidden
- `422` — Unprocessable Content

---

[API](https://skmtc.dev/infoset/apis/infoset-rest-api.md) · [All operations](https://skmtc.dev/infoset/apis/infoset-rest-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/infoset/infoset-rest-api/revisions/f5bc39a1ac15/schema)
