Studio API
Auto-generated from the OpenAPI spec. Run
node docs-site/scripts/fetch-openapi.jsto regenerate.
GET /api/v1/studio/branding
Get Studio Branding
Responses
- 200 — Successful Response
GET /api/v1/studio/error-reporting
Get Error Reporting
The studio's error-monitoring consent, plus whether toggling it would
have any effect on this install (available). Manager-only.
Responses
- 200 — Successful Response
PUT /api/v1/studio/error-reporting
Update Error Reporting
Opt in to / out of error monitoring for this install. Takes effect immediately (no restart): enabling initialises the SDK, disabling closes it. Manager-only.
Request body
| Field | Required | Type | Description |
|---|---|---|---|
enabled | Yes | boolean |
Responses
- 200 — Successful Response
- 422 — Validation Error
GET /api/v1/studio
Get Studio Settings
Responses
- 200 — Successful Response
PUT /api/v1/studio
Update Studio Settings
Request body
| Field | Required | Type | Description |
|---|---|---|---|
studio_name | No | string | |
address | No | string | |
country | No | string | |
tax_id | No | string | |
default_vat_rate | No | number | |
timezone | No | string | |
cancellation_hours | No | integer | |
cancellation_deducts_credit | No | boolean | |
late_cancel_fee | No | number | |
no_show_fee | No | number | |
checkin_open_minutes_before | No | integer | |
checkin_close_minutes_after | No | integer | |
waitlist_confirm_minutes | No | integer | |
guest_bookings_enabled | No | boolean | |
self_service_purchases_enabled | No | boolean | |
reminder_hours_before | No | integer | |
calendar_start_hour | No | integer | |
calendar_end_hour | No | integer | |
primary_color | No | string | |
secondary_color | No | string | |
tunnel_url | No | string |
Responses
- 200 — Successful Response
- 422 — Validation Error
GET /api/v1/studio/status
Get Studio Status
Responses
- 200 — Successful Response
POST /api/v1/studio/backup
Trigger Backup
Take an on-demand SQLite snapshot of the studio database into
app_data_dir()/backups/ — the same artifact the nightly backup job
produces (app/tasks/nightly_backup.py).
Called by the desktop auto-updater before it applies an update, and
available as a manual "back up now" action in the Settings UI. Manager-only.
Prunes the backups directory to the newest 30 files and records
StudioSettings.last_backup_at.
Responses
- 200 — Successful Response
POST /api/v1/studio/reset
Reset Studio
Wipe all studio data and return to the setup wizard (PRODUCT_SPEC.md §3.4 "Danger Zone", TECHNICAL_SPEC.md §6.2).
Full-access manager only — gated by require_manager (checks
user.role.is_full_access, the same underlying flag is_full_access_staff
reads for the other "superpower" gates in this codebase, e.g. retroactive
bookings in bookings.py/appointments.py) — never any other staff role.
require_manager is used directly rather than is_full_access_staff here
because this endpoint is manager-only from the door (unlike those mixed
staff/client endpoints, which authenticate broadly and only use
is_full_access_staff as an in-body conditional); every other
manager-only endpoint in this router (PUT /studio, POST /studio/backup,
POST /studio/ai) uses the same require_manager dependency.
Re-authentication friction, both required:
current_passwordmust match the caller's ownpassword_hash(not any other manager's, if this codebase ever supports more than one full-access account) — 401 AUTH_INVALID_CREDENTIALS on mismatch, withburn_password_check()on the no-match path for timing consistency with login (SECURITY_GUIDELINES.md §1.3).confirm_studio_namemust exactly matchStudioSettings.studio_name— 400 STUDIO_NAME_MISMATCH otherwise (including when no StudioSettings row exists at all, which can't be confirmed against anything).
On success: takes an on-demand backup (app/backup.py's perform_backup
— the same function/artifact the nightly job and POST /studio/backup
use) BEFORE wiping anything. If the backup itself fails, the reset is
aborted with 500 BACKUP_FAILED and nothing is wiped — a mistaken reset
must stay recoverable, so this never silently wipes without a fresh
backup to fall back on. The wipe itself (app/services/ studio_reset_service.wipe_studio_data) deletes every table's rows in
FK-safe order (never DROP, never touches alembic_version) including
studio_settings itself, so needs_setup (see GET /studio/branding)
evaluates true again on the next load — exactly the fresh-install state.
db.commit() happens here, once, covering both the backup's own
last_backup_at write and the wipe — perform_backup commits
internally (see its docstring) and wipe_studio_data never does (per
backend/CLAUDE.md's transaction-semantics rule for app/services/).
Request body
| Field | Required | Type | Description |
|---|---|---|---|
current_password | Yes | string | |
confirm_studio_name | Yes | string |
Responses
- 200 — Successful Response
- 422 — Validation Error
AI Assistant configuration
The AI Assistant runs only on the studio's own AI provider key (a key saved with
POST /studio/ai below, or an LLM_API_KEY in the backend's environment) or on a local keyless
model (Ollama, via an ollama/ or ollama_chat/ LLM_MODEL). There is no hosted fallback: no
prompt or studio data passes through infrastructure run by Agon's developer. With none of these
configured, POST /agent/act and POST /support/chat answer in basic
mode (mode: "basic"): a keyword documentation search with no LLM and no network call.
All /studio/ai* endpoints are manager-only (require_manager). There is no license
check. User guide: How to set up the AI Assistant.
GET /api/v1/studio/ai/providers
Get Ai Providers
List the providers a manager can bring their own key for. Never includes
litellm_model — that's an internal implementation detail (see
app/services/ai_providers.py's module docstring).
Responses
- 200 — Successful Response
GET /api/v1/studio/ai
Get Ai Status
AI status for the desktop Settings page and the assistant's basic/AI mode.
configured / provider — unchanged: whether a BYO key is stored, and for which
provider. ai_configured / ai_provider / ai_source — the effective state
from resolve_ai_config (BYO key, env LLM_API_KEY or local Ollama): when
ai_configured is false, the assistant runs in basic mode. Never returns a key.
Responses
- 200 — Successful Response
POST /api/v1/studio/ai
Configure Ai
Manager only. Saves the studio's own AI provider key, which switches the assistant from basic
mode to AI mode (see the configuration note above). Validates the
submitted key with a live test call to the chosen provider before persisting anything; the key is then
stored encrypted at rest (Fernet, app/services/crypto.py) and is never returned by
any response.
Request body
| Field | Required | Type | Description |
|---|---|---|---|
provider | Yes | string | One of the id values from GET /studio/ai/providers (e.g. "gemini", "groq"). |
api_key | Yes | string | The provider's API key. Write-only — never echoed back. |
Responses
- 200 —
{"success": true} - 400
AI_KEY_INVALID— The provider rejected the key on the live validation call. - 403 — Caller is not a manager.
- 422
AI_INVALID_PROVIDER—provideris not one of the registered provider ids. Checked before any live call is made. - 422 — Validation Error (missing
providerorapi_key).
The custom error codes above aren't captured by fetch-openapi.js's regeneration
(FastAPI's OpenAPI spec doesn't include raise_api_error responses) — added by hand
from app/routers/studio.py's configure_ai/get_ai_status/get_ai_providers and
app/services/ai_providers.py's provider registry. Keep them if this page is
regenerated.
DELETE /api/v1/studio/ai
Remove Ai Key
Remove the studio's stored BYO AI-provider key, so the studio stops sending data to that provider — immediately, without a restart.
Clears both columns POST /studio/ai writes (gemini_api_key_encrypted,
ai_provider) and the in-memory runtime key, but only when that runtime key came
from the DB (see clear_runtime_byo_key): a key from the environment (.env)
or a local Ollama model is operator configuration, not the studio's stored key,
and stays active. Idempotent — 200 with no key stored. Returns the same shape as
GET /studio/ai, so ai_configured reflects what (if anything) is still active.
Never returns or logs the key.
Responses
- 200 — Successful Response
POST /api/v1/studio/feedback
Submit Feedback
Responses
- 201 — Successful Response
- 422 — Validation Error