Users API
The Users API manages user accounts, authentication, and identity on the Canvus server. Use it to sign users in and out, create and manage accounts, handle password resets, and perform administrative operations like blocking or approving users.
Authentication overview:
- Most endpoints require a
Private-Tokenheader or an active session cookie - Authentication endpoints (login, register, password reset) do not require authentication
- Admin-only endpoints are noted per section
Related APIs:
- Group membership is managed through the Groups API
- Long-lived API tokens are managed through the Access Tokens API
Current behavior
- When a non-administrator makes a change they are not allowed to make through update, delete, block, unblock or approve, the server returns
401 Unauthorizedrather than403 Forbidden. - Update, delete, block, unblock and approve on a user ID that does not exist return
400 Bad Requestrather than404. - Change email with an address already in use returns
500 Internal Server Errorrather than409 Conflict. - Confirm email with an invalid token returns
403 Forbidden, and validating or using an invalid password-reset token returns404 Not Found, rather than400. - An invalid or expired token returns
403 Forbidden, not401. See Current behavior.
These are being corrected.
User object
Every user-related endpoint that returns user data uses the same JSON structure.
Note: User IDs (and group IDs) are integers, unlike most other API resources which use UUIDs.
Fields:
id(integer) -- unique user identifiername(string) -- display nameemail(string) -- email address, also used as the login nameadmin(boolean) -- whether the user has administrator privilegesapproved(boolean) -- whether the user account has been approvedblocked(boolean) -- whether the user account is blocked from signing instate(string) -- account state (e.g.,"normal")created_at(string) -- ISO 8601 timestamp of account creationlast_login(string) -- ISO 8601 timestamp of last sign-in, or empty string if never signed in
Example:
{
"id": 1002,
"name": "Alice Chen",
"email": "alice@example.com",
"admin": false,
"approved": true,
"blocked": false,
"state": "normal",
"created_at": "2025-03-15T09:22:41.817Z",
"last_login": "2025-03-28T14:05:12.003Z"
}
Sign in
Signs the user in with email and password, returning a session token.
POST /api/v1/users/login
Authentication: None required.
Streaming: Not supported.
Request body (JSON):
email(string, required) -- the user's email addresspassword(string, required) -- the user's passwordremember(boolean, optional) -- if true, extends the session lifetime
Send only these fields. A body with any other field, for example username, is rejected with 400 Bad Request and the message "Login request must have either email and password or token".
curl -X POST \
-H "Content-Type: application/json" \
-d '{"email":"alice@example.com","password":"s3cureP@ss"}' \
https://canvus.example.com/api/v1/users/login
Response (200 OK):
{
"token": "EXAMPLE_SESSION_TOKEN_REPLACE_WITH_YOUR_OWN",
"user": {
"id": 1002,
"name": "Alice Chen",
"email": "alice@example.com",
"admin": false,
"approved": true,
"blocked": false,
"state": "normal",
"created_at": "2025-03-15T09:22:41.817Z",
"last_login": "2025-03-28T14:05:12.003Z"
}
}
Use the returned token value in subsequent requests as the Private-Token header.
Token validation mode: You can also POST an existing token to validate it and get a new one. If the token is valid, the server returns a new session token with a fresh lifetime. The token you sent is not extended; it stays valid until its own expiry.
token(string, required) -- an existing access token to validate
curl -X POST \
-H "Content-Type: application/json" \
-d '{"token":"EXAMPLE_SESSION_TOKEN_REPLACE_WITH_YOUR_OWN"}' \
https://canvus.example.com/api/v1/users/login
Error responses:
401 Unauthorized-- invalid email/password or invalid token, or the account is blocked or not yet approved
Current behavior
In token validation mode, an invalid or expired token currently returns 500 Internal Server Error rather than 401. This is being corrected.
SAML 2.0 sign in
Validates a SAML 2.0 assertion and signs the user in. The server must have SAML authentication enabled in server settings.
POST /api/v1/users/login/saml
Authentication: None required.
Streaming: Not supported.
Request body (JSON):
inResponseTo(string, required) -- the request ID known to the SAML initiator (correlates response to request)responseXml(string, required) -- the full SAML response XMLremember(boolean, optional) -- if true, extends the session lifetime
curl -X POST \
-H "Content-Type: application/json" \
-d '{"inResponseTo":"_abc123","responseXml":"<samlp:Response>...</samlp:Response>","remember":true}' \
https://canvus.example.com/api/v1/users/login/saml
Response (200 OK): Same token + user object as the standard sign-in endpoint.
Error responses:
400 Bad Request-- invalid or malformed SAML assertion, or the assertion failed validation403 Forbidden-- SAML sign-in is disabled in server settings
Sign out
Invalidates a session token, signing the user out.
POST /api/v1/users/logout
Authentication: Required.
Streaming: Not supported.
Request body (JSON, optional):
token(string, optional) -- specific token to invalidate. If omitted, the token from thePrivate-Tokenheader is invalidated.
curl -X POST \
-H "Private-Token: EXAMPLE_SESSION_TOKEN_REPLACE_WITH_YOUR_OWN" \
https://canvus.example.com/api/v1/users/logout
Response (200 OK): Empty body on success.
List users
Returns all user accounts on the server, including the built-in Guest account. Accounts that are still waiting for email confirmation are not included.
GET /api/v1/users
Authentication: Required.
Streaming: Supports ?subscribe for live updates.
Query parameters:
subscribe(flag, optional) -- when present, keeps the connection open and streams updates as newline-delimited JSON. The parameter takes no value; its presence alone turns streaming on, so?subscribe=falsealso streams.
curl -H "Private-Token: YOUR_TOKEN" \
https://canvus.example.com/api/v1/users
Response (200 OK):
[
{
"id": 100,
"name": "Guest",
"email": "",
"admin": false,
"approved": true,
"blocked": false,
"state": "normal",
"created_at": "2025-03-15T09:20:18.817Z",
"last_login": "2025-03-15T09:21:48.569Z"
},
{
"id": 1000,
"name": "Admin",
"email": "admin@example.com",
"admin": true,
"approved": true,
"blocked": false,
"state": "normal",
"created_at": "2025-03-15T09:20:33.392Z",
"last_login": "2025-03-28T14:05:12.003Z"
},
{
"id": 1002,
"name": "Alice Chen",
"email": "alice@example.com",
"admin": false,
"approved": true,
"blocked": false,
"state": "normal",
"created_at": "2025-03-15T09:22:41.817Z",
"last_login": ""
}
]
Get single user
Returns details for a specific user.
GET /api/v1/users/:user_id
Authentication: Required.
Streaming: Supports ?subscribe for live updates.
Path parameters:
user-id(integer, required) -- the ID of the user
curl -H "Private-Token: YOUR_TOKEN" \
https://canvus.example.com/api/v1/users/1002
Response (200 OK):
{
"id": 1002,
"name": "Alice Chen",
"email": "alice@example.com",
"admin": false,
"approved": true,
"blocked": false,
"state": "normal",
"created_at": "2025-03-15T09:22:41.817Z",
"last_login": ""
}
Error responses:
404 Not Found-- no user with the given ID exists
Create user
Creates a new user account. If no password is provided, the server sends a password reset email to the new user.
POST /api/v1/users
Authentication: Admin required.
Streaming: Not supported.
Request body (JSON):
email(string, required) -- email address, used as the login name. Must be unique across all users.name(string, required) -- display namepassword(string, optional) -- initial password. If omitted, a password reset email is sent.admin(boolean, optional) -- grant administrator privileges. Default:false.approved(boolean, optional) -- mark the account as approved. Default:true.blocked(boolean, optional) -- create the account in blocked state. Default:false.
curl -X POST \
-H "Private-Token: YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"email":"bob.martinez@example.com","name":"Bob Martinez","password":"b0bSecure!"}' \
https://canvus.example.com/api/v1/users
Response (200 OK):
{
"id": 1003,
"name": "Bob Martinez",
"email": "bob.martinez@example.com",
"admin": false,
"approved": true,
"blocked": false,
"state": "normal",
"created_at": "2025-03-28T15:10:22.501Z",
"last_login": ""
}
Error responses:
400 Bad Request-- missing required fields, invalid email format, or a user with this email already exists403 Forbidden-- caller is not an administrator
Update user
Changes user profile data. Regular users can update their own name and blocked fields. Administrators can change all fields of any user.
PATCH /api/v1/users/:user_id
Authentication: Required. Admin required for other users' profiles or admin-only fields.
Streaming: Not supported.
Path parameters:
user-id(integer, required) -- the ID of the user to update
Request body (JSON) -- all fields optional, include only those being changed:
name(string) -- display nameemail(string) -- email address. Must be unique. Admin-only; regular users change their own address through Change email.password(string) -- new password. Admin-only.admin(boolean) -- grant or revoke admin privileges. Admin-only.approved(boolean) -- approve the user (can only change fromfalsetotrue). Admin-only.blocked(boolean) -- block or unblock the userneed_email_confirmation(boolean) -- confirm email on behalf of user. Onlyfalseis accepted, which confirms a pending account;trueis rejected. Admin-only.
curl -X PATCH \
-H "Private-Token: YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"Alice Chen-Williams"}' \
https://canvus.example.com/api/v1/users/1002
Response (200 OK):
{
"id": 1002,
"name": "Alice Chen-Williams",
"email": "alice@example.com",
"admin": false,
"approved": true,
"blocked": false,
"state": "normal",
"created_at": "2025-03-15T09:22:41.817Z",
"last_login": "2025-03-28T14:05:12.003Z"
}
Error responses:
400 Bad Request-- email already in use by another user403 Forbidden-- insufficient permissions for the requested change404 Not Found-- no user with the given ID exists
Delete user
Permanently deletes a user account.
DELETE /api/v1/users/:user_id
Authentication: Admin required.
Streaming: Not supported.
Path parameters:
user-id(integer, required) -- the ID of the user to delete
curl -X DELETE \
-H "Private-Token: YOUR_TOKEN" \
https://canvus.example.com/api/v1/users/1003
Response (200 OK): Empty body on success.
Error responses:
403 Forbidden-- caller is not an administrator404 Not Found-- no user with the given ID exists
Change password
Allows a user to change their own password by providing the current password. To set another user's password, administrators use the password field of Update user.
POST /api/v1/users/:user_id/password
Authentication: Required.
Streaming: Not supported.
Path parameters:
user-id(integer, required) -- the ID of the user
Request body (JSON):
current_password(string, required) -- the user's current passwordnew_password(string, required) -- the desired new password
curl -X POST \
-H "Private-Token: YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"current_password":"s3cureP@ss","new_password":"n3wS3cure!"}' \
https://canvus.example.com/api/v1/users/1002/password
Response (200 OK): Returns the updated user object.
{
"id": 1002,
"name": "Alice Chen",
"email": "alice@example.com",
"admin": false,
"approved": true,
"blocked": false,
"state": "normal",
"created_at": "2025-03-15T09:22:41.817Z",
"last_login": "2025-03-28T14:05:12.003Z"
}
Error responses:
401 Unauthorized-- current password is incorrect403 Forbidden-- non-admin trying to change another user's password
Change email
Initiates an email change for a user. The server sends a confirmation link to the new email address.
POST /api/v1/users/:user_id/change-email
Authentication: Required.
Streaming: Not supported.
Path parameters:
user-id(integer, required) -- the ID of the user
Request body (JSON):
new_email(string, required) -- the new email address
curl -X POST \
-H "Private-Token: YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"new_email":"alice.new@example.com"}' \
https://canvus.example.com/api/v1/users/1002/change-email
Error responses:
400 Bad Request-- invalid email format409 Conflict-- email already in use by another user
Confirm email
Confirms a user's email address using a token received via email. This completes the email change or registration process.
POST /api/v1/users/confirm-email
Authentication: None required.
Streaming: Not supported.
Request body (JSON):
token(string, required) -- the confirmation token from the email
curl -X POST \
-H "Content-Type: application/json" \
-d '{"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."}' \
https://canvus.example.com/api/v1/users/confirm-email
Response (200 OK): Empty body on success.
Error responses:
400 Bad Request--{"msg": "Invalid email confirmation token."}-- token is expired, malformed, or already used
Request password reset
Sends a password reset email to the specified address. If the email matches an existing account, the user receives a reset token.
For security, this endpoint returns success even if no matching account exists.
POST /api/v1/users/password/create-reset-token
Authentication: None required.
Streaming: Not supported.
Request body (JSON):
email(string, required) -- the email address of the account to reset
curl -X POST \
-H "Content-Type: application/json" \
-d '{"email":"alice@example.com"}' \
https://canvus.example.com/api/v1/users/password/create-reset-token
Response (200 OK): Empty body on success.
Validate password reset token
Checks whether a password reset token is still valid without consuming it. Use this to verify a token before showing the password reset form.
GET /api/v1/users/password/validate-reset-token
Authentication: None required.
Streaming: Not supported.
Query parameters:
token(string, required) -- the reset token from the email
curl "https://canvus.example.com/api/v1/users/password/validate-reset-token?token=eyJhbGciOiJIUzI1NiJ9..."
Response (200 OK): Empty body if the token is valid.
Error responses:
400 Bad Request--{"msg": "Invalid token"}-- token is expired, malformed, or already consumed
Reset password
Sets a new password using a reset token from the password reset email.
POST /api/v1/users/password/reset
Authentication: None required.
Streaming: Not supported.
Request body (JSON):
token(string, required) -- the reset token from the emailpassword(string, required) -- the new password
curl -X POST \
-H "Content-Type: application/json" \
-d '{"token":"eyJhbGciOiJIUzI1NiJ9...","password":"myN3wP@ssword!"}' \
https://canvus.example.com/api/v1/users/password/reset
Response (200 OK): Empty body on success.
Error responses:
400 Bad Request--{"msg": "Invalid token"}-- token is expired, malformed, or already consumed
Register user (self-registration)
Allows a new user to create their own account. Self-registration must be enabled in the server settings.
On success, the server sends a confirmation email. The account is not active until the email is confirmed via the Confirm Email endpoint.
POST /api/v1/users/register
Authentication: None required.
Streaming: Not supported.
Request body (JSON):
email(string, required) -- email address, used as the login name. Must be unique.name(string, required) -- display namepassword(string, required) -- password for the new accountadmin(boolean, optional) -- only administrators can set this totrue; a request from anyone else that sets it totrueis rejected. Default:false.approved(boolean, optional) -- when the server requires admin approval, a non-admin request that sets this totrueis rejected. Default depends on server settings.blocked(boolean, optional) -- default:false
curl -X POST \
-H "Content-Type: application/json" \
-d '{"email":"carol.nguyen@example.com","name":"Carol Nguyen","password":"c@r0lSecure"}' \
https://canvus.example.com/api/v1/users/register
Response (200 OK): Returns the new user object.
Error responses:
400 Bad Request-- missing required fields, or a user with this email already exists403 Forbidden--{"msg": "Sign-up using a password is not enabled"}-- self-registration is disabled in server settings
Block user
Blocks a user account, preventing them from signing in. All active sessions are revoked.
Regular users can block their own account. Administrators can block any user.
POST /api/v1/users/:user_id/block
Authentication: Required.
Streaming: Not supported.
Path parameters:
user-id(integer, required) -- the ID of the user to block
curl -X POST \
-H "Private-Token: YOUR_TOKEN" \
https://canvus.example.com/api/v1/users/1002/block
Response (200 OK):
{
"id": 1002,
"name": "Alice Chen",
"email": "alice@example.com",
"admin": false,
"approved": true,
"blocked": true,
"state": "normal",
"created_at": "2025-03-15T09:22:41.817Z",
"last_login": "2025-03-28T14:05:12.003Z"
}
Error responses:
403 Forbidden-- non-admin trying to block another user404 Not Found-- no user with the given ID exists
Unblock user
Unblocks a previously blocked user account, allowing them to sign in again.
POST /api/v1/users/:user_id/unblock
Authentication: Admin required.
Streaming: Not supported.
Path parameters:
user-id(integer, required) -- the ID of the user to unblock
curl -X POST \
-H "Private-Token: YOUR_TOKEN" \
https://canvus.example.com/api/v1/users/1002/unblock
Response (200 OK):
{
"id": 1002,
"name": "Alice Chen",
"email": "alice@example.com",
"admin": false,
"approved": true,
"blocked": false,
"state": "normal",
"created_at": "2025-03-15T09:22:41.817Z",
"last_login": "2025-03-28T14:05:12.003Z"
}
Error responses:
403 Forbidden-- caller is not an administrator404 Not Found-- no user with the given ID exists
Approve user
Approves a user account that is pending approval (e.g., after self-registration when admin approval is required).
POST /api/v1/users/:user_id/approve
Authentication: Admin required.
Streaming: Not supported.
Path parameters:
user-id(integer, required) -- the ID of the user to approve
curl -X POST \
-H "Private-Token: YOUR_TOKEN" \
https://canvus.example.com/api/v1/users/1002/approve
Response (200 OK):
{
"id": 1002,
"name": "Alice Chen",
"email": "alice@example.com",
"admin": false,
"approved": true,
"blocked": false,
"state": "normal",
"created_at": "2025-03-15T09:22:41.817Z",
"last_login": ""
}
Error responses:
403 Forbidden-- caller is not an administrator404 Not Found-- no user with the given ID exists
Force password reset
Forces a password reset for a user. The user's password is cleared and all of their active sessions are revoked, so they cannot sign in until they set a new password. The server emails them a password reset link automatically, unless the account is blocked.
POST /api/v1/users/:user_id/reset-password
Authentication: Admin required.
Streaming: Not supported.
Path parameters:
user-id(integer, required) -- the ID of the user
curl -X POST \
-H "Private-Token: YOUR_TOKEN" \
https://canvus.example.com/api/v1/users/1002/reset-password
Response (200 OK):
user(object) -- the updated user objectremoved_login_token_count(integer) -- number of session tokens revokedremaining_login_token_count(integer) -- number of session tokens still validremaining_access_token_count(integer) -- number of the user's access tokenstoken_delete_error(string) -- present only if revoking the sessions failedemail_send_error(string) -- present only if the reset email was not sent, for example because the account is blocked
Error responses:
403 Forbidden-- caller is not an administrator404 Not Found-- no user with the given ID exists