---
title: "Update Profile"
method: PUT
path: "/api/user/profile"
---

# Update Profile

`PUT /api/user/profile`

Partial update of the current user's profile.

Bounded-growth columns (``user_text``, ``soul_text``,
``heartbeat_text``) are routed through
:func:`backend.app.agent.markdown_registry.assert_column_within_budget`
so the dashboard editor cannot bypass the byte cap that the agent's
workspace tools and compaction paths already respect. Returns
``413 Payload Too Large`` with the registry's actual / allowed
sizes so a client-side editor can show a useful error.

## Request body

- UserProfileUpdate — Fields the client is allowed to update on the current user. ``onboarding_complete`` is deliberately not writable here. It is owned by the backend (set by ``OnboardingSubscriber`` when the LLM deletes BOOTSTRAP.md or heuristic evidence appears) so the conversational onboarding can't be short-circuited by the UI. ``data_sharing_consent`` is deliberately not writable here either: it has its own dedicated endpoint (``PUT /api/user/data-sharing-consent``) that always stamps ``data_sharing_consent_at``. Routing it through this generic patch endpoint would lose the timestamp guarantee. ``model_config`` pins ``extra="ignore"`` so unknown fields (including ``data_sharing_consent`` if a client tries to slip it through here) are silently dropped. This is the contract the dedicated-endpoint test relies on. If pydantic ever flips the global default to ``"forbid"``, this declaration keeps the contract stable.
  - `phone` string, nullable
  - `timezone` string, nullable
  - `soul_text` string, nullable
  - `user_text` string, nullable
  - `heartbeat_text` string, nullable
  - `heartbeat_opt_in` boolean, nullable
  - `heartbeat_frequency` string, nullable
  - `heartbeat_max_daily` integer, nullable

## Response `200`

Successful Response

- UserProfileResponse
  - `id` string, required
  - `user_id` string, required
  - `phone` string, required
  - `timezone` string, required
  - `soul_text` string, required
  - `user_text` string, required
  - `heartbeat_text` string, required
  - `preferred_channel` string, required
  - `channel_identifier` string, required
  - `heartbeat_opt_in` boolean, required
  - `heartbeat_frequency` string, required
  - `heartbeat_max_daily` integer
  - `onboarding_complete` boolean, required
  - `is_active` boolean, required
  - `data_sharing_consent` boolean
  - `data_sharing_consent_at` string, nullable
  - `created_at` string, required
  - `updated_at` string, required

## Other responses

- `422` — Validation Error

---

[API](https://skmtc.net/mozilla-ai/apis/clawbolt.md) · [All operations](https://skmtc.net/mozilla-ai/apis/clawbolt/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/mozilla-ai/clawbolt/versions/327e305858ac/schema)
