Use these endpoints to read and update Hoody user profiles, audit account security, browse activity logs, manage free-tier onboarding, and read or write entries in your personal encrypted vault. Every endpoint on this page is a control-plane operation served from https://api.hoody.com. Authenticate with a first-party JWT for account-setting endpoints (onboarding milestones and invite redemption) or with an auth token for everything else, sent in the Authorization header as Bearer <token>.
Retrieve a user profile by ID. Admins can read any account; regular users may only read their own. The endpoint continues to work for banned accounts (read-only access). When the caller is an auth token that lacks the resources.read_account permission, the response is reduced to identity fields and email / account PII are omitted.
Update a user profile. Regular accounts may change their own display alias and password (the request must include current_password for verification). Admins may update any account and may set the is_admin and is_banned flags. When the caller is an auth token that lacks the resources.read_account permission, the returned profile is reduced to identity fields and email / account PII are omitted.
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, 3 of 4 character classes
Choose a password with at least 12 characters, 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
CURRENT_PASSWORD_INCORRECT
Current password incorrect
The provided current password does not match your account password
Verify your current password and try again
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, security when they appear as a whole word. Ordinary names that merely contain one of those words are not affected, so Supporter, Code, and Bill Ing are all accepted.
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
{
"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_BAN_ADMIN
Cannot ban admin users
Admin users cannot be banned
Remove admin privileges before banning this user
CANNOT_MODIFY_OTHER_USER
Cannot modify other user
Regular users can only modify their own profile
You can only update your own profile, or request admin access
{
"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
Returns whether the beta gate is enabled, whether this account is unlocked, whether it already owns a free server, and (advisory, point-in-time) why a claim is currently blocked. Never attempts a claim. Auth-token callers must hold the resources.read_account permission (account-level status); tokens without it receive 403. JWT / owner callers are unaffected.
Redeem a single-use invite code to unlock free-tier server claiming during the beta, then immediately provision a free server. Idempotent if already unlocked. No-op (no code consumed) when the beta gate is disabled. Requires a first-party JWT; auth tokens, HTTP Basic, and impersonation are rejected.
Idempotently records a per-account onboarding / UI milestone (key to ISO timestamp). Used by the /auth/home first-run tour (milestone hub_tour_v1) and reusable for any future onboarding step. Setting an already-present milestone is a no-op; the original timestamp is kept.
Returns your own account security history: sign-ins and, on request, rejected attempts and other security events (logout, 2FA changes, OTP outcomes), with IP address, resolved country, source channel, and timestamp, newest first.
History covers the last 180 days, which is platform policy and the same for every account; 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.
Pass include_failed=true to also see rejected sign-in attempts. A burst of them, or any from a country you have not visited, is the clearest sign someone else is trying to get in. Failures are only recorded when a credential was presented against a real account (an attempt on an unknown address is never recorded, so this cannot be used to test whether an account exists), and are capped at 200 per account per hour; beyond that, further attempts in the same hour are not listed.
Pass include_security=true for other account-security events: logout, 2FA enable / disable, OTP verification outcomes, and backup-code use.
country is resolved in the background after the event is recorded. It is null when the address is not geolocatable at all (private, reserved, or IPv6; these stay null permanently), when the provider returned no country for it, or when resolution has not completed. Treat null as unavailable, never as a location. A null does not necessarily become non-null later: background retries stop once the row ages out of the retry window.
Also return rejected sign-in attempts against this account. Opt-in: mixing them in by default would make failed attempts look like your own sessions. (default false)
include_security
query
boolean
No
Also return other account-security events: logout, 2FA enabled / disabled, OTP verification outcomes, backup-code regeneration. (default false)
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.
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.
Vault key name (alphanumeric, dots, underscores, hyphens)
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.
Create or update a key-value pair in your personal encrypted vault. Values can be any UTF-8 string (JSON, encrypted data, plain text). The API does not validate content; encryption is highly recommended.
Vault key name (alphanumeric, dots, underscores, hyphens)
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.
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 highly recommended for sensitive data such as secrets, passwords, and API keys.
metadata
object
No
Optional JSON metadata (max 256 KB). Useful for file uploads to store content-type, filename, upload date, and so on. Must be valid JSON or null. Counts toward storage.
Vault key name (alphanumeric, dots, underscores, hyphens)
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.
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.
Return vault usage statistics. 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.
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.