Users
The Users API manages user profiles, host onboarding, avatar uploads, and availability scheduling. All endpoints under /v1/users/me require authentication.
GET /v1/users/me
Section titled “GET /v1/users/me”Retrieve the full profile of the authenticated user.
Authentication: Bearer token required.
Request
Section titled “Request”GET /v1/users/meAuthorization: Bearer eyJhbGciOiJSUzI1NiJ9...Response
Section titled “Response”{ "id": "01JN2X4K8M3F7QPZRVWT6YBHCE", "email": "jane@example.com", "display_name": "Jane Smith", "username": "janesmith", "bio": "Life coach and productivity consultant", "avatar_url": "https://cdn.vidivo.app/avatars/01JN2X4K.jpg", "role": "host", "email_verified": true, "is_age_verified": true, "is_available": true, "rate_per_minute": "2.50", "window_size_minutes": 10, "payout_enabled": true, "created_at": "2026-03-15T10:00:00Z"}PUT /v1/users/me
Section titled “PUT /v1/users/me”Update the authenticated user’s profile. Only included fields are updated (partial update).
Authentication: Bearer token required.
Request
Section titled “Request”PUT /v1/users/meAuthorization: Bearer eyJhbGciOiJSUzI1NiJ9...Content-Type: application/json{ "display_name": "Jane Smith-Jones", "bio": "Executive coach specializing in leadership development", "username": "janecoach"}| Field | Type | Required | Description |
|---|---|---|---|
display_name | string | No | Public name. Max 80 characters. |
bio | string | No | Profile bio. Max 500 characters. |
username | string | No | Unique username for public profile URL. |
Response
Section titled “Response”Returns the updated user profile (same format as GET /v1/users/me).
Errors
Section titled “Errors”| Code | Status | Description |
|---|---|---|
validation_error | 400 | Invalid field values |
conflict | 409 | Username already taken |
unauthorized | 401 | Missing or invalid token |
PUT /v1/users/me/avatar
Section titled “PUT /v1/users/me/avatar”Upload a profile avatar image. The image is resized to 512x512 pixels and stored in Cloudflare R2.
Authentication: Bearer token required.
Request
Section titled “Request”PUT /v1/users/me/avatarAuthorization: Bearer eyJhbGciOiJSUzI1NiJ9...Content-Type: multipart/form-data| Field | Type | Required | Description |
|---|---|---|---|
avatar | file | Yes | Image file (JPEG, PNG, WebP, or GIF). Max 5 MB. |
curl -X PUT https://api.vidivo.app/v1/users/me/avatar \ -H "Authorization: Bearer eyJhbGciOiJSUzI1NiJ9..." \ -F "avatar=@photo.jpg"const formData = new FormData();formData.append('avatar', fileInput.files[0]);
const { avatar_url } = await fetch(`${API}/users/me/avatar`, { method: 'PUT', headers: { Authorization: `Bearer ${accessToken}` }, body: formData,}).then(r => r.json());Response
Section titled “Response”{ "avatar_url": "https://cdn.vidivo.app/avatars/01JN2X4K.jpg"}Errors
Section titled “Errors”| Code | Status | Description |
|---|---|---|
validation_error | 400 | File too large or unsupported format |
unauthorized | 401 | Missing or invalid token |
POST /v1/users/me/become-host
Section titled “POST /v1/users/me/become-host”Transition a verified user to the host role. Requires email verification and age verification to be completed first.
Authentication: Bearer token required (role: verified_user).
Request
Section titled “Request”POST /v1/users/me/become-hostAuthorization: Bearer eyJhbGciOiJSUzI1NiJ9...Content-Type: application/json{ "username": "janecoach", "bio": "Life coach and productivity consultant", "rate_per_minute": "2.50", "window_size_minutes": 10}| Field | Type | Required | Description |
|---|---|---|---|
username | string | Yes | Unique username for public profile |
bio | string | No | Profile bio |
rate_per_minute | string | Yes | Per-minute rate in USD |
window_size_minutes | integer | Yes | Billing window size (1—60 minutes) |
Response
Section titled “Response”Returns the updated user profile with role: "host".
Errors
Section titled “Errors”| Code | Status | Description |
|---|---|---|
forbidden | 403 | Email not verified or age verification not complete |
conflict | 409 | Username already taken |
validation_error | 400 | Invalid rate or window size |
PUT /v1/users/me/rate
Section titled “PUT /v1/users/me/rate”Set or update the host’s per-minute billing rate.
Authentication: Bearer token required (role: host or admin).
Request
Section titled “Request”PUT /v1/users/me/rateAuthorization: Bearer eyJhbGciOiJSUzI1NiJ9...Content-Type: application/json{ "rate_per_minute": "3.00"}Response
Section titled “Response”{ "rate_per_minute": "3.00"}PUT /v1/users/me/toggle-available
Section titled “PUT /v1/users/me/toggle-available”Toggle the host’s online/offline status. When available, the host appears in search results and can receive calls.
Authentication: Bearer token required.
Request
Section titled “Request”PUT /v1/users/me/toggle-availableAuthorization: Bearer eyJhbGciOiJSUzI1NiJ9...Response
Section titled “Response”{ "is_available": true}GET /v1/users/me/availability
Section titled “GET /v1/users/me/availability”Retrieve the host’s weekly availability schedule.
Authentication: Bearer token required.
Request
Section titled “Request”GET /v1/users/me/availabilityAuthorization: Bearer eyJhbGciOiJSUzI1NiJ9...Response
Section titled “Response”{ "slots": [ { "day_of_week": 1, "start_time": "09:00", "end_time": "17:00" }, { "day_of_week": 2, "start_time": "09:00", "end_time": "17:00" }, { "day_of_week": 3, "start_time": "10:00", "end_time": "14:00" } ]}| Field | Type | Description |
|---|---|---|
day_of_week | integer | 0 = Sunday, 1 = Monday, …, 6 = Saturday |
start_time | string | Start time in HH:MM format (UTC) |
end_time | string | End time in HH:MM format (UTC) |
PUT /v1/users/me/availability
Section titled “PUT /v1/users/me/availability”Replace the host’s entire weekly availability schedule with new slots.
Authentication: Bearer token required.
Request
Section titled “Request”PUT /v1/users/me/availabilityAuthorization: Bearer eyJhbGciOiJSUzI1NiJ9...Content-Type: application/json{ "slots": [ { "day_of_week": 1, "start_time": "09:00", "end_time": "17:00" }, { "day_of_week": 2, "start_time": "09:00", "end_time": "17:00" }, { "day_of_week": 3, "start_time": "10:00", "end_time": "14:00" }, { "day_of_week": 4, "start_time": "09:00", "end_time": "17:00" }, { "day_of_week": 5, "start_time": "09:00", "end_time": "12:00" } ]}Response
Section titled “Response”Returns the updated availability schedule (same format as GET).
Errors
Section titled “Errors”| Code | Status | Description |
|---|---|---|
validation_error | 400 | Invalid time format or overlapping slots |
GET /v1/users/:username
Section titled “GET /v1/users/:username”Retrieve the public profile of a host by their username. No authentication required.
Request
Section titled “Request”GET /v1/users/janecoachResponse
Section titled “Response”{ "id": "01JN2X4K8M3F7QPZRVWT6YBHCE", "display_name": "Jane Smith", "username": "janecoach", "bio": "Life coach and productivity consultant", "avatar_url": "https://cdn.vidivo.app/avatars/01JN2X4K.jpg", "is_available": true, "rate_per_minute": "2.50", "window_size_minutes": 10, "follower_count": 42}Errors
Section titled “Errors”| Code | Status | Description |
|---|---|---|
not_found | 404 | Username does not exist or user is not a host |
Push Token Management
Section titled “Push Token Management”Device push tokens are managed via the notification endpoints but are also aliased under /v1/users/me/devices for convenience.
POST /v1/users/me/devices
Section titled “POST /v1/users/me/devices”Register a push notification token for the current device.
POST /v1/users/me/devicesAuthorization: Bearer eyJhbGciOiJSUzI1NiJ9...Content-Type: application/json{ "token": "fcm_device_token_string", "platform": "ios"}| Field | Type | Required | Description |
|---|---|---|---|
token | string | Yes | FCM device token |
platform | string | Yes | ios, android, or web |
DELETE /v1/users/me/devices/:id
Section titled “DELETE /v1/users/me/devices/:id”Remove a registered push token.
DELETE /v1/users/me/devices/01JN2X4K8M3F7QPZRVWT6YBHCEAuthorization: Bearer eyJhbGciOiJSUzI1NiJ9...Returns 204 No Content on success.