Users
The users API lets you manage the authenticated user’s profile, password, profile image, and identities (email and phone). All endpoints operate on the currently authenticated user via /users/me.
Endpoints
| Method | Endpoint | Description |
|---|---|---|
| GET | /users/me | Get current user profile |
| PATCH | /users/me | Update current user profile |
| POST | /users/me/change-password | Change password |
| POST | /users/me/profile-image | Upload profile image |
| DELETE | /users/me/profile-image | Remove profile image |
| GET | /users/me/identities | List identities |
| POST | /users/me/identities | Add an identity |
| DELETE | /users/me/identities | Remove an identity |
| POST | /users/me/identities/verify | Request identity verification |
Get Current User
GET /api/v2/users/me
Returns the authenticated user’s profile, including their identities.
Response
{
"id": 7,
"created_at": "2024-01-15T08:30:00Z",
"first_name": "Ola",
"last_name": "Nordmann",
"profile_image_url": "https://cdn.snapbooks.no/profile-images/abc123.jpg",
"last_login": "2026-03-31T14:22:00Z",
"identities": [
{
"type": "email",
"value": "ola@example.com",
"verified": true
},
{
"type": "phone",
"value": "+4791234567",
"verified": false
}
]
}
Update Current User
PATCH /api/v2/users/me
Updates the authenticated user’s first name and/or last name.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| first_name | string | No | User’s first name |
| last_name | string | No | User’s last name |
Example Request
{
"first_name": "Ola",
"last_name": "Nordmann"
}
Response
Returns the updated user object (same shape as GET /users/me).
Change Password
POST /api/v2/users/me/change-password
Changes the authenticated user’s password. Rate limited to 5 requests per hour.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| password | string | Yes | Current password |
| new_password | string | Yes | New password |
Password Requirements
- Minimum 8 characters
- Must contain at least one uppercase letter
- Must contain at least one lowercase letter
- Must contain at least one number
- Must be different from the current password
Example Request
{
"password": "OldPass123",
"new_password": "NewSecure456"
}
Response
{
"message": "Password changed successfully"
}
Error Responses
| Status | Code | Description |
|---|---|---|
| 400 | common.validation_error |
Missing request body, password, or new_password |
| 400 | user.password_unchanged |
The new password is identical to the current one |
| 400 | user.weak_password |
The new password does not meet the requirements above |
| 401 | user.invalid_current_password |
The supplied current password is incorrect |
| 429 | — | Rate limit exceeded (5 per hour) |
Upload Profile Image
POST /api/v2/users/me/profile-image
Uploads a new profile image for the authenticated user. The request must use multipart/form-data encoding.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| file | file | Yes | Image file (JPEG, PNG, or WebP) |
Allowed Content Types
image/jpegimage/jpgimage/pngimage/webp
Response
Returns the updated user object with the new profile_image_url.
Error Responses
| Status | Code | Description |
|---|---|---|
| 400 | common.validation_error |
No file part in the request, or no file selected |
| 400 | user.unsupported_image_type |
The Content-Type is not JPEG, PNG, or WebP |
| 400 | user.invalid_image_content |
The file contents are not a valid image of the declared type |
Remove Profile Image
DELETE /api/v2/users/me/profile-image
Removes the authenticated user’s profile image.
Response
Returns the updated user object with profile_image_url set to null.
List Identities
GET /api/v2/users/me/identities
Returns the authenticated user’s identities (email and phone number).
Response
Returns the user object with the identities array populated. See the response example in Get Current User.
Add an Identity
POST /api/v2/users/me/identities
Adds a phone number identity to the authenticated user. Email changes are not supported through this endpoint.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| type | string | Yes | Identity type. Only phone is supported |
| value | string | Yes | The phone number |
Example Request
{
"type": "phone",
"value": "+4791234567"
}
Response
Returns the updated user object with identities.
Error Responses
| Status | Code | Description |
|---|---|---|
| 400 | common.validation_error |
Missing request body, type, or value |
| 400 | user.email_identity_immutable |
type was email — email changes are not supported here |
| 400 | user.unsupported_identity_type |
type is neither phone nor email |
Remove an Identity
DELETE /api/v2/users/me/identities
Removes a phone number identity from the authenticated user. Email cannot be removed.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| type | string | Yes | Identity type to remove. Only phone is supported |
Example Request
{
"type": "phone"
}
Response
Returns the updated user object with identities.
Error Responses
| Status | Code | Description |
|---|---|---|
| 400 | common.validation_error |
Missing request body or type |
| 400 | user.email_identity_immutable |
type was email — the email identity cannot be removed |
| 400 | user.unsupported_identity_type |
type is neither phone nor email |
Request Identity Verification
POST /api/v2/users/me/identities/verify
Sends a verification email to the authenticated user. Rate limited to 5 requests per hour. Only email verification is currently supported.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| type | string | Yes | Identity type to verify. Only email is supported |
| value | string | Yes | The email address to verify (must match the stored email) |
Example Request
{
"type": "email",
"value": "ola@example.com"
}
Response
{
"message": "Verification email sent"
}
Error Responses
| Status | Code | Description |
|---|---|---|
| 400 | common.validation_error |
Missing request body, type, or value |
| 400 | user.unsupported_identity_type |
type is not email |
| 400 | user.identity_value_mismatch |
value does not match the stored email address |
| 400 | user.identity_already_verified |
The email address is already verified |
| 429 | — | Rate limit exceeded (5 per hour) |
Attributes
| Attribute | Type | Description |
|---|---|---|
| id | integer | Unique identifier (read-only) |
| created_at | datetime | Account creation timestamp (read-only) |
| first_name | string | User’s first name |
| last_name | string | User’s last name |
| profile_image_url | string | URL to the user’s profile image (read-only) |
| last_login | datetime | Last login timestamp (read-only) |
Identity
| Attribute | Type | Description |
|---|---|---|
| type | string | Identity type: email or phone |
| value | string | The identity value (email address or phone number) |
| verified | boolean | Whether the identity has been verified. Only email verification is supported; phone identities always return false |
Error Codes
Errors use the standard error envelope. Branch on code, not on
message. In addition to the common codes, the
/users/me endpoints return:
| Code | HTTP status | When |
|---|---|---|
user.password_unchanged |
400 | The new password equals the current password |
user.weak_password |
400 | The new password is shorter than 8 characters or lacks an uppercase letter, a lowercase letter, or a number |
user.invalid_current_password |
401 | The password field does not match the stored password |
user.unsupported_image_type |
400 | The uploaded profile image is not JPEG, PNG, or WebP |
user.invalid_image_content |
400 | The uploaded file’s contents are not a valid image |
user.email_identity_immutable |
400 | An attempt to add, change, or remove the email identity |
user.unsupported_identity_type |
400 | An identity type other than the one the endpoint supports |
user.identity_value_mismatch |
400 | The value sent to the verify endpoint is not the user’s stored email |
user.identity_already_verified |
400 | The email address has already been verified |
Example Error Response
{
"error": {
"code": "user.weak_password",
"message": "Password must be at least 8 characters with uppercase, lowercase, and a number",
"request_id": "a1b2c3d4-5678-90ab-cdef-1234567890ab"
}
}
Related Resources
- Client Accounts — companies the user has access to
- Invitations — invite users to join client accounts
- Authentication — OAuth2 authentication flow