> For the complete documentation index, see [llms.txt](https://docs.otari.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.otari.ai/otari/for-integrators/api-reference/settings.md).

# Settings

## Get Settings

> Return non-secret runtime settings for the admin dashboard.

```json
{"openapi":"3.1.0","info":{"title":"otari","version":"0.33.0"},"security":[{"ApiKeyAuth":[]},{"XApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"description":"Enter your API key here (sent as Otari-Key header).","in":"header","name":"Otari-Key","type":"apiKey"},"XApiKeyAuth":{"description":"Anthropic-native clients send credentials here (no Bearer prefix).","in":"header","name":"x-api-key","type":"apiKey"}},"schemas":{"GatewaySettings":{"description":"Operator-facing runtime settings surfaced to the dashboard.\n\nThe top-level flags are kept for the callers that read them directly\n(pricing warnings, the models/providers pages); ``config`` is the full\nread-only view with the settable/startup-only marking.","properties":{"config":{"items":{"$ref":"#/components/schemas/ConfigField"},"title":"Config","type":"array"},"default_pricing":{"title":"Default Pricing","type":"boolean"},"master_key_source":{"description":"Whether the dashboard master key is configured at startup or generated and stored by Otari.","enum":["configured","generated"],"title":"Master Key Source","type":"string"},"model_discovery":{"title":"Model Discovery","type":"boolean"},"require_pricing":{"title":"Require Pricing","type":"boolean"},"secret_key_configured":{"description":"Whether OTARI_SECRET_KEY is set on the server. Provider credentials are encrypted at rest with it, so a deployment without it can store none. The dashboard reads the same fact from the membership context's provider_key_encryption_available, because this endpoint is operator-only and the provider-key pages are read by tenants.","title":"Secret Key Configured","type":"boolean"},"version":{"title":"Version","type":"string"}},"required":["version","model_discovery","default_pricing","require_pricing","master_key_source","secret_key_configured","config"],"title":"GatewaySettings","type":"object"},"ConfigField":{"description":"One effective config value surfaced to the dashboard's config viewer.","properties":{"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"exclusive_minimum":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Exclusive Minimum"},"group":{"title":"Group","type":"string"},"key":{"title":"Key","type":"string"},"minimum":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Minimum"},"options":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Options"},"settable":{"title":"Settable","type":"boolean"},"type":{"enum":["bool","int","float","str","list"],"title":"Type","type":"string"},"value":{"anyOf":[{"type":"boolean"},{"type":"integer"},{"type":"number"},{"type":"string"},{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Value"}},"required":["key","value","type","settable","group"],"title":"ConfigField","type":"object"}}},"paths":{"/api/v1/settings":{"get":{"description":"Return non-secret runtime settings for the admin dashboard.","operationId":"settings-get_settings","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewaySettings"}}},"description":"Successful Response"}},"summary":"Get Settings","tags":["settings"]}}}}
```

## Update Settings

> Persist and apply runtime setting changes.\
> \
> Each provided field is stored as an override (winning over config/env) and\
> applied to the running gateway immediately. Operator-gated: these change\
> how the gateway meters and lists models.

```json
{"openapi":"3.1.0","info":{"title":"otari","version":"0.33.0"},"security":[{"ApiKeyAuth":[]},{"XApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"description":"Enter your API key here (sent as Otari-Key header).","in":"header","name":"Otari-Key","type":"apiKey"},"XApiKeyAuth":{"description":"Anthropic-native clients send credentials here (no Bearer prefix).","in":"header","name":"x-api-key","type":"apiKey"}},"schemas":{"UpdateSettingsRequest":{"description":"Change one or more runtime settings. Omitted fields are left unchanged.\n\nOnly the hot-changeable subset is accepted; startup-only fields are not\nsettable over the API (they are display-only in the dashboard).","properties":{"budget_estimate_default_output_tokens":{"anyOf":[{"minimum":0,"type":"integer"},{"type":"null"}],"title":"Budget Estimate Default Output Tokens"},"default_pricing":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Default Pricing"},"file_understanding_enabled":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"File Understanding Enabled"},"model_cache_ttl_seconds":{"anyOf":[{"minimum":0,"type":"integer"},{"type":"null"}],"title":"Model Cache Ttl Seconds"},"model_discovery":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Model Discovery"},"model_discovery_negative_ttl_seconds":{"anyOf":[{"minimum":0,"type":"number"},{"type":"null"}],"title":"Model Discovery Negative Ttl Seconds"},"model_discovery_timeout_seconds":{"anyOf":[{"exclusiveMinimum":0,"type":"number"},{"type":"null"}],"title":"Model Discovery Timeout Seconds"},"models_dev_cache_ttl_seconds":{"anyOf":[{"minimum":0,"type":"integer"},{"type":"null"}],"title":"Models Dev Cache Ttl Seconds"},"models_dev_metadata":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Models Dev Metadata"},"pricing_refresh":{"anyOf":[{"enum":["manual","review","auto"],"type":"string"},{"type":"null"}],"title":"Pricing Refresh"},"public_catalog":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Public Catalog"},"reject_user_mismatch":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Reject User Mismatch"},"require_pricing":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Require Pricing"},"stream_missing_usage_policy":{"anyOf":[{"enum":["estimate","fail","allow_free"],"type":"string"},{"type":"null"}],"title":"Stream Missing Usage Policy"},"vision_describe_max_tokens":{"anyOf":[{"exclusiveMinimum":0,"type":"integer"},{"type":"null"}],"title":"Vision Describe Max Tokens"},"vision_describe_model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Vision Describe Model"},"vision_strategy":{"anyOf":[{"enum":["describe","ocr","off"],"type":"string"},{"type":"null"}],"title":"Vision Strategy"}},"title":"UpdateSettingsRequest","type":"object"},"GatewaySettings":{"description":"Operator-facing runtime settings surfaced to the dashboard.\n\nThe top-level flags are kept for the callers that read them directly\n(pricing warnings, the models/providers pages); ``config`` is the full\nread-only view with the settable/startup-only marking.","properties":{"config":{"items":{"$ref":"#/components/schemas/ConfigField"},"title":"Config","type":"array"},"default_pricing":{"title":"Default Pricing","type":"boolean"},"master_key_source":{"description":"Whether the dashboard master key is configured at startup or generated and stored by Otari.","enum":["configured","generated"],"title":"Master Key Source","type":"string"},"model_discovery":{"title":"Model Discovery","type":"boolean"},"require_pricing":{"title":"Require Pricing","type":"boolean"},"secret_key_configured":{"description":"Whether OTARI_SECRET_KEY is set on the server. Provider credentials are encrypted at rest with it, so a deployment without it can store none. The dashboard reads the same fact from the membership context's provider_key_encryption_available, because this endpoint is operator-only and the provider-key pages are read by tenants.","title":"Secret Key Configured","type":"boolean"},"version":{"title":"Version","type":"string"}},"required":["version","model_discovery","default_pricing","require_pricing","master_key_source","secret_key_configured","config"],"title":"GatewaySettings","type":"object"},"ConfigField":{"description":"One effective config value surfaced to the dashboard's config viewer.","properties":{"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"exclusive_minimum":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Exclusive Minimum"},"group":{"title":"Group","type":"string"},"key":{"title":"Key","type":"string"},"minimum":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Minimum"},"options":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Options"},"settable":{"title":"Settable","type":"boolean"},"type":{"enum":["bool","int","float","str","list"],"title":"Type","type":"string"},"value":{"anyOf":[{"type":"boolean"},{"type":"integer"},{"type":"number"},{"type":"string"},{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Value"}},"required":["key","value","type","settable","group"],"title":"ConfigField","type":"object"},"HTTPValidationError":{"properties":{"code":{"const":"invalid_request","description":"Stable error code, also sent as the Otari-Error-Code header.","title":"Code","type":"string"},"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"title":"Detail","type":"array"}},"title":"HTTPValidationError","type":"object"},"ValidationError":{"properties":{"ctx":{"title":"Context","type":"object"},"input":{"title":"Input"},"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"title":"Location","type":"array"},"msg":{"title":"Message","type":"string"},"type":{"title":"Error Type","type":"string"}},"required":["loc","msg","type"],"title":"ValidationError","type":"object"}}},"paths":{"/api/v1/settings":{"patch":{"description":"Persist and apply runtime setting changes.\n\nEach provided field is stored as an override (winning over config/env) and\napplied to the running gateway immediately. Operator-gated: these change\nhow the gateway meters and lists models.","operationId":"settings-update_settings","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSettingsRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewaySettings"}}},"description":"Successful Response"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}},"description":"Validation Error"}},"summary":"Update Settings","tags":["settings"]}}}}
```

## Get Country Database

> Describe the stored country file, and say whether \`\`client\_country\_database\`\` is read instead.

```json
{"openapi":"3.1.0","info":{"title":"otari","version":"0.33.0"},"security":[{"ApiKeyAuth":[]},{"XApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"description":"Enter your API key here (sent as Otari-Key header).","in":"header","name":"Otari-Key","type":"apiKey"},"XApiKeyAuth":{"description":"Anthropic-native clients send credentials here (no Bearer prefix).","in":"header","name":"x-api-key","type":"apiKey"}},"schemas":{"CountryDatabaseStatus":{"description":"The country file a request's address is looked up in.","properties":{"client_country_database_set":{"description":"Whether `client_country_database` names a file. That file is read, and a stored one is not.","title":"Client Country Database Set","type":"boolean"},"stored":{"anyOf":[{"$ref":"#/components/schemas/StoredCountryDatabasePublic"},{"type":"null"}],"description":"The stored file, or null when none is stored."}},"required":["stored","client_country_database_set"],"title":"CountryDatabaseStatus","type":"object"},"StoredCountryDatabasePublic":{"description":"The country file stored in the database, which every replica reads.","properties":{"built_at":{"description":"When the file was built, from its metadata.","format":"date-time","title":"Built At","type":"string"},"database_type":{"description":"The type the file's metadata names, such as `GeoLite2-Country` or `DBIP-Country-Lite`.","title":"Database Type","type":"string"},"sha256":{"description":"The file's SHA-256, in hex.","title":"Sha256","type":"string"},"size_bytes":{"title":"Size Bytes","type":"integer"},"uploaded_at":{"format":"date-time","title":"Uploaded At","type":"string"}},"required":["database_type","built_at","size_bytes","sha256","uploaded_at"],"title":"StoredCountryDatabasePublic","type":"object"}}},"paths":{"/api/v1/settings/country-database":{"get":{"description":"Describe the stored country file, and say whether ``client_country_database`` is read instead.","operationId":"settings-get_country_database","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CountryDatabaseStatus"}}},"description":"Successful Response"}},"summary":"Get Country Database","tags":["settings"]}}}}
```

## Upload Country Database

> Store a country file in place of the one stored before.\
> \
> A file larger than 32 MiB answers 413, and one that is no MaxMind DB\
> country file answers 400. Either way the file stored before stays. While\
> \`\`client\_country\_database\`\` is set, the stored file is kept but not read.

```json
{"openapi":"3.1.0","info":{"title":"otari","version":"0.33.0"},"security":[{"ApiKeyAuth":[]},{"XApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"description":"Enter your API key here (sent as Otari-Key header).","in":"header","name":"Otari-Key","type":"apiKey"},"XApiKeyAuth":{"description":"Anthropic-native clients send credentials here (no Bearer prefix).","in":"header","name":"x-api-key","type":"apiKey"}},"schemas":{"CountryDatabaseStatus":{"description":"The country file a request's address is looked up in.","properties":{"client_country_database_set":{"description":"Whether `client_country_database` names a file. That file is read, and a stored one is not.","title":"Client Country Database Set","type":"boolean"},"stored":{"anyOf":[{"$ref":"#/components/schemas/StoredCountryDatabasePublic"},{"type":"null"}],"description":"The stored file, or null when none is stored."}},"required":["stored","client_country_database_set"],"title":"CountryDatabaseStatus","type":"object"},"StoredCountryDatabasePublic":{"description":"The country file stored in the database, which every replica reads.","properties":{"built_at":{"description":"When the file was built, from its metadata.","format":"date-time","title":"Built At","type":"string"},"database_type":{"description":"The type the file's metadata names, such as `GeoLite2-Country` or `DBIP-Country-Lite`.","title":"Database Type","type":"string"},"sha256":{"description":"The file's SHA-256, in hex.","title":"Sha256","type":"string"},"size_bytes":{"title":"Size Bytes","type":"integer"},"uploaded_at":{"format":"date-time","title":"Uploaded At","type":"string"}},"required":["database_type","built_at","size_bytes","sha256","uploaded_at"],"title":"StoredCountryDatabasePublic","type":"object"}}},"paths":{"/api/v1/settings/country-database":{"put":{"description":"Store a country file in place of the one stored before.\n\nA file larger than 32 MiB answers 413, and one that is no MaxMind DB\ncountry file answers 400. Either way the file stored before stays. While\n``client_country_database`` is set, the stored file is kept but not read.","operationId":"settings-upload_country_database","requestBody":{"content":{"multipart/form-data":{"schema":{"properties":{"file":{"contentMediaType":"application/octet-stream","description":"A MaxMind DB country file, such as GeoLite2 Country or DB-IP Lite Country.","type":"string"}},"required":["file"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CountryDatabaseStatus"}}},"description":"Successful Response"},"413":{"description":"The file is larger than 32 MiB."},"422":{"description":"The body holds no file in the field ``file``."}},"summary":"Upload Country Database","tags":["settings"]}}}}
```

## Delete Country Database

> Remove the stored country file.\
> \
> Answers 404 when none is stored, and 409 when it is the only country source\
> for \`\`provider\_supported\_countries\`\` or for the supported countries of an\
> enabled hosted provider.

```json
{"openapi":"3.1.0","info":{"title":"otari","version":"0.33.0"},"security":[{"ApiKeyAuth":[]},{"XApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"description":"Enter your API key here (sent as Otari-Key header).","in":"header","name":"Otari-Key","type":"apiKey"},"XApiKeyAuth":{"description":"Anthropic-native clients send credentials here (no Bearer prefix).","in":"header","name":"x-api-key","type":"apiKey"}}},"paths":{"/api/v1/settings/country-database":{"delete":{"description":"Remove the stored country file.\n\nAnswers 404 when none is stored, and 409 when it is the only country source\nfor ``provider_supported_countries`` or for the supported countries of an\nenabled hosted provider.","operationId":"settings-delete_country_database","responses":{"204":{"description":"Successful Response"}},"summary":"Delete Country Database","tags":["settings"]}}}}
```

## Get Mail Settings

> Report the effective outgoing-mail configuration.

```json
{"openapi":"3.1.0","info":{"title":"otari","version":"0.33.0"},"security":[{"ApiKeyAuth":[]},{"XApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"description":"Enter your API key here (sent as Otari-Key header).","in":"header","name":"Otari-Key","type":"apiKey"},"XApiKeyAuth":{"description":"Anthropic-native clients send credentials here (no Bearer prefix).","in":"header","name":"x-api-key","type":"apiKey"}},"schemas":{"MailSettings":{"description":"What this deployment can send, and what stands in the way if it cannot.","properties":{"enabled":{"description":"Whether a transport is configured at all.","title":"Enabled","type":"boolean"},"from_email":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The 'From' address on outgoing mail, if one is configured.","title":"From Email"},"from_name":{"description":"The 'From' display name on outgoing mail.","title":"From Name","type":"string"},"missing":{"description":"Settings that must be set before mail works, in config order. Empty exactly when 'ready' is true, so the dashboard can name what to configure rather than only reporting that mail is off.","items":{"type":"string"},"title":"Missing","type":"array"},"public_base_url":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"This deployment's own externally-reachable URL, which mail needs before it can send. The links themselves are built from ui_base_url, or from this when that is unset.","title":"Public Base Url"},"ready":{"description":"Whether a message carrying a link back to this deployment can be sent, which is what every message the control plane sends needs. Matches 'mail_ready' on /api/v1/bootstrap.","title":"Ready","type":"boolean"},"transport":{"description":"The transport a send would use: 'smtp', 'console' (logged, not delivered), or 'none'.","title":"Transport","type":"string"}},"required":["transport","enabled","ready","from_email","from_name","public_base_url","missing"],"title":"MailSettings","type":"object"}}},"paths":{"/api/v1/settings/mail":{"get":{"description":"Report the effective outgoing-mail configuration.","operationId":"settings-get_mail_settings","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailSettings"}}},"description":"Successful Response"}},"summary":"Get Mail Settings","tags":["settings"]}}}}
```

## Send Test Mail

> Send one templated test message to prove the configuration works.\
> \
> Refuses with 503 when the deployment cannot send a linked message, naming\
> the missing settings; the dashboard disables the control in that state, so\
> reaching this is a direct API call or a race with a configuration change.\
> \
> The recipient is the only caller-supplied value: the body is a fixed\
> template, so this cannot be used to put chosen text in someone's inbox from\
> the deployment's own address, and the message says outright that no account\
> was created for whoever receives it.

```json
{"openapi":"3.1.0","info":{"title":"otari","version":"0.33.0"},"security":[{"ApiKeyAuth":[]},{"XApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"description":"Enter your API key here (sent as Otari-Key header).","in":"header","name":"Otari-Key","type":"apiKey"},"XApiKeyAuth":{"description":"Anthropic-native clients send credentials here (no Bearer prefix).","in":"header","name":"x-api-key","type":"apiKey"}},"schemas":{"SendTestMailRequest":{"description":"Where to send the test message.","properties":{"to":{"description":"Recipient of the test message.","format":"email","maxLength":255,"title":"To","type":"string"}},"required":["to"],"title":"SendTestMailRequest","type":"object"},"SendTestMailResponse":{"description":"The outcome of one test send.\n\n``reason`` carries the transport's own error text, which is the whole value\nof a test button (an operator needs to know it was a refused login rather\nthan a wrong port). Safe here and only here: this endpoint is master-key\ngated, unlike the public error paths that must not leak internals.","properties":{"ok":{"title":"Ok","type":"boolean"},"reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reason"},"transport":{"title":"Transport","type":"string"}},"required":["ok","transport"],"title":"SendTestMailResponse","type":"object"},"HTTPValidationError":{"properties":{"code":{"const":"invalid_request","description":"Stable error code, also sent as the Otari-Error-Code header.","title":"Code","type":"string"},"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"title":"Detail","type":"array"}},"title":"HTTPValidationError","type":"object"},"ValidationError":{"properties":{"ctx":{"title":"Context","type":"object"},"input":{"title":"Input"},"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"title":"Location","type":"array"},"msg":{"title":"Message","type":"string"},"type":{"title":"Error Type","type":"string"}},"required":["loc","msg","type"],"title":"ValidationError","type":"object"}}},"paths":{"/api/v1/settings/mail/test":{"post":{"description":"Send one templated test message to prove the configuration works.\n\nRefuses with 503 when the deployment cannot send a linked message, naming\nthe missing settings; the dashboard disables the control in that state, so\nreaching this is a direct API call or a race with a configuration change.\n\nThe recipient is the only caller-supplied value: the body is a fixed\ntemplate, so this cannot be used to put chosen text in someone's inbox from\nthe deployment's own address, and the message says outright that no account\nwas created for whoever receives it.","operationId":"settings-send_test_mail","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendTestMailRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendTestMailResponse"}}},"description":"Successful Response"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}},"description":"Validation Error"}},"summary":"Send Test Mail","tags":["settings"]}}}}
```

## Get Maintenance Mode

> Report whether new dashboard sign-ins are frozen.

```json
{"openapi":"3.1.0","info":{"title":"otari","version":"0.33.0"},"security":[{"ApiKeyAuth":[]},{"XApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"description":"Enter your API key here (sent as Otari-Key header).","in":"header","name":"Otari-Key","type":"apiKey"},"XApiKeyAuth":{"description":"Anthropic-native clients send credentials here (no Bearer prefix).","in":"header","name":"x-api-key","type":"apiKey"}},"schemas":{"MaintenanceMode":{"description":"Whether this deployment is currently refusing new dashboard sign-ins.","properties":{"enabled":{"description":"When true, POST /api/v1/auth/session refuses every credential with 503 so nobody starts a new dashboard session during a redeploy. Sessions already issued keep working, and the management API and the data plane are unaffected: a caller presenting the master key or an API key through the header is never frozen out.","title":"Enabled","type":"boolean"}},"required":["enabled"],"title":"MaintenanceMode","type":"object"}}},"paths":{"/api/v1/settings/maintenance-mode":{"get":{"description":"Report whether new dashboard sign-ins are frozen.","operationId":"settings-get_maintenance_mode","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MaintenanceMode"}}},"description":"Successful Response"}},"summary":"Get Maintenance Mode","tags":["settings"]}}}}
```

## Update Maintenance Mode

> Freeze or unfreeze dashboard sign-ins, for this and every other replica.\
> \
> The new state is persisted and nothing is applied to the running worker,\
> because every reader goes back to the stored row. That is what makes one\
> call enough for a deployment running more than one of them.

```json
{"openapi":"3.1.0","info":{"title":"otari","version":"0.33.0"},"security":[{"ApiKeyAuth":[]},{"XApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"description":"Enter your API key here (sent as Otari-Key header).","in":"header","name":"Otari-Key","type":"apiKey"},"XApiKeyAuth":{"description":"Anthropic-native clients send credentials here (no Bearer prefix).","in":"header","name":"x-api-key","type":"apiKey"}},"schemas":{"UpdateMaintenanceModeRequest":{"description":"Turn the sign-in freeze on or off.","properties":{"enabled":{"description":"True to freeze new dashboard sign-ins, false to allow them again.","title":"Enabled","type":"boolean"}},"required":["enabled"],"title":"UpdateMaintenanceModeRequest","type":"object"},"MaintenanceMode":{"description":"Whether this deployment is currently refusing new dashboard sign-ins.","properties":{"enabled":{"description":"When true, POST /api/v1/auth/session refuses every credential with 503 so nobody starts a new dashboard session during a redeploy. Sessions already issued keep working, and the management API and the data plane are unaffected: a caller presenting the master key or an API key through the header is never frozen out.","title":"Enabled","type":"boolean"}},"required":["enabled"],"title":"MaintenanceMode","type":"object"},"HTTPValidationError":{"properties":{"code":{"const":"invalid_request","description":"Stable error code, also sent as the Otari-Error-Code header.","title":"Code","type":"string"},"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"title":"Detail","type":"array"}},"title":"HTTPValidationError","type":"object"},"ValidationError":{"properties":{"ctx":{"title":"Context","type":"object"},"input":{"title":"Input"},"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"title":"Location","type":"array"},"msg":{"title":"Message","type":"string"},"type":{"title":"Error Type","type":"string"}},"required":["loc","msg","type"],"title":"ValidationError","type":"object"}}},"paths":{"/api/v1/settings/maintenance-mode":{"patch":{"description":"Freeze or unfreeze dashboard sign-ins, for this and every other replica.\n\nThe new state is persisted and nothing is applied to the running worker,\nbecause every reader goes back to the stored row. That is what makes one\ncall enough for a deployment running more than one of them.","operationId":"settings-update_maintenance_mode","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMaintenanceModeRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MaintenanceMode"}}},"description":"Successful Response"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}},"description":"Validation Error"}},"summary":"Update Maintenance Mode","tags":["settings"]}}}}
```

## Rotate Master Key

> Regenerate the database-backed master key and invalidate the old one.\
> \
> Only the first-run generated master key can be rotated here. When a master\
> key is supplied through config or \`\`OTARI\_MASTER\_KEY\`\`, the dashboard cannot\
> invalidate it; the operator must change that value and restart instead.\
> \
> Every dashboard session is revoked with the rotation (a session only proves\
> possession of the now-dead key); the caller's own session is re-minted under\
> the new key, for the same identity it named, so the tab that performed the\
> rotation stays signed in as who it was. A caller that authenticated with a\
> header key has no session identity to re-mint for, so it is not handed one:\
> it was not signed in to the dashboard to begin with.

```json
{"openapi":"3.1.0","info":{"title":"otari","version":"0.33.0"},"security":[{"ApiKeyAuth":[]},{"XApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"description":"Enter your API key here (sent as Otari-Key header).","in":"header","name":"Otari-Key","type":"apiKey"},"XApiKeyAuth":{"description":"Anthropic-native clients send credentials here (no Bearer prefix).","in":"header","name":"x-api-key","type":"apiKey"}},"schemas":{"RotateMasterKeyResponse":{"description":"A newly generated dashboard master key, returned once.","properties":{"master_key":{"description":"The new plaintext master key. Store it now; it is never returned again.","title":"Master Key","type":"string"}},"required":["master_key"],"title":"RotateMasterKeyResponse","type":"object"}}},"paths":{"/api/v1/settings/master-key/rotate":{"post":{"description":"Regenerate the database-backed master key and invalidate the old one.\n\nOnly the first-run generated master key can be rotated here. When a master\nkey is supplied through config or ``OTARI_MASTER_KEY``, the dashboard cannot\ninvalidate it; the operator must change that value and restart instead.\n\nEvery dashboard session is revoked with the rotation (a session only proves\npossession of the now-dead key); the caller's own session is re-minted under\nthe new key, for the same identity it named, so the tab that performed the\nrotation stays signed in as who it was. A caller that authenticated with a\nheader key has no session identity to re-mint for, so it is not handed one:\nit was not signed in to the dashboard to begin with.","operationId":"settings-rotate_master_key","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RotateMasterKeyResponse"}}},"description":"Successful Response"}},"summary":"Rotate Master Key","tags":["settings"]}}}}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.otari.ai/otari/for-integrators/api-reference/settings.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
