Skip to content

The Hoody API authenticates users with short-lived JWT access tokens (1 day) paired with refresh tokens (7 days), supports email/password and OAuth (GitHub, Google) flows, and exposes end-to-end two-factor authentication with TOTP and backup codes. Use this page to sign users up, log them in, refresh sessions, drive OAuth and RFC 8628 device flows, and configure 2FA.

Authenticated endpoints accept a JWT in the Authorization header: Authorization: Bearer <token>. Responses from endpoints that support signing carry an X-Hoody-Signature header you can verify against the public key returned by GET /api/v1/meta/public-key.

Returns regions where free-tier servers exist, with a boolean availability flag. Public, no authentication required.

This endpoint takes no parameters.

Terminal window
curl -X GET https://api.hoody.com/api/v1/auth/available-regions

Returns the ED25519 public key(s) used by Hoody to sign API responses (X-Hoody-Signature header), identity claims issued at login, and container authorization claims. Public, no authentication required. Cache the result for at least 24 hours.

This endpoint takes no parameters.

Terminal window
curl -X GET https://api.hoody.com/api/v1/meta/public-key

Create a new account with email and password. A verification email is sent; the account is inactive until the email is verified.

This endpoint takes no parameters.

Request Body

FieldTypeRequiredDescription
emailstringYesEmail address for the new account
passwordstringYesPassword (min 12 chars, must include uppercase, lowercase, number, and special char)
regionstringNoPreferred server region (e.g. eu-west). Auto-assigned by GeoIP if omitted
Terminal window
curl -X POST https://api.hoody.com/api/v1/auth/signup \
-H "Content-Type: application/json" \
-d '{
"email": "alice@example.com",
"password": "S3cure!Passw0rd",
"region": "eu-west"
}'

Verify the email address using the token from the verification email. By default returns full login credentials. When response_mode=intent and code_challenge are provided, returns an opaque auth_intent_token for PKCE exchange. If 2FA is enabled on the account, returns requires_2fa and temp_token instead.

This endpoint takes no parameters.

Request Body

FieldTypeRequiredDescription
tokenstringYesVerification token from the email link (64 chars)
response_modestringNotokens (default) or intent
code_challengestringNoPKCE code_challenge. Required when response_mode=intent
Terminal window
curl -X POST https://api.hoody.com/api/v1/auth/verify-email \
-H "Content-Type: application/json" \
-d '{
"token": "a1b2c3d4e5f6789012345678901234567890abcdefabcdefabcdefabcdef1234"
}'

Resend the email verification link. Always returns success to prevent email enumeration.

This endpoint takes no parameters.

Request Body

FieldTypeRequiredDescription
emailstringYesEmail address to resend verification to
Terminal window
curl -X POST https://api.hoody.com/api/v1/auth/resend-verification \
-H "Content-Type: application/json" \
-d '{ "email": "alice@example.com" }'

Send a password reset email. Always returns success to prevent email enumeration.

This endpoint takes no parameters.

Request Body

FieldTypeRequiredDescription
emailstringYesEmail address associated with the account
Terminal window
curl -X POST https://api.hoody.com/api/v1/auth/forgot-password \
-H "Content-Type: application/json" \
-d '{ "email": "alice@example.com" }'

Set a new password using the reset token from the password reset email.

This endpoint takes no parameters.

Request Body

FieldTypeRequiredDescription
tokenstringYesPassword reset token from the email link (64 chars)
passwordstringYesNew password (min 12 chars)
Terminal window
curl -X POST https://api.hoody.com/api/v1/auth/reset-password \
-H "Content-Type: application/json" \
-d '{
"token": "a1b2c3d4e5f6789012345678901234567890abcdefabcdefabcdefabcdef1234",
"password": "N3wS3cure!Passw0rd"
}'

Authenticate with username (or email) and password to receive a JWT access token (1 day) and a refresh token (7 days). Use the access token in the Authorization header for subsequent requests.

This endpoint takes no parameters.

Request Body

FieldTypeRequiredDescription
usernamestringNoUsername (alphanumeric, underscores, hyphens). Either username or email is required
emailstringNoEmail address. Either username or email is required
passwordstringYesAccount password (min 8 chars, must include uppercase, lowercase, and number)
response_modestringNotokens (default) or intent (hosted auth UI PKCE flow)
code_challengestringNoPKCE code_challenge. Required when response_mode=intent
Terminal window
curl -X POST https://api.hoody.com/api/v1/users/auth/login \
-H "Content-Type: application/json" \
-d '{
"username": "john_doe",
"password": "SecurePassword123!"
}'

Log out the current user. Creates an audit log entry. In a stateless JWT setup, the client should also discard the token. This endpoint works even for banned users.

This endpoint takes no parameters.

