{"openapi":"3.1.0","info":{"title":"Hawt Site API","description":"\nMinimalist static site deployment platform API providing multi-tenant site hosting, user account management, personal access tokens, and user asset isolation.\n\n### Authentication\nProtected endpoints require a Personal Access Token (`hawt_pat_<hex>`) passed in either header:\n* `Authorization: Bearer <token>`\n* `X-API-Key: <token>`\n\n### Core Policies\n* **User Isolation**: Users can only view, manage, and delete their own sites and API tokens (`403 Forbidden` on unauthorized access attempts).\n* **Storage Quotas**: Default per-user active storage quota is **500 MB** across active sites, with a **50 MB** max upload size per deployment.\n","version":"1.0.0"},"paths":{"/v1/users":{"post":{"tags":["users"],"summary":"Create User Account","description":"Creates a new user account and generates an initial API token.\n\n### Access Control & Authorization:\n* **Registration**: Allows unauthenticated self-registration if enabled on the instance, requires master administrative secret key authorization, or requires a valid single-use invite code.\n\n### Namespace Rules:\n* Username must be 3-32 characters (`^[a-z0-9_-]+$`).\n* Prohibits reserved system keywords (`hawt`, `admin`, `api`, `v1`, `v2`, `system`, `static`, etc.).","operationId":"create_user_v1_users_post","security":[{"HTTPBearer":[]},{"APIKeyHeader":[]}],"parameters":[{"name":"Authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserCreate"}}}},"responses":{"201":{"description":"User account created successfully alongside initial API token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserWithTokenResponse"}}}},"400":{"description":"Invalid format, missing/invalid invite code, or email mismatch.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized: Invite code or administrative secret key required when public registration is restricted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict: Username or email already registered.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/users/me":{"get":{"tags":["users"],"summary":"Get Current User Profile","description":"Retrieve profile details of the currently authenticated user.\n\n### Access Control & Authorization:\n* **Authentication Required**: Bearer PAT (`hawt_pat_...`) or `X-API-Key`.\n* **Identity Scoping**: Strictly scoped to the authenticated caller's account profile.","operationId":"get_current_user_profile_v1_users_me_get","security":[{"HTTPBearer":[]},{"APIKeyHeader":[]}],"parameters":[{"name":"Authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Returns account profile details of the authenticated caller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserResponse"}}}},"401":{"description":"Unauthorized: Missing, invalid, or expired API token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/invites":{"post":{"tags":["admin-invites"],"summary":"Create Invite Code","description":"Generate a new single-use invite code token.\n\n### Access Control & Authorization:\n* **Administrative Secret Key**: Strictly requires master `HAWT_CLOUD_ADMIN_KEY` header (`X-API-Key` or `Authorization: Bearer`).","operationId":"create_invite_code_v1_admin_invites_post","security":[{"HTTPBearer":[]},{"APIKeyHeader":[]}],"parameters":[{"name":"Authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InviteCreate"}}}},"responses":{"201":{"description":"Invite code created successfully.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InviteCreatedResponse"}}}},"401":{"description":"Unauthorized: Master administrative secret key required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error: Invalid request body fields or expires_in_days out of bounds.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"get":{"tags":["admin-invites"],"summary":"List Invite Codes","description":"Retrieve list of invite codes generated by administrators.\n\n### Access Control & Authorization:\n* **Administrative Secret Key**: Strictly requires master `HAWT_CLOUD_ADMIN_KEY`.","operationId":"list_invite_codes_v1_admin_invites_get","security":[{"HTTPBearer":[]},{"APIKeyHeader":[]}],"parameters":[{"name":"status","in":"query","required":false,"schema":{"type":"string","description":"Filter invite status: 'all', 'unused', 'used', 'expired', or 'valid'.","default":"all","title":"Status"},"description":"Filter invite status: 'all', 'unused', 'used', 'expired', or 'valid'."},{"name":"Authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"List of invite code records matching query parameters.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InviteListResponse"}}}},"401":{"description":"Unauthorized: Master administrative secret key required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/invites/{invite_id}":{"delete":{"tags":["admin-invites"],"summary":"Revoke Invite Code","description":"Revoke an unredeemed invite code.\n\n### Access Control & Authorization:\n* **Administrative Secret Key**: Strictly requires master `HAWT_CLOUD_ADMIN_KEY`.","operationId":"revoke_invite_code_v1_admin_invites__invite_id__delete","security":[{"HTTPBearer":[]},{"APIKeyHeader":[]}],"parameters":[{"name":"invite_id","in":"path","required":true,"schema":{"type":"string","title":"Invite Id"}},{"name":"Authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"204":{"description":"Invite code revoked and deleted successfully."},"400":{"description":"Bad Request: Cannot revoke an invite code that has already been redeemed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized: Master administrative secret key required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found: Invite code ID does not exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/tokens":{"post":{"tags":["tokens"],"summary":"Create Personal Access Token","description":"Generates a new Personal Access Token (PAT) bound to the authenticated user account.\n\n### Access Control & Authorization:\n* **Authentication Required**: Bearer PAT (`hawt_pat_...`) or `X-API-Key`.\n* **Ownership**: Created token is bound exclusively to `current_user.id`.\n* **Secret Exposure**: Returns the raw secret token string (`raw_token`) **only once**.","operationId":"create_token_v1_tokens_post","security":[{"HTTPBearer":[]},{"APIKeyHeader":[]}],"parameters":[{"name":"Authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenCreate"}}}},"responses":{"201":{"description":"Token generated successfully. Returns raw token secret once.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenCreatedResponse"}}}},"401":{"description":"Unauthorized: Missing, invalid, or expired API token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["tokens"],"summary":"List API Tokens","description":"Lists active API token metadata (excluding raw secrets) owned by the caller.\n\n### Access Control & Authorization:\n* **Authentication Required**: Bearer PAT (`hawt_pat_...`) or `X-API-Key`.\n* **Ownership Scoping**: Users can view only tokens where `user_id == current_user.id`.","operationId":"list_tokens_v1_tokens_get","security":[{"HTTPBearer":[]},{"APIKeyHeader":[]}],"parameters":[{"name":"Authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Returns list of active token metadata owned by the authenticated caller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenListResponse"}}}},"401":{"description":"Unauthorized: Missing, invalid, or expired API token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/tokens/{token_id}":{"delete":{"tags":["tokens"],"summary":"Revoke API Token","description":"Revokes an API token owned by the authenticated user.\n\n### Access Control & Authorization:\n* **Authentication Required**: Bearer PAT (`hawt_pat_...`) or `X-API-Key`.\n* **Ownership Check**: Rejects with `403 Forbidden` if `token_obj.user_id != current_user.id`.","operationId":"delete_token_v1_tokens__token_id__delete","security":[{"HTTPBearer":[]},{"APIKeyHeader":[]}],"parameters":[{"name":"token_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Token Id"}},{"name":"Authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Token revoked successfully.","content":{"application/json":{"schema":{}}}},"401":{"description":"Unauthorized: Missing, invalid, or expired API token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden: You do not have permission to revoke this token (ownership check failed).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found: Target token_id does not exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/sites/upload":{"post":{"tags":["sites"],"summary":"Upload Static Site Assets","description":"Upload static site assets (single HTML file or ZIP archive).\n\n### Access Control & Authorization:\n* **Authentication Required**: Bearer PAT (`hawt_pat_...`) or `X-API-Key`.\n* **Ownership Scoping**: Uploaded site is strictly owned by `current_user.id`.\n* **Namespace Isolation**: If `path_type='user'`, assets are saved under `<username>/<site_id>`, ensuring multi-tenant disk isolation.\n\n### Quota & Security Restrictions:\n* **Max Upload Size**: 50 MB\n* **Max Decompressed Archive Size**: 50 MB\n* **Max Zip Member Count**: 10,000 files\n* **User Storage Quota**: Enforces 500 MB quota across active sites owned by caller.\n* **Security Checks**: Path traversal (`..`) and escaping symlink attempts are automatically blocked.","operationId":"upload_site_v1_sites_upload_post","security":[{"HTTPBearer":[]},{"APIKeyHeader":[]}],"parameters":[{"name":"Authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_upload_site_v1_sites_upload_post"}}}},"responses":{"201":{"description":"Site deployed successfully.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SiteResponse"}}}},"400":{"description":"Invalid path_type, slug, path traversal, or malformed zip entry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized: Missing, invalid, or expired API token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict: Custom slug or storage path already exists.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"413":{"description":"Content Too Large: Maximum upload size (50MB), extracted size (50MB), or user storage quota (500MB) exceeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/sites":{"get":{"tags":["sites"],"summary":"List Owned Sites","description":"List deployed sites owned exclusively by the authenticated user.\n\n### Access Control & Authorization:\n* **Authentication Required**: Bearer PAT (`hawt_pat_...`) or `X-API-Key`.\n* **Ownership Scoping**: Queries `Site.user_id == current_user.id`. Other users' sites are never returned.","operationId":"list_sites_v1_sites_get","security":[{"HTTPBearer":[]},{"APIKeyHeader":[]}],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"Max sites to return per page (1-100).","default":50,"title":"Limit"},"description":"Max sites to return per page (1-100)."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Pagination offset index.","default":0,"title":"Offset"},"description":"Pagination offset index."},{"name":"Authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Returns paginated list of sites owned exclusively by the caller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SiteListResponse"}}}},"401":{"description":"Unauthorized: Missing, invalid, or expired API token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/sites/{site_id}":{"get":{"tags":["sites"],"summary":"Get Site Metadata","description":"Retrieve metadata and deployment status for a given site.\n\n### Access Control & Authorization:\n* **Authentication Required**: Bearer PAT (`hawt_pat_...`) or `X-API-Key`.\n* **Ownership Verification**: Validates `site_obj.user_id == current_user.id`. Rejects with `403 Forbidden` if caller does not own the site.","operationId":"get_site_v1_sites__site_id__get","security":[{"HTTPBearer":[]},{"APIKeyHeader":[]}],"parameters":[{"name":"site_id","in":"path","required":true,"schema":{"type":"string","title":"Site Id"}},{"name":"Authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Returns site deployment metadata for the site owner.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SiteResponse"}}}},"401":{"description":"Unauthorized: Missing, invalid, or expired API token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden: You do not have permission to view metadata for this site (ownership check failed).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found: Site ID does not exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["sites"],"summary":"Delete Site","description":"Delete a deployed site and all associated disk files.\n\n### Access Control & Authorization:\n* **Authentication Required**: Bearer PAT (`hawt_pat_...`) or `X-API-Key`.\n* **Ownership Verification**: Validates `site_obj.user_id == current_user.id`. Rejects with `403 Forbidden` if caller does not own the site.","operationId":"delete_site_v1_sites__site_id__delete","security":[{"HTTPBearer":[]},{"APIKeyHeader":[]}],"parameters":[{"name":"site_id","in":"path","required":true,"schema":{"type":"string","title":"Site Id"}},{"name":"Authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Site deleted successfully from database and storage disk.","content":{"application/json":{"schema":{}}}},"401":{"description":"Unauthorized: Missing, invalid, or expired API token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden: You do not have permission to delete this site (ownership check failed).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found: Site ID does not exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/health":{"get":{"tags":["health"],"summary":"Health Check","operationId":"health_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}}},"components":{"schemas":{"Body_upload_site_v1_sites_upload_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"},"slug":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Slug","description":"Optional custom site slug or ID."},"path_type":{"type":"string","title":"Path Type","description":"Path scoping mode: 'hawt' (/hawt/<site_id>) or 'user' (/<username>/<site_id>).","default":"hawt"}},"type":"object","required":["file"],"title":"Body_upload_site_v1_sites_upload_post"},"ErrorResponse":{"properties":{"detail":{"type":"string","title":"Detail","description":"Human-readable error explanation describing the authorization or validation failure.","examples":["Invalid or revoked authentication token."]}},"type":"object","required":["detail"],"title":"ErrorResponse"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"InviteCreate":{"properties":{"email":{"anyOf":[{"type":"string","format":"email"},{"type":"null"}],"title":"Email","description":"Optional target email address restriction.","examples":["bob@example.com"]},"note":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Note","description":"Optional administrative descriptor note or label.","examples":["Conference invite for Bob"]},"expires_in_days":{"anyOf":[{"type":"integer","maximum":3650.0,"minimum":1.0},{"type":"null"}],"title":"Expires In Days","description":"Optional expiration lifetime in days. Must be between 1 and 3650. If null or omitted, code does not expire.","examples":[30]}},"type":"object","title":"InviteCreate"},"InviteCreatedResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id","description":"Unique invite record UUID."},"code":{"type":"string","title":"Code","description":"Raw invite token string (`hawt_inv_<32_hex_chars>`)."},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email","description":"Optional target email restriction."},"note":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Note","description":"Administrative note or label."},"is_used":{"type":"boolean","title":"Is Used","description":"Redemption status flag."},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"Invite creation timestamp (UTC)."},"expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Expires At","description":"Optional expiration timestamp (UTC)."},"used_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Used At","description":"Timestamp when the invite code was redeemed (UTC)."},"used_by_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Used By Id","description":"UUID of the user account created upon redemption."}},"type":"object","required":["id","code","is_used","created_at"],"title":"InviteCreatedResponse"},"InviteListResponse":{"properties":{"invites":{"items":{"$ref":"#/components/schemas/InviteResponse"},"type":"array","title":"Invites","description":"List of invite code records matching query filters."},"total":{"type":"integer","title":"Total","description":"Total count of invite codes matching query filters."}},"type":"object","required":["invites","total"],"title":"InviteListResponse"},"InviteResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id","description":"Unique invite record UUID."},"code":{"type":"string","title":"Code","description":"Raw invite token string (`hawt_inv_<32_hex_chars>`)."},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email","description":"Optional target email restriction."},"note":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Note","description":"Administrative note or label."},"is_used":{"type":"boolean","title":"Is Used","description":"Redemption status flag."},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"Invite creation timestamp (UTC)."},"expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Expires At","description":"Optional expiration timestamp (UTC)."},"used_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Used At","description":"Timestamp when the invite code was redeemed (UTC)."},"used_by_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Used By Id","description":"UUID of the user account created upon redemption."}},"type":"object","required":["id","code","is_used","created_at"],"title":"InviteResponse"},"SiteListResponse":{"properties":{"sites":{"items":{"$ref":"#/components/schemas/SiteResponse"},"type":"array","title":"Sites","description":"Paginated list of deployed sites owned by the caller."},"total":{"type":"integer","title":"Total","description":"Total count of active sites owned by the caller."}},"type":"object","required":["sites","total"],"title":"SiteListResponse"},"SiteResponse":{"properties":{"site_id":{"type":"string","title":"Site Id","description":"Unique short site identifier or custom slug."},"owner":{"type":"string","title":"Owner","description":"Username of the user account owning the site."},"path_type":{"type":"string","title":"Path Type","description":"Path scoping type: 'hawt' (shared path) or 'user' (user-scoped namespace path).","default":"hawt"},"url":{"type":"string","title":"Url","description":"Full public URL serving the static site."},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"Deployment timestamp (UTC)."},"expires_at":{"type":"string","format":"date-time","title":"Expires At","description":"Retention expiration timestamp (UTC)."},"file_count":{"type":"integer","title":"File Count","description":"Total count of files stored within the site archive."},"total_size_bytes":{"type":"integer","title":"Total Size Bytes","description":"Total uncompressed byte size of site files on disk."},"status":{"type":"string","title":"Status","description":"Site deployment status ('active').","default":"active"}},"type":"object","required":["site_id","owner","url","created_at","expires_at","file_count","total_size_bytes"],"title":"SiteResponse"},"TokenCreate":{"properties":{"name":{"type":"string","maxLength":64,"title":"Name","description":"Human-readable descriptor label for the token.","default":"default","examples":["deploy-key","laptop-cli"]},"expires_in_days":{"anyOf":[{"type":"integer","maximum":3650.0,"minimum":1.0},{"type":"null"}],"title":"Expires In Days","description":"Optional expiration lifetime in days. If null or omitted, token does not expire.","examples":[30,90]}},"type":"object","title":"TokenCreate"},"TokenCreatedResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id","description":"Unique token UUID identifier."},"name":{"type":"string","title":"Name","description":"Human-readable token label."},"token_prefix":{"type":"string","title":"Token Prefix","description":"Display prefix of the token hash (`hawt_pat_...`)."},"raw_token":{"type":"string","title":"Raw Token","description":"Generated raw secret token (`hawt_pat_<hex>`). Store securely; this secret is never shown again.","examples":["hawt_pat_9f8a7b6c5d4e3f2a1b0c9d8e7f6a5b4c"]},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"Token creation timestamp (UTC)."},"expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Expires At","description":"Token expiration timestamp (UTC), if set."}},"type":"object","required":["id","name","token_prefix","raw_token","created_at"],"title":"TokenCreatedResponse"},"TokenListResponse":{"properties":{"tokens":{"items":{"$ref":"#/components/schemas/TokenResponse"},"type":"array","title":"Tokens","description":"List of API tokens owned by the authenticated user."}},"type":"object","required":["tokens"],"title":"TokenListResponse"},"TokenResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id","description":"Unique token UUID identifier."},"name":{"type":"string","title":"Name","description":"Human-readable token label."},"token_prefix":{"type":"string","title":"Token Prefix","description":"Display prefix of the token hash (`hawt_pat_...`)."},"last_used_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Used At","description":"Timestamp when the token was last used for authentication (UTC)."},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"Token creation timestamp (UTC)."},"expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Expires At","description":"Token expiration timestamp (UTC), if set."}},"type":"object","required":["id","name","token_prefix","created_at"],"title":"TokenResponse"},"UserCreate":{"properties":{"username":{"type":"string","title":"Username","description":"Unique username (3-32 chars, lowercase letters, numbers, hyphens, underscores). System reserved names prohibited.","examples":["alice_dev"]},"email":{"anyOf":[{"type":"string","format":"email"},{"type":"null"}],"title":"Email","description":"Optional unique email address associated with the user account.","examples":["alice@example.com"]},"invite_code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Invite Code","description":"Optional single-use invite token required when public registration is restricted.","examples":["hawt_inv_9f8a7b6c5d4e3f2a1b0c9d8e7f6a5b4c"]}},"type":"object","required":["username"],"title":"UserCreate"},"UserResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id","description":"Unique UUID identifier for the user account."},"username":{"type":"string","title":"Username","description":"Unique account username."},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email","description":"Optional registered email address."},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"Account creation timestamp (UTC)."}},"type":"object","required":["id","username","created_at"],"title":"UserResponse"},"UserWithTokenResponse":{"properties":{"user":{"$ref":"#/components/schemas/UserResponse","description":"Created user profile details."},"api_token":{"type":"string","title":"Api Token","description":"Initial raw API token (`hawt_pat_<hex>`). Store securely; this value is never returned again.","examples":["hawt_pat_9f8a7b6c5d4e3f2a1b0c9d8e7f6a5b4c"]}},"type":"object","required":["user","api_token"],"title":"UserWithTokenResponse"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}},"securitySchemes":{"HTTPBearer":{"type":"http","description":"Personal Access Token (`hawt_pat_<hex>`) passed as `Bearer <token>` in `Authorization` header.","scheme":"bearer"},"APIKeyHeader":{"type":"apiKey","description":"Personal Access Token or Master Admin Secret Key (`HAWT_CLOUD_ADMIN_KEY`) passed in `X-API-Key` header.","in":"header","name":"X-API-Key"}}},"tags":[{"name":"users","description":"User registration and account profile management (`/v1/users`)."},{"name":"admin-invites","description":"Administrative invite code lifecycle management (`/v1/admin/invites`)."},{"name":"tokens","description":"Personal Access Token lifecycle and revocation management (`/v1/tokens`)."},{"name":"sites","description":"Static site asset upload, metadata inspection, listing, and deletion (`/v1/sites`)."},{"name":"health","description":"Service health check endpoint."}]}