Update User Profile Picture
Set or clear a user’s custom profile photo.
Path param user_id selects whose photo is being changed; the
load_user_for_crew_edit dep enforces self-or-admin/office-admin
scoping (404s on cross-org or unauthorized access).
Body: {"uploadId": "<uuid>" | null}. A UUID sets/replaces the
photo; null clears it (avatar reverts to the WorkOS-provided URL).
Validations when uploadId is non-null:
- Upload exists in the caller’s org (IDOR-safe via get_by_id_and_org).
- Upload was uploaded by the caller (
actor), not the target. An admin uploading a photo for a crew member is the expected flow — the upload row’suploaded_by_user_idbelongs to the admin, while the photo is applied to the target user. - Upload kind is
image(rejects PDFs etc.). - Upload status is
ready(rejects pending/scanning/infected/failed).
Returns the target’s freshly-resolved profile DTO, identical shape
to the /me user payload so the frontend can update either cache
(the /me cache or the /users//profile cache) from this response.
Authorizations
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Path Parameters
Body
Request body for PATCH /api/v1/users/me/profile-picture.
upload_id is REQUIRED in the body. null = remove the custom
photo (revert to the WorkOS-provided URL). A UUID = set or replace
the custom photo with the given upload. The endpoint validates
ownership, scope, kind, and ready-state before writing.
Response
Successful Response
User profile for /users/me endpoint.
profile_picture_url: server-resolved. If the user has uploaded a
custom photo this is a presigned URL for that upload's thumb
derivative (256 px); otherwise it's the WorkOS-provided URL.
has_custom_profile_picture: lets the FE show a "Remove photo"
affordance only when there's a custom photo to remove.