Terminal window
curl -X POST https://api.hoody.com/api/v1/users/auth/logout \
-H "Authorization: Bearer <token>"

Exchange a valid refresh token for a new access token and a new refresh token. Send the refresh token in the request body.

This endpoint takes no parameters.

Request Body

FieldTypeRequiredDescription
refreshTokenstringYesValid refresh token from a previous login/refresh
Terminal window
curl -X POST https://api.hoody.com/api/v1/users/auth/refresh \
-H "Content-Type: application/json" \
-d '{
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}'

Retrieve the profile of the currently authenticated user. Works with JWT, auth token, or Basic authentication. When authenticated with an auth token, the response includes data.auth_token introspection details (permissions and realm restrictions). This endpoint works even for banned users (read-only access).

This endpoint takes no parameters.

Terminal window
curl -X GET https://api.hoody.com/api/v1/users/auth/me \
-H "Authorization: Bearer <token>"

Redirects the browser to GitHub for OAuth authentication. Browser-only endpoint. Supports a star_check intent to check whether the user has starred the repository for credit.

NameInTypeRequiredDescription
intentquerystringNoOAuth intent: login (default) or star_check (check for star credit)
redirect_uriquerystringNoFrontend URL to redirect to after OAuth completes (must be on allowed domain)
code_challengequerystringYesPKCE code_challenge (base64url SHA-256 of code_verifier). Required — all OAuth flows must use PKCE post-migration
Terminal window
curl -X GET "https://api.hoody.com/api/v1/auth/github?intent=login&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM"

Handles the GitHub OAuth callback. Browser-only endpoint.

NameInTypeRequiredDescription
codequerystringYesAuthorization code returned by GitHub
statequerystringYesState parameter for CSRF protection
Terminal window
curl -X GET "https://api.hoody.com/api/v1/auth/github/callback?code=acbd1234&state=xyz987"

Redirects the browser to Google for OAuth authentication. Browser-only endpoint.

NameInTypeRequiredDescription
redirect_uriquerystringNoFrontend URL to redirect to after OAuth completes
code_challengequerystringYesPKCE code_challenge (base64url SHA-256 of code_verifier). Required — all OAuth flows must use PKCE post-migration
Terminal window
curl -X GET "https://api.hoody.com/api/v1/auth/google?code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM"

Handles the Google OAuth callback. Browser-only endpoint.

NameInTypeRequiredDescription
codequerystringYesAuthorization code returned by Google
statequerystringYesState parameter for CSRF protection
Terminal window
curl -X GET "https://api.hoody.com/api/v1/auth/google/callback?code=acbd1234&state=xyz987"

Initiate the OAuth popup-handoff launch flow. Issues a one-shot launch ticket bound to the request Origin header. The frontend navigates the popup to the returned launch_url.

This endpoint takes no parameters.

Request Body

FieldTypeRequiredDescription
providerstringYesOAuth provider: github or google
code_challengestringYesPKCE code_challenge (base64url SHA-256 of code_verifier, 43–128 chars)
state_idstringYesPer-attempt UUID v4
Terminal window
curl -X POST https://api.hoody.com/api/v1/auth/launch/initiate \
-H "Content-Type: application/json" \
-d '{
"provider": "github",
"code_challenge": "E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM",
"state_id": "550e8400-e29b-41d4-a716-446655440000"
}'

Consume the launch ticket and run the existing OAuth redirect flow. The popup navigates here. Sets Referrer-Policy: no-referrer.

NameInTypeRequiredDescription
ticketquerystringYesOne-shot ticket from /launch/initiate response
Terminal window
curl -X GET "https://api.hoody.com/api/v1/auth/launch/start?ticket=eyJhbGciOi..."

The verification page navigates here. Consumes the device_verify_ticket and __Host-device_verify cookie atomically, then redirects to the provider with a server-injected device_binding. Sets Referrer-Policy: no-referrer.

NameInTypeRequiredDescription
ticketquerystringYesdevice_verify_ticket minted by /device/verify_code
providerquerystringYesOAuth provider: github or google
Terminal window
curl -X GET "https://api.hoody.com/api/v1/auth/device/authorize?ticket=eyJhbGciOi...&provider=github"

Start an RFC 8628 device authorization flow. Issues a device_code (polled by the TUI) and a short, hand-typeable user_code (shown to the human). Public, no authentication.

This endpoint takes no parameters.

Request Body

FieldTypeRequiredDescription
client_namestringNoShown on the verification page as “X is requesting access”
code_challengestringNoOptional PKCE on the device flow itself; if present the poll requires the verifier
Terminal window
curl -X POST https://api.hoody.com/api/v1/auth/device/code \
-H "Content-Type: application/json" \
-d '{ "client_name": "Hoody CLI" }'

