# Settings (/docs/api/gateway/settings)

Account-level settings shared by every device: read with defaults, deep-merge updates, optimistic versioning.

One settings object per account (per user, not per key): what you change on the phone is what the watch, the desktop and the hub read. `GET /v1/settings` always answers the full object with defaults applied; `version` is `0` and `updatedAt` is `null` until the first write.

`PATCH /v1/settings` deep-merges a partial object into what is stored and validates the result strictly — an unknown key or a bad value is a `400`. Send the `version` you last read to make the write conditional: when someone else changed the settings meanwhile you get `409 version_conflict` with `current` (the GET shape) and nothing is written. A database outage is a `503 settings_unavailable`, never defaults presented as your settings.

| Key | Values | Default |
| --- | --- | --- |
| `transcripts.waveform` | `ring`, `bars`, `blob`, `dot`, `off` | `ring` |
| `transcripts.haptics` | `true` / `false` | `true` |
| `transcripts.liveText` | `true` / `false` | `true` |
| `transcripts.target` | `auto`, `phone`, `watch` | `auto` |
| `transcripts.language` | BCP-47 tag (at most 16 characters) or `null` for auto-detect | `null` |

The same operations are in the SDKs (`client.settings.get()` / `client.settings.update(partial, { version })` in TypeScript, `client.settings.update(partial, version=…)` in Python), the CLI (`codaid settings get`, `codaid settings set transcripts.waveform=bars`) and the MCP server (`settings_get`, `settings_update`).

<OpenAPIPage document="./openapi/en/gateway.yaml" operations={[{path: '/v1/settings',method: 'get'},{path: '/v1/settings',method: 'patch'}]} />
