User profile management
Section titled “User profile management”Retrieve and update user profiles, audit account activity, and read or manage the secure per-user vault. This page covers the control-plane user endpoints under /api/v1/users/ and /api/v1/vault/.
Two endpoints on this page require a first-party signed-in session JWT and refuse API auth tokens, HTTP Basic credentials, and impersonated sessions:
POST /api/v1/users/me/redeem-invite(redeem a beta invite code)POST /api/v1/users/me/onboarding(mark an onboarding milestone)
All other endpoints on this page accept either a session JWT or an auth token that carries the relevant permission, such as resources.read_account for account-scoped reads.
User profile
Section titled “User profile”Read and update account records. You can only view and update your own profile.
Get user by ID
Section titled “Get user by ID”GET /api/v1/users/{id}
Retrieve a user profile by ID. You can only view your own profile. This endpoint works even for banned users (read-only access).
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes | User ID to retrieve |
Response
Section titled “Response”curl -X GET "https://api.hoody.com/api/v1/users/507f1f77bcf86cd799439011" \ -H "Authorization: Bearer $HOODY_TOKEN"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://api.hoody.com', token: process.env.HOODY_TOKEN });
const user = await client.api.users.get('507f1f77bcf86cd799439011');{ "statusCode": 200, "message": "User retrieved successfully", "data": { "id": "507f1f77bcf86cd799439011", "username": "john_doe", "alias": "John Doe", "email": "john.doe@example.com", "is_banned": false, "metadata": { "department": "Engineering", "location": "San Francisco" }, "created_at": "2024-12-01T10:00:00.000Z", "updated_at": "2025-01-15T10:30:00.000Z" }}{ "statusCode": 400, "error": "Bad Request", "message": "Invalid ID format"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
INVALID_ID_FORMAT | Invalid ID format | The provided ID must be a 24-character hexadecimal string | Ensure the ID is exactly 24 characters long and contains only hexadecimal characters (0-9, a-f) |
{ "statusCode": 401, "error": "Unauthorized", "message": "Authentication token required"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
MISSING_TOKEN | Authentication token missing | No authentication token was provided in the request | Include a valid JWT token in the Authorization header as Bearer <token> |
INVALID_TOKEN | Invalid authentication token | The provided authentication token is malformed or invalid | Obtain a new token by logging in again or using a valid auth token |
TOKEN_EXPIRED | Authentication token expired | The provided authentication token has expired | Obtain a new token by logging in again or refreshing your session |
AUTH_TOKEN_LINEAGE_REVOKED | Parent auth token no longer valid | The auth token was created by another auth token, and that token (or one above it) has been revoked, disabled or has expired, so this one no longer authenticates | Create a new auth token from a valid one, or sign in again |
INVALID_CREDENTIALS | Invalid credentials | The provided username/email or password is incorrect | Verify your credentials and try again, or use the password reset feature |
EMAIL_NOT_VERIFIED | Email not verified | Returned by the login endpoint when the password is correct but the account’s email address has not been verified yet. It is only returned after the password has been checked. The response carries data.email so the client can offer a ‘resend verification email’ action without asking again. | Complete email verification by clicking the link sent to your inbox, or call /auth/resend-verification to receive a new link, or complete a password reset which also implicitly verifies the email. |
INVALID_OTP_CODE | Invalid OTP code | The provided 2FA code is incorrect or has expired | Generate a new code from your authenticator app and try again |
{ "statusCode": 403, "error": "Forbidden", "message": "Insufficient permissions"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
INSUFFICIENT_PERMISSIONS | Insufficient permissions | You do not have the required permissions to perform this action | Contact the resource owner or administrator to request access |
ACCOUNT_BANNED | Account banned | Your account has been banned and cannot access this resource | Contact support for information about your account status |
{ "statusCode": 404, "error": "Not Found", "message": "User not found"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
USER_NOT_FOUND | User not found | The requested user does not exist or has been deleted | Verify the user ID is correct |
Validation Error: the request does not match the operation schema, or its JSON body cannot be parsed. message names each failing check, and data, when present, lists them one entry per failing field.
{ "statusCode": 422, "error": "Validation Error", "message": "Validation failed: /name must NOT have fewer than 3 characters"}Update user profile
Section titled “Update user profile”PUT /api/v1/users/{id} (also accepted: PATCH, identical behaviour)
Update your user profile: alias, public key, and password (a new password needs current_password for verification). You can only update your own profile; a request for another user’s profile is refused with 403.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes | User ID to update |
Request body
Section titled “Request body”| Name | Type | Required | Description |
|---|---|---|---|
alias | string | No | New display name/alias (1 to 100 characters) |
public_key | string | No | ED25519 public key (exactly 64 hexadecimal characters) |
password | string | No | New password (12 to 128 characters, at most 72 UTF-8 bytes, 3 of 4 character classes); requires current_password |
current_password | string | No | Current password (8 to 128 characters); required when setting a new password |
{ "alias": "John Smith", "public_key": "a1b2c3d4e5f6789012345678901234567890abcdefabcdefabcdefabcdef1234"}Response
Section titled “Response”curl -X PUT "https://api.hoody.com/api/v1/users/507f1f77bcf86cd799439011" \ -H "Authorization: Bearer $HOODY_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "alias": "John Smith" }'import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://api.hoody.com', token: process.env.HOODY_TOKEN });
const updated = await client.api.users.update('507f1f77bcf86cd799439011', { alias: 'John Smith',});{ "statusCode": 200, "message": "User updated successfully", "data": { "id": "507f1f77bcf86cd799439011", "username": "john_doe", "alias": "John Smith", "email": "john.doe@example.com", "public_key": "a1b2c3d4e5f6789012345678901234567890abcdefabcdefabcdefabcdef1234", "is_banned": false, "metadata": { "department": "Engineering", "location": "New York" }, "created_at": "2024-12-01T10:00:00.000Z", "updated_at": "2025-01-15T14:45:00.000Z" }}{ "statusCode": 400, "error": "Bad Request", "message": "Password must be at least 12 characters, at most 72 UTF-8 bytes, 3 of 4 character classes"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
VALIDATION_ERROR | Invalid input parameters | One or more request parameters failed validation | Check the error message for specific field requirements and correct your input |
INVALID_ID_FORMAT | Invalid ID format | The provided ID must be a 24-character hexadecimal string | Ensure the ID is exactly 24 characters long and contains only hexadecimal characters (0-9, a-f) |
INVALID_PUBLIC_KEY_FORMAT | Invalid public key format | Public key must be exactly 64 hexadecimal characters (ED25519 format) | Provide a valid ED25519 public key as a 64-character hexadecimal string |
WEAK_PASSWORD | Password does not meet requirements | Password must be at least 12 characters, at most 72 UTF-8 bytes, 3 of 4 character classes | Choose a password with at least 12 characters, at most 72 UTF-8 bytes, 3 of 4 character classes |
CURRENT_PASSWORD_REQUIRED | Current password required | You must provide your current password to set a new password | Include the current_password field in your request |
RESERVED_IDENTITY | Display name is reserved | A small set of display names is refused because they read as official Hoody channels rather than as a person: the brand itself, and authority words such as admin, support, billing and security when they appear as a whole word. The response names the term that matched. Ordinary names that merely contain one of those words are not affected, so Supporter, Code and Bill Ing are all accepted. An account may also use a role it actually holds, so an owner can be New Admin and a staff account can be Staff | Choose a display name that identifies the person or team rather than the platform |
{ "statusCode": 401, "error": "Unauthorized", "message": "Authentication token required"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
MISSING_TOKEN | Authentication token missing | No authentication token was provided in the request | Include a valid JWT token in the Authorization header as Bearer <token> |
INVALID_TOKEN | Invalid authentication token | The provided authentication token is malformed or invalid | Obtain a new token by logging in again or using a valid auth token |
TOKEN_EXPIRED | Authentication token expired | The provided authentication token has expired | Obtain a new token by logging in again or refreshing your session |
CURRENT_PASSWORD_INCORRECT | Current password incorrect | The provided current password does not match your account password | Verify your current password and try again |
AUTH_TOKEN_LINEAGE_REVOKED | Parent auth token no longer valid | The auth token was created by another auth token, and that token (or one above it) has been revoked, disabled or has expired, so this one no longer authenticates | Create a new auth token from a valid one, or sign in again |
INVALID_CREDENTIALS | Invalid credentials | The provided username/email or password is incorrect | Verify your credentials and try again, or use the password reset feature |
EMAIL_NOT_VERIFIED | Email not verified | Returned by the login endpoint when the password is correct but the account’s email address has not been verified yet. It is only returned after the password has been checked. The response carries data.email so the client can offer a ‘resend verification email’ action without asking again. | Complete email verification by clicking the link sent to your inbox, or call /auth/resend-verification to receive a new link, or complete a password reset which also implicitly verifies the email. |
INVALID_OTP_CODE | Invalid OTP code | The provided 2FA code is incorrect or has expired | Generate a new code from your authenticator app and try again |
{ "statusCode": 403, "error": "Forbidden", "message": "Insufficient permissions"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
INSUFFICIENT_PERMISSIONS | Insufficient permissions | You do not have the required permissions to perform this action | Contact the resource owner or administrator to request access |
ACCOUNT_BANNED | Account banned | Your account has been banned and cannot access this resource | Contact support for information about your account status |
CANNOT_MODIFY_OTHER_USER | Cannot modify other user | You can only modify your own profile | Update your own profile instead, using your own user ID |
{ "statusCode": 404, "error": "Not Found", "message": "User not found"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
USER_NOT_FOUND | User not found | The requested user does not exist or has been deleted | Verify the user ID is correct |
The account credentials this request was authorized against changed while it was in flight (a competing password change, emailed reset, logout or 2FA change). Nothing was written; re-authenticate and retry.
{ "statusCode": 409, "error": "Conflict", "message": "Account credentials changed during the request. Re-authenticate and retry."}Validation Error: the request does not match the operation schema, or its JSON body cannot be parsed. message names each failing check, and data, when present, lists them one entry per failing field.
{ "statusCode": 422, "error": "Validation Error", "message": "Validation failed: /name must NOT have fewer than 3 characters"}Free tier and onboarding
Section titled “Free tier and onboarding”Inspect and manage beta access, free-tier server claiming, and per-account onboarding milestones.
Get free-tier claim status
Section titled “Get free-tier claim status”GET /api/v1/users/me/free-tier-status
Return whether the beta gate is enabled, whether this account is unlocked, whether it already owns a free server, and an advisory reason explaining why a claim is currently blocked. This endpoint never attempts a claim.
Response
Section titled “Response”curl -X GET "https://api.hoody.com/api/v1/users/me/free-tier-status" \ -H "Authorization: Bearer $HOODY_TOKEN"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://api.hoody.com', token: process.env.HOODY_TOKEN });
const status = await client.api.users.getFreeTierStatus();{ "statusCode": 200, "message": "Free-tier status retrieved", "data": { "gate_enabled": true, "unlocked": false, "has_free_server": false, "can_claim": false, "claim_blocked_reason": "invite_required", "signup_code_failed": false }}{ "statusCode": 401, "error": "Unauthorized", "message": "Authentication token required"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
MISSING_TOKEN | Authentication token missing | No authentication token was provided in the request | Include a valid JWT token in the Authorization header as Bearer <token> |
INVALID_TOKEN | Invalid authentication token | The provided authentication token is malformed or invalid | Obtain a new token by logging in again or using a valid auth token |
TOKEN_EXPIRED | Authentication token expired | The provided authentication token has expired | Obtain a new token by logging in again or refreshing your session |
AUTH_TOKEN_LINEAGE_REVOKED | Parent auth token no longer valid | The auth token was created by another auth token, and that token (or one above it) has been revoked, disabled or has expired, so this one no longer authenticates | Create a new auth token from a valid one, or sign in again |
INVALID_CREDENTIALS | Invalid credentials | The provided username/email or password is incorrect | Verify your credentials and try again, or use the password reset feature |
EMAIL_NOT_VERIFIED | Email not verified | Returned by the login endpoint when the password is correct but the account’s email address has not been verified yet. It is only returned after the password has been checked. The response carries data.email so the client can offer a ‘resend verification email’ action without asking again. | Complete email verification by clicking the link sent to your inbox, or call /auth/resend-verification to receive a new link, or complete a password reset which also implicitly verifies the email. |
INVALID_OTP_CODE | Invalid OTP code | The provided 2FA code is incorrect or has expired | Generate a new code from your authenticator app and try again |
{ "statusCode": 403, "error": "Forbidden", "message": "Insufficient permissions"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
INSUFFICIENT_PERMISSIONS | Insufficient permissions | You do not have the required permissions to perform this action | Contact the resource owner or administrator to request access |
ACCOUNT_BANNED | Account banned | Your account has been banned and cannot access this resource | Contact support for information about your account status |
{ "statusCode": 429, "error": "Too Many Requests", "message": "Rate limit exceeded"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
RATE_LIMIT_EXCEEDED | Rate limit exceeded | You have exceeded the rate limit for this endpoint | Wait before making additional requests, or upgrade your plan for higher limits |
Redeem a beta invite code
Section titled “Redeem a beta invite code”POST /api/v1/users/me/redeem-invite
Redeem a single-use invite code to unlock free-tier server claiming during the beta, then immediately provision a free server. The call is idempotent if the account is already unlocked. When the beta gate is disabled, no code is consumed (the call is a no-op).
Request body
Section titled “Request body”| Name | Type | Required | Description |
|---|---|---|---|
code | string | Yes | The invite code (case/format-insensitive), 1 to 64 characters |
{ "code": "HOODY-7Q4K-9F2M-3B8T-XR5W-2HKD-1"}Response
Section titled “Response”curl -X POST "https://api.hoody.com/api/v1/users/me/redeem-invite" \ -H "Authorization: Bearer $HOODY_JWT" \ -H "Content-Type: application/json" \ -d '{ "code": "HOODY-7Q4K-9F2M-3B8T-XR5W-2HKD-1" }'import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://api.hoody.com', token: process.env.HOODY_TOKEN });
const result = await client.api.users.redeemInvite({ code: 'HOODY-7Q4K-9F2M-3B8T-XR5W-2HKD-1',});{ "statusCode": 200, "message": "Invite code redeemed. Your free server is being prepared.", "data": { "unlocked": true, "required": true, "claim_blocked_reason": "none", "server": { "id": "5a1f3c4d8e9f0a1b2c3d4e5f", "region": "us-east-1" }, "project": { "id": "5a1f3c4d8e9f0a1b2c3d4e60", "name": "Default Project" }, "container": null }}{ "statusCode": 400, "error": "Bad Request", "message": "This invite code is invalid, expired, or already used."}| Error Code | Title | Description | Resolution |
|---|---|---|---|
VALIDATION_ERROR | Invalid input parameters | One or more request parameters failed validation | Check the error message for specific field requirements and correct your input |
INVALID_INVITE_CODE | Invalid invite code | The submitted invite code could not be redeemed because it is unknown, already used, disabled, or expired | Check the code for typos, or request a new invite code from an administrator |
{ "statusCode": 401, "error": "Unauthorized", "message": "Authentication token required"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
MISSING_TOKEN | Authentication token missing | No authentication token was provided in the request | Include a valid JWT token in the Authorization header as Bearer <token> |
INVALID_TOKEN | Invalid authentication token | The provided authentication token is malformed or invalid | Obtain a new token by logging in again or using a valid auth token |
TOKEN_EXPIRED | Authentication token expired | The provided authentication token has expired | Obtain a new token by logging in again or refreshing your session |
AUTH_TOKEN_LINEAGE_REVOKED | Parent auth token no longer valid | The auth token was created by another auth token, and that token (or one above it) has been revoked, disabled or has expired, so this one no longer authenticates | Create a new auth token from a valid one, or sign in again |
INVALID_CREDENTIALS | Invalid credentials | The provided username/email or password is incorrect | Verify your credentials and try again, or use the password reset feature |
EMAIL_NOT_VERIFIED | Email not verified | Returned by the login endpoint when the password is correct but the account’s email address has not been verified yet. It is only returned after the password has been checked. The response carries data.email so the client can offer a ‘resend verification email’ action without asking again. | Complete email verification by clicking the link sent to your inbox, or call /auth/resend-verification to receive a new link, or complete a password reset which also implicitly verifies the email. |
INVALID_OTP_CODE | Invalid OTP code | The provided 2FA code is incorrect or has expired | Generate a new code from your authenticator app and try again |
{ "statusCode": 403, "error": "Forbidden", "message": "Insufficient permissions"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
INSUFFICIENT_PERMISSIONS | Insufficient permissions | You do not have the required permissions to perform this action | Contact the resource owner or administrator to request access |
ACCOUNT_BANNED | Account banned | Your account has been banned and cannot access this resource | Contact support for information about your account status |
Validation Error: the request does not match the operation schema, or its JSON body cannot be parsed. message names each failing check, and data, when present, lists them one entry per failing field.
{ "statusCode": 422, "error": "Validation Error", "message": "Validation failed: /name must NOT have fewer than 3 characters"}{ "statusCode": 429, "error": "Too Many Requests", "message": "Rate limit exceeded"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
RATE_LIMIT_EXCEEDED | Rate limit exceeded | You have exceeded the rate limit for this endpoint | Wait before making additional requests, or upgrade your plan for higher limits |
Retry free-tier account setup
Section titled “Retry free-tier account setup”POST /api/v1/users/me/retry-setup
Manually claim a free-tier server and create the default project and container. The call is idempotent and safe to invoke if the account is already provisioned.
Request body
Section titled “Request body”| Name | Type | Required | Description |
|---|---|---|---|
region | string | No | Optional preferred region override (lowercase letters, digits, hyphens; up to 50 characters) |
{ "region": "us-east-1"}Response
Section titled “Response”curl -X POST "https://api.hoody.com/api/v1/users/me/retry-setup" \ -H "Authorization: Bearer $HOODY_TOKEN" \ -H "Content-Type: application/json" \ -d '{}'import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://api.hoody.com', token: process.env.HOODY_TOKEN });
const result = await client.api.users.retrySetup({});{ "statusCode": 200, "data": { "server": { "id": "5a1f3c4d8e9f0a1b2c3d4e5f", "region": "us-east-1" }, "project": { "id": "5a1f3c4d8e9f0a1b2c3d4e60", "name": "Default Project" }, "container": null, "blocked_reason": null }}{ "statusCode": 403, "error": "Forbidden", "message": "An invite code is required to claim your free server during the beta."}| Error Code | Title | Description | Resolution |
|---|---|---|---|
FREE_TIER_INVITE_REQUIRED | Invite code required | The beta access gate is enabled and this account has not been unlocked, so it cannot claim a free server yet | Redeem your invite code at POST /api/v1/users/me/redeem-invite, or ask an administrator to validate your account by email |
INSUFFICIENT_PERMISSIONS | Insufficient permissions | You do not have the required permissions to perform this action | Contact the resource owner or administrator to request access |
Validation Error: the request does not match the operation schema, or its JSON body cannot be parsed. message names each failing check, and data, when present, lists them one entry per failing field.
{ "statusCode": 422, "error": "Validation Error", "message": "Validation failed: /name must NOT have fewer than 3 characters"}Mark an onboarding milestone
Section titled “Mark an onboarding milestone”POST /api/v1/users/me/onboarding
Idempotently record a per-account onboarding or UI milestone (key mapped to an ISO timestamp). Setting an already-present milestone changes nothing; the original timestamp is kept.
Request body
Section titled “Request body”| Name | Type | Required | Description |
|---|---|---|---|
milestone | string | Yes | Milestone key, for example hub_tour_v1. Must match `^(hub_tour_v[0-9]3 |
{ "milestone": "hub_tour_v1"}Response
Section titled “Response”curl -X POST "https://api.hoody.com/api/v1/users/me/onboarding" \ -H "Authorization: Bearer $HOODY_JWT" \ -H "Content-Type: application/json" \ -d '{ "milestone": "hub_tour_v1" }'import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://api.hoody.com', token: process.env.HOODY_TOKEN });
const result = await client.api.users.completeOnboardingMilestone({ milestone: 'hub_tour_v1',});{ "statusCode": 200, "message": "Onboarding milestone recorded", "data": { "onboarding": { "hub_tour_v1": "2026-06-30T10:00:00.000Z" } }}{ "statusCode": 400, "error": "Bad Request", "message": "Validation failed"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
VALIDATION_ERROR | Invalid input parameters | One or more request parameters failed validation | Check the error message for specific field requirements and correct your input |
ONBOARDING_LIMIT | Onboarding milestone cap reached | The account already holds the maximum number of distinct onboarding milestones (50) | No action needed; existing milestones are unaffected |
{ "statusCode": 401, "error": "Unauthorized", "message": "Authentication token required"}This endpoint requires a signed-in session (JWT). API auth tokens, HTTP Basic credentials, and impersonated sessions are refused.
{ "statusCode": 403, "error": "Forbidden", "message": "This endpoint requires a first-party signed-in session."}Validation Error: the request does not match the operation schema, or its JSON body cannot be parsed. message names each failing check, and data, when present, lists them one entry per failing field.
{ "statusCode": 422, "error": "Validation Error", "message": "Validation failed: /name must NOT have fewer than 3 characters"}Activity logs
Section titled “Activity logs”List and summarise the authenticated user’s API activity, including the method, path, status code, and source IP of each call.
Get activity logs
Section titled “Get activity logs”GET /api/v1/users/auth/activity
Retrieve activity logs for the authenticated user with optional filtering. Results are paginated; the pages field is capped to the server’s reachable pagination window.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
page | query | integer | No | Page number (default: 1) |
limit | query | integer | No | Results per page (default: 50) |
start_date | query | string | No | Filter logs after this date |
end_date | query | string | No | Filter logs before this date |
errors_only | query | boolean | No | Show only errors (status >= 400) |
min_status | query | integer | No | Minimum status code |
max_status | query | integer | No | Maximum status code |
method | query | string | No | Filter by HTTP method; one of GET, POST, PUT, PATCH, DELETE |
realm_id | query | string | No | Filter by realm ID |
Response
Section titled “Response”curl -X GET "https://api.hoody.com/api/v1/users/auth/activity?errors_only=true&limit=20" \ -H "Authorization: Bearer $HOODY_TOKEN"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://api.hoody.com', token: process.env.HOODY_TOKEN });
const iterator = client.api.activity.listIterator({ errors_only: true, limit: 20 });for await (const entry of iterator) { console.log(entry);}{ "statusCode": 200, "message": "Activity logs retrieved successfully", "data": [ { "id": "1a9c3592695c087a8f35ceae", "user_id": "507f1f77bcf86cd799439011", "realm_id": "507f1f77bcf86cd799439011", "method": "GET", "path": "/api/v1/projects", "status_code": 200, "ip_address": "198.51.100.42", "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36", "created_at": "2025-11-18T20:00:00Z" } ], "metadata": { "total": 1, "page": 1, "limit": 20, "pages": 1 }}Validation Error: the request does not match the operation schema, or its JSON body cannot be parsed. message names each failing check, and data, when present, lists them one entry per failing field.
{ "statusCode": 422, "error": "Validation Error", "message": "Validation failed: /name must NOT have fewer than 3 characters"}Get activity stats
Section titled “Get activity stats”GET /api/v1/users/auth/activity/stats
Retrieve storage usage statistics for activity logs, including the total size, the oldest and newest record, and the configured retention period.
Response
Section titled “Response”curl -X GET "https://api.hoody.com/api/v1/users/auth/activity/stats" \ -H "Authorization: Bearer $HOODY_TOKEN"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://api.hoody.com', token: process.env.HOODY_TOKEN });
const stats = await client.api.activity.getStats();{ "statusCode": 200, "message": "Activity stats retrieved successfully", "data": { "total_size_bytes": 1048576, "total_records": 5000, "oldest_record": "2025-10-18T20:00:00Z", "newest_record": "2025-11-18T20:00:00Z", "retention_days": 365 }}Security history
Section titled “Security history”Get your account security history
Section titled “Get your account security history”GET /api/v1/users/me/security-history
Return your own account security history: sign-ins and, on request, rejected attempts and other security events (logout, 2FA changes, OTP outcomes, backup-code use). Each entry carries the IP address, the resolved country, the source channel, and the timestamp, newest first.
History covers the last 180 days; older logins are purged automatically and cannot be recovered. Login records cannot be edited or deleted by the account holder. The trail is append-only so it stays trustworthy as evidence.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
page | query | integer | No | Page number (default: 1) |
limit | query | integer | No | Results per page (default: 50) |
include_failed | query | boolean | No | Also return rejected sign-in attempts against this account (default: false). Opt-in, because mixing them in by default would make failed attempts look like your own sessions |
include_security | query | boolean | No | Also return other account-security events: logout, 2FA enable/disable, OTP verification outcomes, backup-code regeneration (default: false) |
Response
Section titled “Response”curl -X GET "https://api.hoody.com/api/v1/users/me/security-history?include_failed=true" \ -H "Authorization: Bearer $HOODY_TOKEN"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://api.hoody.com', token: process.env.HOODY_TOKEN });
const iterator = client.api.users.listSecurityHistoryIterator({ include_failed: true });for await (const entry of iterator) { console.log(entry);}{ "statusCode": 200, "message": "Login history retrieved successfully", "data": [ { "id": "5a1f3c4d8e9f0a1b2c3d4e5f", "event": "login", "outcome": "success", "ip_address": "8.8.8.8", "country": "US", "client": "hoody-web", "created_at": "2026-01-15T10:00:00.000Z" }, { "id": "5a1f3c4d8e9f0a1b2c3d4e60", "event": "login", "outcome": "success", "ip_address": "10.0.0.42", "country": null, "client": "hoody-cli", "created_at": "2026-01-14T22:00:00.000Z" } ], "metadata": { "total": 2, "page": 1, "limit": 50, "pages": 1 }}{ "statusCode": 403, "error": "Forbidden", "message": "Insufficient permissions"}Validation Error: the request does not match the operation schema, or its JSON body cannot be parsed. message names each failing check, and data, when present, lists them one entry per failing field.
{ "statusCode": 422, "error": "Validation Error", "message": "Validation failed: /name must NOT have fewer than 3 characters"}The vault stores per-user key-value pairs scoped to a realm (or globally when no realm_id is given). Values can be any UTF-8 string: JSON, encrypted data, or plain text. The API does not validate or verify the content of stored values.
List vault keys
Section titled “List vault keys”GET /api/v1/vault/keys
List all keys in your encrypted vault with metadata (key names, sizes, timestamps). Values are not included in this response; use GET /api/v1/vault/keys/{key} to retrieve individual values.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
realm_id | query | string | No | Target a specific realm (24-character hex). When omitted and not on a realm subdomain, defaults to global scope (realm_id = ""). Case-insensitive; uppercase is normalized to lowercase |
Response
Section titled “Response”curl -X GET "https://api.hoody.com/api/v1/vault/keys" \ -H "Authorization: Bearer $HOODY_TOKEN"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://api.hoody.com', token: process.env.HOODY_TOKEN });
const iterator = client.api.vault.listIterator({});for await (const entry of iterator) { console.log(entry);}{ "statusCode": 200, "message": "Vault keys retrieved successfully", "data": [ { "key": "my-encrypted-notes", "realm_id": "507f1f77bcf86cd799439011", "metadata": { "filename": "notes.json", "content_type": "application/json" }, "size_bytes": 2048, "created_at": "2025-11-14T18:00:00.000Z", "updated_at": "2025-11-14T18:15:00.000Z" }, { "key": "config.json", "realm_id": "", "metadata": null, "size_bytes": 512, "created_at": "2025-11-14T17:30:00.000Z", "updated_at": "2025-11-14T17:30:00.000Z" } ]}{ "statusCode": 401, "error": "Unauthorized", "message": "Authentication token required"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
MISSING_TOKEN | Authentication token missing | No authentication token was provided in the request | Include a valid JWT token in the Authorization header as Bearer <token> |
INVALID_TOKEN | Invalid authentication token | The provided authentication token is malformed or invalid | Obtain a new token by logging in again or using a valid auth token |
TOKEN_EXPIRED | Authentication token expired | The provided authentication token has expired | Obtain a new token by logging in again or refreshing your session |
AUTH_TOKEN_LINEAGE_REVOKED | Parent auth token no longer valid | The auth token was created by another auth token, and that token (or one above it) has been revoked, disabled or has expired, so this one no longer authenticates | Create a new auth token from a valid one, or sign in again |
INVALID_CREDENTIALS | Invalid credentials | The provided username/email or password is incorrect | Verify your credentials and try again, or use the password reset feature |
EMAIL_NOT_VERIFIED | Email not verified | Returned by the login endpoint when the password is correct but the account’s email address has not been verified yet. It is only returned after the password has been checked. The response carries data.email so the client can offer a ‘resend verification email’ action without asking again. | Complete email verification by clicking the link sent to your inbox, or call /auth/resend-verification to receive a new link, or complete a password reset which also implicitly verifies the email. |
INVALID_OTP_CODE | Invalid OTP code | The provided 2FA code is incorrect or has expired | Generate a new code from your authenticator app and try again |
{ "statusCode": 403, "error": "Forbidden", "message": "Insufficient permissions"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
INSUFFICIENT_PERMISSIONS | Insufficient permissions | You do not have the required permissions to perform this action | Contact the resource owner or administrator to request access |
ACCOUNT_BANNED | Account banned | Your account has been banned and cannot access this resource | Contact support for information about your account status |
Validation Error: the request does not match the operation schema, or its JSON body cannot be parsed. message names each failing check, and data, when present, lists them one entry per failing field.
{ "statusCode": 422, "error": "Validation Error", "message": "Validation failed: /name must NOT have fewer than 3 characters"}Get vault key
Section titled “Get vault key”GET /api/v1/vault/keys/{key}
Retrieve a specific key-value pair from your encrypted vault by key name.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
realm_id | query | string | No | Target a specific realm (24-character hex). When omitted and not on a realm subdomain, defaults to global scope (realm_id = ""). Case-insensitive; uppercase is normalized to lowercase |
key | path | string | Yes | Vault key name (alphanumeric, dots, underscores, hyphens) |
Response
Section titled “Response”curl -X GET "https://api.hoody.com/api/v1/vault/keys/api-keys.json" \ -H "Authorization: Bearer $HOODY_TOKEN"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://api.hoody.com', token: process.env.HOODY_TOKEN });
const entry = await client.api.vault.get('api-keys.json');{ "statusCode": 200, "message": "Vault key retrieved successfully", "data": { "key": "my-encrypted-notes", "realm_id": "507f1f77bcf86cd799439011", "value": "{\"notes\": \"My important notes\", \"encrypted\": true}", "metadata": { "filename": "notes.json", "content_type": "application/json" }, "size_bytes": 53, "created_at": "2025-11-14T18:00:00.000Z", "updated_at": "2025-11-14T18:15:00.000Z" }}{ "statusCode": 401, "error": "Unauthorized", "message": "Authentication token required"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
MISSING_TOKEN | Authentication token missing | No authentication token was provided in the request | Include a valid JWT token in the Authorization header as Bearer <token> |
INVALID_TOKEN | Invalid authentication token | The provided authentication token is malformed or invalid | Obtain a new token by logging in again or using a valid auth token |
TOKEN_EXPIRED | Authentication token expired | The provided authentication token has expired | Obtain a new token by logging in again or refreshing your session |
AUTH_TOKEN_LINEAGE_REVOKED | Parent auth token no longer valid | The auth token was created by another auth token, and that token (or one above it) has been revoked, disabled or has expired, so this one no longer authenticates | Create a new auth token from a valid one, or sign in again |
INVALID_CREDENTIALS | Invalid credentials | The provided username/email or password is incorrect | Verify your credentials and try again, or use the password reset feature |
EMAIL_NOT_VERIFIED | Email not verified | Returned by the login endpoint when the password is correct but the account’s email address has not been verified yet. It is only returned after the password has been checked. The response carries data.email so the client can offer a ‘resend verification email’ action without asking again. | Complete email verification by clicking the link sent to your inbox, or call /auth/resend-verification to receive a new link, or complete a password reset which also implicitly verifies the email. |
INVALID_OTP_CODE | Invalid OTP code | The provided 2FA code is incorrect or has expired | Generate a new code from your authenticator app and try again |
{ "statusCode": 403, "error": "Forbidden", "message": "Insufficient permissions"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
INSUFFICIENT_PERMISSIONS | Insufficient permissions | You do not have the required permissions to perform this action | Contact the resource owner or administrator to request access |
ACCOUNT_BANNED | Account banned | Your account has been banned and cannot access this resource | Contact support for information about your account status |
{ "statusCode": 404, "error": "Not Found", "message": "Vault key not found."}| Error Code | Title | Description | Resolution |
|---|---|---|---|
VAULT_KEY_NOT_FOUND | Vault key not found | The specified key does not exist in your vault | Verify the key name is correct |
Validation Error: the request does not match the operation schema, or its JSON body cannot be parsed. message names each failing check, and data, when present, lists them one entry per failing field.
{ "statusCode": 422, "error": "Validation Error", "message": "Validation failed: /name must NOT have fewer than 3 characters"}Set vault key
Section titled “Set vault key”PUT /api/v1/vault/keys/{key} (also accepted: PATCH, identical behaviour)
Create or update a key-value pair in your personal encrypted vault.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
realm_id | query | string | No | Target a specific realm (24-character hex). When omitted and not on a realm subdomain, defaults to global scope (realm_id = ""). Case-insensitive; uppercase is normalized to lowercase |
key | path | string | Yes | Vault key name (alphanumeric, dots, underscores, hyphens) |
Request body
Section titled “Request body”| Name | Type | Required | Description |
|---|---|---|---|
value | string | Yes | Value to store. Can be any UTF-8 string (JSON, encrypted data, plain text). The API does not validate or verify the content; encryption is required for sensitive data such as secrets, passwords, or API keys |
metadata | object | No | Optional JSON metadata (max 256KB). Useful for file uploads to store content-type, filename, upload date, and similar. Must be valid JSON or null. Counts toward total vault storage |
{ "value": "{\"api_key\": \"sk_test_123456\", \"encrypted\": true}", "metadata": { "filename": "api-keys.json", "content_type": "application/json", "encrypted": true }}Response
Section titled “Response”curl -X PUT "https://api.hoody.com/api/v1/vault/keys/api-keys.json" \ -H "Authorization: Bearer $HOODY_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "value": "{\"api_key\": \"sk_test_123456\", \"encrypted\": true}", "metadata": { "encrypted": true } }'import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://api.hoody.com', token: process.env.HOODY_TOKEN });
const entry = await client.api.vault.set('api-keys.json', { value: '{"api_key": "sk_test_123456", "encrypted": true}', metadata: { encrypted: true },});{ "statusCode": 200, "message": "Vault key updated successfully", "data": { "key": "my-encrypted-notes", "realm_id": "507f1f77bcf86cd799439011", "value": "{\"notes\": \"My important notes\", \"encrypted\": true}", "metadata": { "filename": "notes.json", "content_type": "application/json", "encrypted": true }, "size_bytes": 53, "created_at": "2025-11-14T18:00:00.000Z", "updated_at": "2025-11-14T18:15:00.000Z" }}{ "statusCode": 201, "message": "Vault key created successfully", "data": { "key": "my-encrypted-notes", "realm_id": "507f1f77bcf86cd799439011", "value": "{\"notes\": \"My important notes\", \"encrypted\": true}", "metadata": { "filename": "notes.json", "content_type": "application/json", "encrypted": true }, "size_bytes": 53, "created_at": "2025-11-14T18:00:00.000Z", "updated_at": "2025-11-14T18:00:00.000Z" }}{ "statusCode": 400, "error": "VAULT_LIMIT_EXCEEDED", "message": "Vault storage limit exceeded."}| Error Code | Title | Description | Resolution |
|---|---|---|---|
VALIDATION_ERROR | Invalid input parameters | One or more request parameters failed validation | Check the error message for specific field requirements and correct your input |
VAULT_LIMIT_EXCEEDED | Vault storage limit exceeded | The operation would exceed your vault storage limit | Delete existing keys to free up space or contact support to increase your limit |
{ "statusCode": 401, "error": "Unauthorized", "message": "Authentication token required"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
MISSING_TOKEN | Authentication token missing | No authentication token was provided in the request | Include a valid JWT token in the Authorization header as Bearer <token> |
INVALID_TOKEN | Invalid authentication token | The provided authentication token is malformed or invalid | Obtain a new token by logging in again or using a valid auth token |
TOKEN_EXPIRED | Authentication token expired | The provided authentication token has expired | Obtain a new token by logging in again or refreshing your session |
AUTH_TOKEN_LINEAGE_REVOKED | Parent auth token no longer valid | The auth token was created by another auth token, and that token (or one above it) has been revoked, disabled or has expired, so this one no longer authenticates | Create a new auth token from a valid one, or sign in again |
INVALID_CREDENTIALS | Invalid credentials | The provided username/email or password is incorrect | Verify your credentials and try again, or use the password reset feature |
EMAIL_NOT_VERIFIED | Email not verified | Returned by the login endpoint when the password is correct but the account’s email address has not been verified yet. It is only returned after the password has been checked. The response carries data.email so the client can offer a ‘resend verification email’ action without asking again. | Complete email verification by clicking the link sent to your inbox, or call /auth/resend-verification to receive a new link, or complete a password reset which also implicitly verifies the email. |
INVALID_OTP_CODE | Invalid OTP code | The provided 2FA code is incorrect or has expired | Generate a new code from your authenticator app and try again |
{ "statusCode": 403, "error": "Forbidden", "message": "Insufficient permissions"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
INSUFFICIENT_PERMISSIONS | Insufficient permissions | You do not have the required permissions to perform this action | Contact the resource owner or administrator to request access |
ACCOUNT_BANNED | Account banned | Your account has been banned and cannot access this resource | Contact support for information about your account status |
Validation Error: the request does not match the operation schema, or its JSON body cannot be parsed. message names each failing check, and data, when present, lists them one entry per failing field.
{ "statusCode": 422, "error": "Validation Error", "message": "Validation failed: /name must NOT have fewer than 3 characters"}Get vault statistics
Section titled “Get vault statistics”GET /api/v1/vault/stats
Retrieve statistics about your vault usage. total_keys and total_size_bytes are scoped to the current realm. limit_mb, remaining_mb, and used_percentage reflect global vault usage across all realms.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
realm_id | query | string | No | Target a specific realm (24-character hex). When omitted and not on a realm subdomain, defaults to global scope (realm_id = ""). Case-insensitive; uppercase is normalized to lowercase |
Response
Section titled “Response”curl -X GET "https://api.hoody.com/api/v1/vault/stats" \ -H "Authorization: Bearer $HOODY_TOKEN"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://api.hoody.com', token: process.env.HOODY_TOKEN });
const stats = await client.api.vault.getStats({});{ "statusCode": 200, "message": "Vault statistics retrieved successfully", "data": { "total_keys": 5, "total_size_bytes": 10240, "total_size_mb": 0.009766, "limit_mb": 50, "used_percentage": 0.02, "remaining_mb": 49.990234 }}{ "statusCode": 401, "error": "Unauthorized", "message": "Authentication token required"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
MISSING_TOKEN | Authentication token missing | No authentication token was provided in the request | Include a valid JWT token in the Authorization header as Bearer <token> |
INVALID_TOKEN | Invalid authentication token | The provided authentication token is malformed or invalid | Obtain a new token by logging in again or using a valid auth token |
TOKEN_EXPIRED | Authentication token expired | The provided authentication token has expired | Obtain a new token by logging in again or refreshing your session |
AUTH_TOKEN_LINEAGE_REVOKED | Parent auth token no longer valid | The auth token was created by another auth token, and that token (or one above it) has been revoked, disabled or has expired, so this one no longer authenticates | Create a new auth token from a valid one, or sign in again |
INVALID_CREDENTIALS | Invalid credentials | The provided username/email or password is incorrect | Verify your credentials and try again, or use the password reset feature |
EMAIL_NOT_VERIFIED | Email not verified | Returned by the login endpoint when the password is correct but the account’s email address has not been verified yet. It is only returned after the password has been checked. The response carries data.email so the client can offer a ‘resend verification email’ action without asking again. | Complete email verification by clicking the link sent to your inbox, or call /auth/resend-verification to receive a new link, or complete a password reset which also implicitly verifies the email. |
INVALID_OTP_CODE | Invalid OTP code | The provided 2FA code is incorrect or has expired | Generate a new code from your authenticator app and try again |
{ "statusCode": 403, "error": "Forbidden", "message": "Insufficient permissions"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
INSUFFICIENT_PERMISSIONS | Insufficient permissions | You do not have the required permissions to perform this action | Contact the resource owner or administrator to request access |
ACCOUNT_BANNED | Account banned | Your account has been banned and cannot access this resource | Contact support for information about your account status |
Validation Error: the request does not match the operation schema, or its JSON body cannot be parsed. message names each failing check, and data, when present, lists them one entry per failing field.
{ "statusCode": 422, "error": "Validation Error", "message": "Validation failed: /name must NOT have fewer than 3 characters"}Delete vault key
Section titled “Delete vault key”DELETE /api/v1/vault/keys/{key}
Permanently delete a key-value pair from your encrypted vault. This action cannot be undone.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
realm_id | query | string | No | Target a specific realm (24-character hex). When omitted and not on a realm subdomain, defaults to global scope (realm_id = ""). Case-insensitive; uppercase is normalized to lowercase |
key | path | string | Yes | Vault key name (alphanumeric, dots, underscores, hyphens) |
Response
Section titled “Response”curl -X DELETE "https://api.hoody.com/api/v1/vault/keys/api-keys.json" \ -H "Authorization: Bearer $HOODY_TOKEN"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://api.hoody.com', token: process.env.HOODY_TOKEN });
await client.api.vault.delete('api-keys.json');{ "statusCode": 200, "message": "Vault key deleted successfully"}{ "statusCode": 401, "error": "Unauthorized", "message": "Authentication token required"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
MISSING_TOKEN | Authentication token missing | No authentication token was provided in the request | Include a valid JWT token in the Authorization header as Bearer <token> |
INVALID_TOKEN | Invalid authentication token | The provided authentication token is malformed or invalid | Obtain a new token by logging in again or using a valid auth token |
TOKEN_EXPIRED | Authentication token expired | The provided authentication token has expired | Obtain a new token by logging in again or refreshing your session |
AUTH_TOKEN_LINEAGE_REVOKED | Parent auth token no longer valid | The auth token was created by another auth token, and that token (or one above it) has been revoked, disabled or has expired, so this one no longer authenticates | Create a new auth token from a valid one, or sign in again |
INVALID_CREDENTIALS | Invalid credentials | The provided username/email or password is incorrect | Verify your credentials and try again, or use the password reset feature |
EMAIL_NOT_VERIFIED | Email not verified | Returned by the login endpoint when the password is correct but the account’s email address has not been verified yet. It is only returned after the password has been checked. The response carries data.email so the client can offer a ‘resend verification email’ action without asking again. | Complete email verification by clicking the link sent to your inbox, or call /auth/resend-verification to receive a new link, or complete a password reset which also implicitly verifies the email. |
INVALID_OTP_CODE | Invalid OTP code | The provided 2FA code is incorrect or has expired | Generate a new code from your authenticator app and try again |
{ "statusCode": 403, "error": "Forbidden", "message": "Insufficient permissions"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
INSUFFICIENT_PERMISSIONS | Insufficient permissions | You do not have the required permissions to perform this action | Contact the resource owner or administrator to request access |
ACCOUNT_BANNED | Account banned | Your account has been banned and cannot access this resource | Contact support for information about your account status |
{ "statusCode": 404, "error": "Not Found", "message": "Vault key not found."}| Error Code | Title | Description | Resolution |
|---|---|---|---|
VAULT_KEY_NOT_FOUND | Vault key not found | The specified key does not exist in your vault | Verify the key name is correct |
Validation Error: the request does not match the operation schema, or its JSON body cannot be parsed. message names each failing check, and data, when present, lists them one entry per failing field.
{ "statusCode": 422, "error": "Validation Error", "message": "Validation failed: /name must NOT have fewer than 3 characters"}Clear entire vault
Section titled “Clear entire vault”DELETE /api/v1/vault
Permanently delete all keys and values from your encrypted vault. This action cannot be undone.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
realm_id | query | string | No | Target a specific realm (24-character hex). When omitted and not on a realm subdomain, defaults to global scope (realm_id = ""). Case-insensitive; uppercase is normalized to lowercase |
Response
Section titled “Response”curl -X DELETE "https://api.hoody.com/api/v1/vault" \ -H "Authorization: Bearer $HOODY_TOKEN"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://api.hoody.com', token: process.env.HOODY_TOKEN });
const result = await client.api.vault.clear({});{ "statusCode": 200, "message": "Vault cleared successfully", "data": { "deleted_count": 5 }}{ "statusCode": 401, "error": "Unauthorized", "message": "Authentication token required"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
MISSING_TOKEN | Authentication token missing | No authentication token was provided in the request | Include a valid JWT token in the Authorization header as Bearer <token> |
INVALID_TOKEN | Invalid authentication token | The provided authentication token is malformed or invalid | Obtain a new token by logging in again or using a valid auth token |
TOKEN_EXPIRED | Authentication token expired | The provided authentication token has expired | Obtain a new token by logging in again or refreshing your session |
AUTH_TOKEN_LINEAGE_REVOKED | Parent auth token no longer valid | The auth token was created by another auth token, and that token (or one above it) has been revoked, disabled or has expired, so this one no longer authenticates | Create a new auth token from a valid one, or sign in again |
INVALID_CREDENTIALS | Invalid credentials | The provided username/email or password is incorrect | Verify your credentials and try again, or use the password reset feature |
EMAIL_NOT_VERIFIED | Email not verified | Returned by the login endpoint when the password is correct but the account’s email address has not been verified yet. It is only returned after the password has been checked. The response carries data.email so the client can offer a ‘resend verification email’ action without asking again. | Complete email verification by clicking the link sent to your inbox, or call /auth/resend-verification to receive a new link, or complete a password reset which also implicitly verifies the email. |
INVALID_OTP_CODE | Invalid OTP code | The provided 2FA code is incorrect or has expired | Generate a new code from your authenticator app and try again |
{ "statusCode": 403, "error": "Forbidden", "message": "Insufficient permissions"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
INSUFFICIENT_PERMISSIONS | Insufficient permissions | You do not have the required permissions to perform this action | Contact the resource owner or administrator to request access |
ACCOUNT_BANNED | Account banned | Your account has been banned and cannot access this resource | Contact support for information about your account status |
Validation Error: the request does not match the operation schema, or its JSON body cannot be parsed. message names each failing check, and data, when present, lists them one entry per failing field.
{ "statusCode": 422, "error": "Validation Error", "message": "Validation failed: /name must NOT have fewer than 3 characters"}