Poll for device-flow tokens (RFC 8628 §3.5). Returns lifecycle errors (authorization_pending, slow_down, access_denied, expired_token) in 400 responses until approval, then 200 with the token set. Single-use on approval. Public, no authentication.

This endpoint takes no parameters.

Request Body

FieldTypeRequiredDescription
device_codestringYesDevice code from /device/code (64 hex chars)
code_verifierstringNoPKCE code_verifier. Required if code_challenge was provided to /device/code
Terminal window
curl -X POST https://api.hoody.com/api/v1/auth/device/token \
-H "Content-Type: application/json" \
-d '{
"device_code": "a1b2c3d4e5f6789012345678901234567890abcdefabcdefabcdefabcdef1234"
}'

Verification page helper. On a live pending row, mints a one-time device_verify_ticket and sets the __Host-device_verify cookie. Leaks only client_name and a coarse status. Page-only.

This endpoint takes no parameters.

Request Body

FieldTypeRequiredDescription
user_codestringYesXXXX-XXXX user code (dashes optional)
Terminal window
curl -X POST https://api.hoody.com/api/v1/auth/device/verify_code \
-H "Content-Type: application/json" \
-d '{ "user_code": "ABCD-1234" }'

Cancel a pending OAuth AuthIntent or 2FA temp_token. Idempotent. Used by the handoff page when the user dismisses the confirmation. Pass the intent or temp token in the Authorization header.

This endpoint takes no parameters.

Terminal window
curl -X POST https://api.hoody.com/api/v1/auth/intent/cancel \
-H "Authorization: Bearer <intent_or_temp_token>"

Check the current 2FA status for the authenticated user, including whether it is enabled and how many backup codes remain.

This endpoint takes no parameters.

Terminal window
curl -X GET https://api.hoody.com/api/v1/users/auth/2fa/status \
-H "Authorization: Bearer <token>"

Begin 2FA setup. Requires the current password for verification. Returns a QR code for the authenticator app and backup codes.

This endpoint takes no parameters.

Request Body

FieldTypeRequiredDescription
passwordstringYesCurrent account password for verification
Terminal window
curl -X POST https://api.hoody.com/api/v1/users/auth/2fa/setup \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{ "password": "S3cure!Passw0rd" }'

Complete 2FA setup by providing the first code from your authenticator app. This confirms the setup is working correctly.

This endpoint takes no parameters.

Request Body

FieldTypeRequiredDescription
codestringYes6-digit code from the authenticator app
Terminal window
curl -X POST https://api.hoody.com/api/v1/users/auth/2fa/verify-setup \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{ "code": "123456" }'

Complete login by verifying the 2FA code. Use the temp_token from the login response and provide either a 6-digit OTP code or a 10-character backup code.

This endpoint takes no parameters.

Request Body

FieldTypeRequiredDescription
temp_tokenstringNoTemporary token from login response (valid for 5 minutes). Alternatively pass it as Authorization: Bearer
codestringYes6-digit OTP code from authenticator app OR 10-character backup code
response_modestringNotokens (default) or intent
Terminal window
curl -X POST https://api.hoody.com/api/v1/users/auth/2fa/verify \
-H "Content-Type: application/json" \
-d '{
"temp_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"code": "123456"
}'

POST /api/v1/users/auth/2fa/backup-codes/regenerate

Section titled “POST /api/v1/users/auth/2fa/backup-codes/regenerate”

Generate new backup codes. All existing backup codes are invalidated. Requires the current password and a current OTP code for security.

This endpoint takes no parameters.

Request Body

FieldTypeRequiredDescription
passwordstringYesCurrent account password
codestringYes6-digit OTP code from authenticator app
Terminal window
curl -X POST https://api.hoody.com/api/v1/users/auth/2fa/backup-codes/regenerate \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"password": "S3cure!Passw0rd",
"code": "123456"
}'

Disable 2FA for the account. Requires the current password and a valid OTP code (or backup code) for security.

This endpoint takes no parameters.

Request Body

FieldTypeRequiredDescription
passwordstringYesCurrent account password
codestringYes6-digit OTP code from authenticator app OR backup code
Terminal window
curl -X DELETE https://api.hoody.com/api/v1/users/auth/2fa \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"password": "S3cure!Passw0rd",
"code": "123456"
}'

Enable or disable the OTP requirement for token mutation operations. Setting enabled=false requires both the account password and a valid OTP code as a security downgrade.

This endpoint takes no parameters.

Request Body

FieldTypeRequiredDescription
enabledbooleanYestrue to require OTP for token mutations, false to skip the OTP gate
passwordstringYesRequired when enabled=false (security downgrade requires primary-factor reauth)
otp_codestringNoTOTP code or backup code. Required when enabled=false
Terminal window
curl -X PUT https://api.hoody.com/api/v1/users/auth/2fa/token-gate \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{ "enabled": true }'