---
title: "Upserts the Copilot configuration for the caller's account. DataAnnotations on Infoset.Types.Models.Admin.UpdateCopilotConfigDto are validated automatically by `[ApiController]`; invalid payloads return 400 with a structured error."
method: PUT
path: "/v1/admin/copilot/config"
tags: ["CopilotConfig"]
---

# Upserts the Copilot configuration for the caller's account. DataAnnotations on Infoset.Types.Models.Admin.UpdateCopilotConfigDto are validated automatically by \`\[ApiController\]\`; invalid payloads return 400 with a structured error.

`PUT /v1/admin/copilot/config`

Emits an `aiSettings:updated` audit log entry on success when the stored config
actually changed. No-op PUTs (incoming dto byte-equals the existing config)
do NOT produce an audit row. Mirrors the diff-then-log pattern used by
Infoset.Api.Controllers.SettingController for `mailAccount:edit`.

## Request body

- UpdateCopilotConfigDto — Write-side DTO for the AI Copilot tenant configuration (IDT-788). Posted by the admin Settings → AI page via PUT `/v1/admin/copilot/config`. Controller validates via DataAnnotations; service layer performs the upsert. Ranges: - Infoset.Types.Models.Admin.UpdateCopilotConfigDto.ModelTemperature: 0.0 (deterministic) → 1.0 (high creativity). - Infoset.Types.Models.Admin.UpdateCopilotConfigDto.MaxResponseTokens: 100 → 2000 — clamped to keep latency / cost bounded; raise the upper bound only with a product decision. - Infoset.Types.Models.Admin.UpdateCopilotConfigDto.CustomSystemPrompt: optional override appended to the base prompt. Empty string is allowed and treated as "no override".
  - `enabled` boolean, required
  - `modelTemperature` number, double, required
  - `maxResponseTokens` integer, required
  - `customSystemPrompt` string, nullable
  - `departmentId` integer — Brand (Infoset department id) this config row targets. 0 (default) = account-level row; > 0 = a department-scoped row, validated against the caller's brand access on PUT. Not a DataAnnotation range because 0 is a valid "account-level" value.
  - `selectedDeskIds` string[], nullable — Desk ids this config applies to. `null` = all desks (no restriction); empty = no desks; non-empty = the explicit desk ids. When non-null and non-empty the controller validates every id exists on the account (and, for a department-scoped row, belongs to that department) before the upsert.

## 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)
