{"openapi":"3.0.3","info":{"title":"opn.onl URL Shortener API","description":"A modern, feature-rich URL shortening service with analytics, teams, and real-time updates.\n\n## Authentication\n\nProtected operations take `Authorization: Bearer <token>`. Each operation lists the kinds of token it accepts:\n\n- `bearer_auth`: the session JWT returned by `POST /auth/register`, `POST /auth/login`, and `POST /auth/passkey/login/finish`. Every protected operation accepts it.\n- `api_key`: a personal API key (`opn_...`) created with `POST /auth/api-keys`. Links, folders, tags, organizations, analytics, and the profile accept it. Account security (password, account deletion, passkeys, API keys) and `/admin` require the session JWT.\n\nOperations without a security requirement are public. `POST /links` also works without a token and then creates an anonymous link.\n\n## Rate limits\n\nLimits are counted per client IP address (per /64 for IPv6). A response that passed the limiter carries `X-RateLimit-Limit` and `X-RateLimit-Remaining` for the budget it was charged to. Over a limit, the answer is `429 Too Many Requests` with `Retry-After` (seconds, rounded up), the same two headers, and a `RateLimitResponse` body.\n\n| Budget | Limit | Requests it covers |\n|---|---|---|\n| Burst | 10 per second | Every request except short-link visits (`/{code}`, `/{code}/preview`, `/{code}/verify`), counted in addition to the request's own budget below |\n| Sign-in | 10 per minute | Every `POST` under `/auth/` |\n| Link creation | 100 per hour | `POST /links` and `POST /links/{id}/clone`. `POST /links/bulk` spends one per URL and lists the URLs past the budget in `errors` instead of answering 429 |\n| Contact | 10 per hour | `POST /contact` |\n| Link password | 5 per minute per link, 20 per minute in total | `POST /{code}/verify`, and `GET /{code}` with an `X-Link-Password` header |\n| Redirects | 100 per second | `GET /{code}` and `GET /{code}/preview` |\n| General | 100 per minute | Every other request, including `GET`, `PUT`, and `DELETE` under `/auth/` |\n","contact":{"name":"opn.onl Support","url":"https://opn.onl","email":"support@opn.onl"},"license":{"name":"AGPL-3.0-only","url":"https://www.gnu.org/licenses/agpl-3.0.html"},"version":"1.4.0"},"servers":[{"url":"http://localhost:3000","description":"Local development server"},{"url":"https://l.opn.onl","description":"Hosted opn.onl API"}],"paths":{"/admin/activity":{"get":{"tags":["Admin"],"summary":"Daily signups, link creations, and clicks for the admin overview chart","operationId":"get_admin_activity","parameters":[{"name":"days","in":"query","description":"Days of history, 1-365 (default 30)","required":false,"schema":{"type":"integer","format":"int64","nullable":true,"minimum":0}}],"responses":{"200":{"description":"Per-day activity for the requested window","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminActivityResponse"}}}},"403":{"description":"Admin access required"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]}]}},"/admin/backup":{"get":{"tags":["Admin"],"summary":"List available backups (admin only)","operationId":"list_backups","responses":{"200":{"description":"List of backups","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupListResponse"}}}},"403":{"description":"Admin access required"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"description":"Backup service not configured"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Admin"],"summary":"Create a database backup (admin only)","operationId":"create_backup","responses":{"200":{"description":"Backup created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupResponse"}}}},"403":{"description":"Admin access required"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"description":"Backup failed"},"503":{"description":"Backup service not configured"}},"security":[{"bearer_auth":[]}]}},"/admin/backup/cleanup/{keep_count}":{"delete":{"tags":["Admin"],"summary":"Clean up old backups (admin only)","operationId":"cleanup_backups","parameters":[{"name":"keep_count","in":"path","description":"Number of recent backups to keep","required":true,"schema":{"type":"integer","minimum":0}}],"responses":{"200":{"description":"Old backups cleaned up","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminResponse"}}}},"403":{"description":"Admin access required"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"description":"Backup service not configured"}},"security":[{"bearer_auth":[]}]}},"/admin/blocked/domains":{"get":{"tags":["Admin"],"summary":"Get all blocked domains (admin only)","operationId":"get_blocked_domains","responses":{"200":{"description":"List of blocked domains","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BlockedDomainResponse"}}}}},"403":{"description":"Admin access required"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Admin"],"summary":"Block a domain (admin only)","operationId":"block_domain","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlockDomainRequest"}}},"required":true},"responses":{"201":{"description":"Domain blocked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlockedDomainResponse"}}}},"403":{"description":"Admin access required"},"409":{"description":"Domain already blocked"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]}]}},"/admin/blocked/domains/{id}":{"delete":{"tags":["Admin"],"summary":"Unblock a domain (admin only)","operationId":"unblock_domain","parameters":[{"name":"id","in":"path","description":"Blocked domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Domain unblocked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminResponse"}}}},"403":{"description":"Admin access required"},"404":{"description":"Blocked domain not found"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]}]}},"/admin/blocked/email-domains":{"get":{"tags":["Admin"],"summary":"Get all blocked email domains.","operationId":"get_blocked_email_domains","responses":{"200":{"description":"List of blocked email domains","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BlockedEmailDomainResponse"}}}}},"403":{"description":"Admin access required"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Admin"],"summary":"Block an email domain and disable matching existing users.","operationId":"block_email_domain","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlockEmailDomainRequest"}}},"required":true},"responses":{"201":{"description":"Email domain blocked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlockedEmailDomainResponse"}}}},"400":{"description":"Invalid email domain, or block would disable the acting admin"},"403":{"description":"Admin access required"},"409":{"description":"Email domain already blocked"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]}]}},"/admin/blocked/email-domains/{id}":{"delete":{"tags":["Admin"],"summary":"Unblock an email domain. Existing disabled users are not auto-restored.","operationId":"unblock_email_domain","parameters":[{"name":"id","in":"path","description":"Blocked email domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Email domain unblocked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminResponse"}}}},"403":{"description":"Admin access required"},"404":{"description":"Blocked email domain not found"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]}]}},"/admin/blocked/links":{"get":{"tags":["Admin"],"summary":"Get all blocked links (admin only)","operationId":"get_blocked_links","responses":{"200":{"description":"List of blocked links","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BlockedLinkResponse"}}}}},"403":{"description":"Admin access required"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Admin"],"summary":"Block a URL (admin only)","operationId":"block_link","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlockLinkRequest"}}},"required":true},"responses":{"201":{"description":"URL blocked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlockedLinkResponse"}}}},"403":{"description":"Admin access required"},"409":{"description":"URL already blocked"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]}]}},"/admin/blocked/links/{id}":{"delete":{"tags":["Admin"],"summary":"Unblock a URL (admin only)","operationId":"unblock_link","parameters":[{"name":"id","in":"path","description":"Blocked link ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"URL unblocked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminResponse"}}}},"403":{"description":"Admin access required"},"404":{"description":"Blocked URL not found"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]}]}},"/admin/links":{"get":{"tags":["Admin"],"summary":"List every link in the system, across all users (admin only)","operationId":"get_all_links","parameters":[{"name":"page","in":"query","description":"1-based page number (default 1)","required":false,"schema":{"type":"integer","format":"int64","nullable":true,"minimum":0}},{"name":"per_page","in":"query","description":"Items per page, 1-100 (default 25)","required":false,"schema":{"type":"integer","format":"int64","nullable":true,"minimum":0}},{"name":"search","in":"query","description":"Substring match on code, destination URL, title, or owner email","required":false,"schema":{"type":"string","nullable":true}},{"name":"status","in":"query","description":"Filter: all (default) | live | deleted","required":false,"schema":{"type":"string","nullable":true}},{"name":"user_id","in":"query","description":"Only links belonging to this user","required":false,"schema":{"type":"integer","format":"int32","nullable":true}},{"name":"sort","in":"query","description":"Sort key: created (default) | clicks","required":false,"schema":{"type":"string","nullable":true}},{"name":"order","in":"query","description":"Sort order: desc (default) | asc","required":false,"schema":{"type":"string","nullable":true}},{"name":"suspicious","in":"query","description":"When true, return only links flagged suspicious (dangerous file type or\nraw-IP host). Applied after the DB query since the heuristic is computed\nin Rust.","required":false,"schema":{"type":"boolean","nullable":true}}],"responses":{"200":{"description":"Paginated list of all links with owner info","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminLinksListResponse"}}}},"403":{"description":"Admin access required"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]}]}},"/admin/links/bulk/delete":{"post":{"tags":["Admin"],"summary":"Soft delete many links at once (admin only) — the fast path for clearing an","description":"abuse spree. Invalidates the redirect cache for each affected code.","operationId":"admin_bulk_delete_links","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkLinkIdsRequest"}}},"required":true},"responses":{"200":{"description":"Links deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkLinkActionResponse"}}}},"400":{"description":"No IDs provided"},"403":{"description":"Admin access required"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]}]}},"/admin/links/bulk/restore":{"post":{"tags":["Admin"],"summary":"Restore many soft-deleted links at once (admin only).","operationId":"admin_bulk_restore_links","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkLinkIdsRequest"}}},"required":true},"responses":{"200":{"description":"Links restored","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkLinkActionResponse"}}}},"400":{"description":"No IDs provided"},"403":{"description":"Admin access required"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]}]}},"/admin/links/{link_id}":{"delete":{"tags":["Admin"],"summary":"Soft delete any user's link (admin only)","operationId":"admin_delete_link","parameters":[{"name":"link_id","in":"path","description":"Link ID to soft delete","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Link deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminResponse"}}}},"400":{"description":"Link already deleted"},"403":{"description":"Admin access required"},"404":{"description":"Link not found"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]}]}},"/admin/links/{link_id}/block-domain":{"post":{"tags":["Admin"],"summary":"One-click takedown from the Links tab: block the destination's host (so no","description":"link can point at it again) and soft-delete this link. The host is extracted\nserver-side from the stored URL rather than trusted from the client.","operationId":"admin_block_domain_from_link","parameters":[{"name":"link_id","in":"path","description":"Link whose destination host to block","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Domain blocked and link deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlockFromLinkResponse"}}}},"400":{"description":"Link has no usable host"},"403":{"description":"Admin access required"},"404":{"description":"Link not found"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]}]}},"/admin/links/{link_id}/restore":{"post":{"tags":["Admin"],"summary":"Restore a soft-deleted link (admin only)","operationId":"admin_restore_link","parameters":[{"name":"link_id","in":"path","description":"Link ID to restore","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Link restored","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminResponse"}}}},"400":{"description":"Link is not deleted"},"403":{"description":"Admin access required"},"404":{"description":"Link not found"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]}]}},"/admin/orgs":{"get":{"tags":["Admin"],"summary":"List every organization with owner and member counts (admin only)","operationId":"get_all_orgs","parameters":[{"name":"page","in":"query","description":"1-based page number (default 1)","required":false,"schema":{"type":"integer","format":"int64","nullable":true,"minimum":0}},{"name":"per_page","in":"query","description":"Items per page, 1-100 (default 25)","required":false,"schema":{"type":"integer","format":"int64","nullable":true,"minimum":0}},{"name":"search","in":"query","description":"Substring match on org name or slug","required":false,"schema":{"type":"string","nullable":true}}],"responses":{"200":{"description":"Paginated list of all organizations","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminOrgsListResponse"}}}},"403":{"description":"Admin access required"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]}]}},"/admin/stats":{"get":{"tags":["Admin"],"summary":"Get admin dashboard stats","operationId":"get_admin_stats","responses":{"200":{"description":"Admin stats","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminStatsResponse"}}}},"403":{"description":"Admin access required"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]}]}},"/admin/users":{"get":{"tags":["Admin"],"summary":"Get all users with per-user aggregates (admin only)","operationId":"get_all_users","parameters":[{"name":"page","in":"query","description":"1-based page number (default 1)","required":false,"schema":{"type":"integer","format":"int64","nullable":true,"minimum":0}},{"name":"per_page","in":"query","description":"Items per page, 1-100 (default 25)","required":false,"schema":{"type":"integer","format":"int64","nullable":true,"minimum":0}},{"name":"search","in":"query","description":"Substring match on email, display name, or bio username","required":false,"schema":{"type":"string","nullable":true}},{"name":"status","in":"query","description":"Filter: all (default) | active | deleted | disabled | admins | unverified","required":false,"schema":{"type":"string","nullable":true}},{"name":"order","in":"query","description":"Sort order for created_at: desc (default) | asc","required":false,"schema":{"type":"string","nullable":true}}],"responses":{"200":{"description":"Paginated list of users with link/click aggregates","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminUsersListResponse"}}}},"403":{"description":"Admin access required"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]}]}},"/admin/users/{user_id}":{"delete":{"tags":["Admin"],"summary":"Soft delete a user (admin only)","operationId":"delete_user","parameters":[{"name":"user_id","in":"path","description":"User ID to delete","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"User deleted successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminResponse"}}}},"403":{"description":"Admin access required"},"404":{"description":"User not found"},"409":{"description":"User still owns organizations with other members"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]}]}},"/admin/users/{user_id}/enable":{"post":{"tags":["Admin"],"summary":"Re-enable a disabled user after the relevant email-domain block has been removed.","operationId":"enable_user","parameters":[{"name":"user_id","in":"path","description":"User ID to enable","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"User enabled successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminResponse"}}}},"400":{"description":"User is deleted or not disabled"},"403":{"description":"Admin access required"},"404":{"description":"User not found"},"409":{"description":"User email domain remains blocked"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]}]}},"/admin/users/{user_id}/hard":{"delete":{"tags":["Admin"],"summary":"Hard delete a user (admin only, use with caution)","operationId":"hard_delete_user","parameters":[{"name":"user_id","in":"path","description":"User ID to permanently delete","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"User permanently deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminResponse"}}}},"403":{"description":"Admin access required"},"404":{"description":"User not found"},"409":{"description":"User still owns organizations with other members"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]}]}},"/admin/users/{user_id}/make-admin":{"post":{"tags":["Admin"],"summary":"Make a user an admin (admin only)","operationId":"make_admin","parameters":[{"name":"user_id","in":"path","description":"User ID to make admin","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"User is now admin","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminResponse"}}}},"403":{"description":"Admin access required"},"404":{"description":"User not found"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]}]}},"/admin/users/{user_id}/remove-admin":{"post":{"tags":["Admin"],"summary":"Remove admin status from a user (admin only)","operationId":"remove_admin","parameters":[{"name":"user_id","in":"path","description":"User ID to remove admin from","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Admin status removed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminResponse"}}}},"403":{"description":"Admin access required or cannot demote self"},"404":{"description":"User not found"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]}]}},"/admin/users/{user_id}/restore":{"post":{"tags":["Admin"],"summary":"Restore a soft-deleted user (admin only)","operationId":"restore_user","parameters":[{"name":"user_id","in":"path","description":"User ID to restore","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"User restored successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminResponse"}}}},"400":{"description":"User is not deleted"},"403":{"description":"Admin access required"},"404":{"description":"User not found"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]}]}},"/admin/users/{user_id}/verify-email":{"post":{"tags":["Admin"],"summary":"Force-verify a user's email (admin only)","operationId":"admin_verify_email","parameters":[{"name":"user_id","in":"path","description":"User ID to verify","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Email marked verified","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminResponse"}}}},"400":{"description":"Email already verified"},"403":{"description":"Admin access required"},"404":{"description":"User not found"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]}]}},"/analytics/dashboard":{"get":{"tags":["Analytics"],"summary":"Get dashboard analytics","operationId":"get_dashboard_stats","responses":{"200":{"description":"Dashboard statistics. clicks_today is the UTC calendar day.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DashboardStats"}}}},"401":{"description":"Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]},{"api_key":[]}]}},"/api/bio/avatar":{"get":{"tags":["Bio"],"summary":"Proxy a public-bio avatar image through the server so a bio VISITOR's browser","description":"only ever connects to this origin — the external avatar host never learns the\nvisitor's IP (the link-in-bio privacy leak). The fetch is SSRF-guarded\n(validated + DNS-pinned, redirects re-validated), restricted to successful\nhttp(s) responses carrying an allowed raster image type, and size-capped.\n\nThe URL must also be the `avatar_url` of a non-deleted user whose bio is\npublic. Otherwise this route is an open fetch.","operationId":"proxy_bio_avatar","parameters":[{"name":"url","in":"query","description":"External http(s) avatar URL to fetch through this origin.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Proxied raster avatar bytes"},"400":{"description":"Invalid avatar URL"},"404":{"description":"URL is not the avatar of a public bio"},"415":{"description":"Avatar is not a supported image type"},"429":{"$ref":"#/components/responses/TooManyRequests"},"502":{"description":"Could not fetch avatar"}}}},"/api/bio/{username}":{"get":{"tags":["Bio"],"summary":"Public bio page data. Returns 404 unless the instance flag AND the user's","description":"`bio_enabled` are both on (and the user isn't deleted) — 404 rather than 403\nso a disabled page never reveals whether a username exists.","operationId":"get_public_bio","parameters":[{"name":"username","in":"path","description":"Public bio username","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Public bio profile and visible active links (click counts are omitted)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BioProfileResponse"}}}},"404":{"description":"No public bio for this username"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/auth/api-keys":{"get":{"tags":["Authentication"],"summary":"List the caller's API keys (never returns the secret).","operationId":"list_api_keys","responses":{"200":{"description":"The caller's API keys (secrets never returned)","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ApiKeyInfo"}}}}},"401":{"description":"Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Authentication"],"summary":"Create a new personal API key. The full key is returned once.","operationId":"create_api_key","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateApiKeyRequest"}}},"required":true},"responses":{"201":{"description":"API key created; the full secret is returned once","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateApiKeyResponse"}}}},"400":{"description":"API key limit reached"},"401":{"description":"Unauthorized"},"403":{"description":"API keys are disabled on this instance"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]}]}},"/auth/api-keys/{id}":{"delete":{"tags":["Authentication"],"summary":"Revoke (delete) one of the caller's API keys.","operationId":"delete_api_key","parameters":[{"name":"id","in":"path","description":"API key id to revoke","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"API key revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"API key not found"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]}]}},"/auth/bio":{"put":{"tags":["Authentication"],"summary":"Update the caller's link-in-bio settings (username, enabled, theme).","operationId":"update_bio_settings","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BioSettingsRequest"}}},"required":true},"responses":{"200":{"description":"Updated bio settings","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BioSettingsResponse"}}}},"400":{"description":"Invalid username or bio enabled without a username"},"401":{"description":"Unauthorized"},"403":{"description":"Link-in-bio is not enabled on this instance"},"404":{"description":"User not found"},"409":{"description":"Username is taken"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]},{"api_key":[]}]}},"/auth/change-password":{"post":{"tags":["Authentication"],"summary":"Change password for authenticated user","operationId":"change_password","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangePasswordRequest"}}},"required":true},"responses":{"200":{"description":"Password changed successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}},"400":{"description":"Invalid request or wrong current password"},"401":{"description":"Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]}]}},"/auth/delete-account":{"post":{"tags":["Authentication"],"summary":"Delete own account (self-service, if enabled)","operationId":"delete_account","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteAccountRequest"}}},"required":true},"responses":{"200":{"description":"Account deleted successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}},"400":{"description":"Invalid request or wrong password"},"401":{"description":"Unauthorized"},"403":{"description":"Account deletion is disabled"},"409":{"description":"User still owns organizations with other members; transfer ownership first"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]}]}},"/auth/forgot-password":{"post":{"tags":["Authentication"],"summary":"Request password reset","operationId":"forgot_password","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForgotPasswordRequest"}}},"required":true},"responses":{"200":{"description":"Reset email sent if account exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/auth/login":{"post":{"tags":["Authentication"],"summary":"Login with email and password","operationId":"login","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginRequest"}}},"required":true},"responses":{"200":{"description":"Login successful","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthResponse"}}}},"401":{"description":"Invalid credentials"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/auth/me":{"get":{"tags":["Authentication"],"summary":"Get current user profile","operationId":"get_current_user","responses":{"200":{"description":"User profile","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserProfileResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"User not found"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]},{"api_key":[]}]}},"/auth/passkey/delete":{"post":{"tags":["Authentication"],"summary":"Delete a passkey","operationId":"delete_passkey","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeletePasskeyRequest"}}},"required":true},"responses":{"200":{"description":"Passkey deleted"},"400":{"description":"Cannot delete the account's only login method"},"401":{"description":"Unauthorized"},"404":{"description":"Passkey not found"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]}]}},"/auth/passkey/login/finish":{"post":{"tags":["Authentication"],"summary":"Complete passkey login and issue a JWT on success.","operationId":"login_finish","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginFinishRequest"}}},"required":true},"responses":{"200":{"description":"Authenticated; JWT issued","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PasskeyAuthResponse"}}}},"400":{"description":"Invalid or expired assertion"},"401":{"description":"Assertion did not verify"},"403":{"description":"Passkeys are disabled on this instance"},"404":{"description":"User not found"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/auth/passkey/login/start":{"post":{"tags":["Authentication"],"summary":"Begin passkey login. Returns a WebAuthn `RequestChallengeResponse`.","description":"Unknown users, disabled users, and users without passkeys receive the same\n200 challenge shape as a real account; pending state is stored only when\nthe account exists and has parseable passkeys.","operationId":"login_start","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginStartRequest"}}},"required":true},"responses":{"200":{"description":"WebAuthn assertion challenge"},"403":{"description":"Passkeys are disabled on this instance"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/auth/passkey/register/finish":{"post":{"tags":["Authentication"],"summary":"Complete passkey enrollment for the authenticated caller. Rejects a","description":"credential already registered to any account (409).","operationId":"register_finish","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterFinishRequest"}}},"required":true},"responses":{"200":{"description":"Passkey registered","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}},"400":{"description":"Invalid or expired registration ceremony"},"401":{"description":"Unauthorized"},"403":{"description":"Passkeys are disabled on this instance"},"404":{"description":"User not found"},"409":{"description":"This passkey is already registered"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]}]}},"/auth/passkey/register/start":{"post":{"tags":["Authentication"],"summary":"Begin passkey enrollment for the authenticated caller. Returns a WebAuthn","description":"`CreationChallengeResponse` to pass to the browser's credential API. The\nresponse is a standard WebAuthn ceremony object and is not expanded into\nthe schema.","operationId":"register_start","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterStartRequest"}}},"required":true},"responses":{"200":{"description":"WebAuthn creation challenge"},"401":{"description":"Unauthorized"},"403":{"description":"Passkeys are disabled on this instance"},"404":{"description":"User not found"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]}]}},"/auth/passkey/rename":{"post":{"tags":["Authentication"],"summary":"Rename a passkey","operationId":"rename_passkey","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RenamePasskeyRequest"}}},"required":true},"responses":{"200":{"description":"Passkey renamed"},"401":{"description":"Unauthorized"},"404":{"description":"Passkey not found"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]}]}},"/auth/passkeys":{"get":{"tags":["Authentication"],"summary":"List user's passkeys","operationId":"list_passkeys","responses":{"200":{"description":"The caller's registered passkeys","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PasskeyListResponse"}}}},"401":{"description":"Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]}]}},"/auth/profile":{"put":{"tags":["Authentication"],"summary":"Update user profile","operationId":"update_profile","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProfileRequest"}}},"required":true},"responses":{"200":{"description":"Profile updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserProfileResponse"}}}},"400":{"description":"Invalid bio, website, or avatar URL"},"401":{"description":"Unauthorized"},"404":{"description":"User not found"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]},{"api_key":[]}]}},"/auth/register":{"post":{"tags":["Authentication"],"summary":"Register a new user","operationId":"register","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterRequest"}}},"required":true},"responses":{"201":{"description":"User registered successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthResponse"}}}},"400":{"description":"Invalid request"},"409":{"description":"Email already exists"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/auth/resend-verification":{"post":{"tags":["Authentication"],"summary":"Resend verification email","operationId":"resend_verification","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResendVerificationRequest"}}},"required":true},"responses":{"200":{"description":"Verification email sent if an unverified account exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}},"400":{"description":"Email domain is not allowed"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/auth/reset-password":{"post":{"tags":["Authentication"],"summary":"Reset password with token","operationId":"reset_password","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResetPasswordRequest"}}},"required":true},"responses":{"200":{"description":"Password reset successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}},"400":{"description":"Invalid or expired token"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/auth/settings":{"get":{"tags":["Authentication"],"summary":"Get app settings","operationId":"get_app_settings","responses":{"200":{"description":"App settings","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppSettingsResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/auth/verify-email":{"post":{"tags":["Authentication"],"summary":"Verify email with token","operationId":"verify_email","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyEmailRequest"}}},"required":true},"responses":{"200":{"description":"Email verified successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}},"400":{"description":"Invalid or expired token"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/contact":{"post":{"tags":["Contact"],"summary":"Send a contact form message to admin","operationId":"send_contact_message","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactRequest"}}},"required":true},"responses":{"200":{"description":"Message sent successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactResponse"}}}},"400":{"description":"Validation error"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"description":"Failed to send message"},"503":{"description":"Email is not configured on this instance; nothing was sent"}}}},"/folders":{"get":{"tags":["Folders"],"summary":"Get user's folders","operationId":"get_folders","parameters":[{"name":"org_id","in":"query","required":false,"schema":{"type":"integer","format":"int32","nullable":true}}],"responses":{"200":{"description":"List of folders","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/FolderResponse"}}}}},"401":{"description":"Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]},{"api_key":[]}]},"post":{"tags":["Folders"],"summary":"Create a new folder","operationId":"create_folder","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFolderRequest"}}},"required":true},"responses":{"201":{"description":"Folder created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FolderResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions to create an organization folder"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]},{"api_key":[]}]}},"/folders/{folder_id}":{"get":{"tags":["Folders"],"summary":"Get folder by ID","operationId":"get_folder","parameters":[{"name":"folder_id","in":"path","description":"Folder ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Folder details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FolderResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]},{"api_key":[]}]},"put":{"tags":["Folders"],"summary":"Update folder","operationId":"update_folder","parameters":[{"name":"folder_id","in":"path","description":"Folder ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateFolderRequest"}}},"required":true},"responses":{"200":{"description":"Folder updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FolderResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]},{"api_key":[]}]},"delete":{"tags":["Folders"],"summary":"Delete folder","operationId":"delete_folder","parameters":[{"name":"folder_id","in":"path","description":"Folder ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Folder deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]},{"api_key":[]}]}},"/folders/{folder_id}/links":{"get":{"tags":["Folders"],"summary":"Get links in folder","operationId":"get_folder_links","parameters":[{"name":"folder_id","in":"path","description":"Folder ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Non-deleted links in folder"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Folder not found"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]},{"api_key":[]}]},"post":{"tags":["Folders"],"summary":"Move links to folder","operationId":"move_links_to_folder","parameters":[{"name":"folder_id","in":"path","description":"Folder ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MoveLinkToFolderRequest"}}},"required":true},"responses":{"200":{"description":"Links moved (`{\"moved\": N}`)"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Folder not found"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]},{"api_key":[]}]}},"/links":{"get":{"tags":["Links"],"summary":"Get user's links with filtering","operationId":"get_user_links","parameters":[{"name":"folder_id","in":"query","required":false,"schema":{"type":"integer","format":"int32","nullable":true}},{"name":"org_id","in":"query","required":false,"schema":{"type":"integer","format":"int32","nullable":true}},{"name":"tag_id","in":"query","required":false,"schema":{"type":"integer","format":"int32","nullable":true}},{"name":"search","in":"query","required":false,"schema":{"type":"string","nullable":true}},{"name":"limit","in":"query","description":"Page size. Omitted or 0 defaults to 1000. Maximum 1000.","required":false,"schema":{"type":"integer","format":"int64","nullable":true,"minimum":0}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","format":"int64","nullable":true,"minimum":0}}],"responses":{"200":{"description":"The caller's non-deleted links (limit defaults to 1000, maximum 1000)","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/LinkResponse"}}}}},"401":{"description":"Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]},{"api_key":[]}]},"post":{"tags":["Links"],"summary":"Create a new shortened link","description":"Credentials are optional. Without them the link is anonymous and cannot be\nput in a folder, tagged, or owned by an organization. An account can shorten\nthe same URL at most 10 times in 10 minutes; the next request is answered\n429 with only an `error` field and no `Retry-After`.","operationId":"create_link","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateLinkRequest"}}},"required":true},"responses":{"201":{"description":"Link created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LinkResponse"}}}},"400":{"description":"Invalid request"},"403":{"description":"Email unverified, link cap reached, URL blocked, or custom aliases disabled"},"409":{"description":"Alias already exists"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{},{"bearer_auth":[]},{"api_key":[]}]}},"/links/build-utm":{"post":{"tags":["Links"],"summary":"Build URL with UTM parameters","operationId":"build_utm_url","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BuildUtmRequest"}}},"required":true},"responses":{"200":{"description":"UTM URL built","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BuildUtmResponse"}}}},"400":{"description":"Invalid URL"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/links/bulk":{"post":{"tags":["Links"],"summary":"Bulk create links","operationId":"bulk_create_links","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkCreateLinkRequest"}}},"required":true},"responses":{"200":{"description":"Links created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkCreateLinkResponse"}}}},"400":{"description":"Batch too large"},"401":{"description":"Authentication required"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]},{"api_key":[]}]}},"/links/bulk/delete":{"post":{"tags":["Links"],"summary":"Bulk delete links","operationId":"bulk_delete_links","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkDeleteRequest"}}},"required":true},"responses":{"200":{"description":"Links deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkDeleteResponse"}}}},"401":{"description":"Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]},{"api_key":[]}]}},"/links/bulk/update":{"post":{"tags":["Links"],"summary":"Bulk update links","operationId":"bulk_update_links","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkUpdateRequest"}}},"required":true},"responses":{"200":{"description":"Links updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkUpdateResponse"}}}},"401":{"description":"Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]},{"api_key":[]}]}},"/links/check-code":{"get":{"tags":["Links"],"summary":"Check if a custom alias/code is available","operationId":"check_code_availability","parameters":[{"name":"code","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Code availability checked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckCodeResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/links/export":{"get":{"tags":["Links"],"summary":"Export links to CSV","operationId":"export_links_csv","responses":{"200":{"description":"CSV file"},"401":{"description":"Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]},{"api_key":[]}]}},"/links/health-check":{"post":{"tags":["Links"],"summary":"Check if a URL is reachable","operationId":"check_url_health","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthCheckRequest"}}},"required":true},"responses":{"200":{"description":"URL health checked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UrlHealthResponse"}}}},"400":{"description":"Invalid URL"},"401":{"description":"Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]},{"api_key":[]}]}},"/links/preview-metadata":{"post":{"tags":["Links"],"summary":"Fetch Open Graph preview data for a URL","operationId":"get_link_preview_metadata","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreviewMetadataRequest"}}},"required":true},"responses":{"200":{"description":"Link preview data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LinkPreviewData"}}}},"400":{"description":"Invalid URL"},"401":{"description":"Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]},{"api_key":[]}]}},"/links/sparklines":{"get":{"tags":["Links"],"summary":"Get sparkline data (last 7 days) for multiple links","operationId":"get_sparklines","parameters":[{"name":"ids","in":"query","description":"Comma-separated link IDs","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sparkline data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SparklineResponse"}}}},"401":{"description":"Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]},{"api_key":[]}]}},"/links/{id}":{"put":{"tags":["Links"],"summary":"Update a link","operationId":"update_link","parameters":[{"name":"id","in":"path","description":"Link ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateLinkRequest"}}},"required":true},"responses":{"200":{"description":"Link updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LinkResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]},{"api_key":[]}]},"delete":{"tags":["Links"],"summary":"Delete a link","operationId":"delete_link","parameters":[{"name":"id","in":"path","description":"Link ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Link deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]},{"api_key":[]}]}},"/links/{id}/clicks/realtime":{"get":{"tags":["Analytics"],"summary":"Get real-time click count for a link","operationId":"get_realtime_clicks","parameters":[{"name":"id","in":"path","description":"Link ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Current click count"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Link not found"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]},{"api_key":[]}]}},"/links/{id}/clone":{"post":{"tags":["Links"],"summary":"Clone an existing link with a new short code","operationId":"clone_link","parameters":[{"name":"id","in":"path","description":"Link ID to clone","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"201":{"description":"Link cloned","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CloneLinkResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Link not found"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]},{"api_key":[]}]}},"/links/{id}/pin":{"post":{"tags":["Links"],"summary":"Toggle pin status for a link","operationId":"toggle_pin","parameters":[{"name":"id","in":"path","description":"Link ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Pin status toggled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PinResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Link not found"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]},{"api_key":[]}]}},"/links/{id}/qr":{"get":{"tags":["Links"],"summary":"Get QR code for a link","operationId":"get_qr_code","parameters":[{"name":"id","in":"path","description":"Link ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"QR code image"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Link not found"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]},{"api_key":[]}]}},"/links/{id}/rules":{"get":{"tags":["Links"],"summary":"List the routing rules for a link.","operationId":"get_routing_rules","parameters":[{"name":"id","in":"path","description":"Link ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Routing rules for the link","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RoutingRuleResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]},{"api_key":[]}]},"put":{"tags":["Links"],"summary":"Replace all routing rules for a link (delete-then-insert in a transaction).","operationId":"replace_routing_rules","parameters":[{"name":"id","in":"path","description":"Link ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReplaceRoutingRulesRequest"}}},"required":true},"responses":{"200":{"description":"Routing rules replaced","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoutingRulesSavedResponse"}}}},"400":{"description":"Too many rules, or a destination URL is invalid or blocked"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]},{"api_key":[]}]}},"/links/{id}/stats":{"get":{"tags":["Analytics"],"summary":"Get detailed stats for a specific link","operationId":"get_link_stats","parameters":[{"name":"id","in":"path","description":"Link ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"days","in":"query","description":"Stats window in days. Omitted defaults to 30; values are clamped to 1..=366.","required":false,"schema":{"type":"integer","format":"int64","nullable":true}}],"responses":{"200":{"description":"Link statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LinkStatsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]},{"api_key":[]}]}},"/links/{id}/tags":{"post":{"tags":["Tags"],"summary":"Add tags to a link","operationId":"add_tags_to_link","parameters":[{"name":"id","in":"path","description":"Link ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddTagsToLinkRequest"}}},"required":true},"responses":{"200":{"description":"Tags added (`{\"added\": N}`)"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Link not found"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]},{"api_key":[]}]},"delete":{"tags":["Tags"],"summary":"Remove tags from a link","operationId":"remove_tags_from_link","parameters":[{"name":"id","in":"path","description":"Link ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RemoveTagsFromLinkRequest"}}},"required":true},"responses":{"200":{"description":"Tags removed (`{\"removed\": N}`)"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Link not found"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]},{"api_key":[]}]}},"/orgs":{"get":{"tags":["Organizations"],"summary":"Get user's organizations","operationId":"get_user_organizations","responses":{"200":{"description":"List of organizations","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OrgResponse"}}}}},"401":{"description":"Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]},{"api_key":[]}]},"post":{"tags":["Organizations"],"summary":"Create a new organization","operationId":"create_organization","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOrgRequest"}}},"required":true},"responses":{"201":{"description":"Organization created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"409":{"description":"Slug already exists"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]},{"api_key":[]}]}},"/orgs/{org_id}":{"get":{"tags":["Organizations"],"summary":"Get organization by ID","operationId":"get_organization","parameters":[{"name":"org_id","in":"path","description":"Organization ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Organization details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]},{"api_key":[]}]},"put":{"tags":["Organizations"],"summary":"Update organization","operationId":"update_organization","parameters":[{"name":"org_id","in":"path","description":"Organization ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateOrgRequest"}}},"required":true},"responses":{"200":{"description":"Organization updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"409":{"description":"Slug already exists"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]},{"api_key":[]}]},"delete":{"tags":["Organizations"],"summary":"Delete organization","operationId":"delete_organization","parameters":[{"name":"org_id","in":"path","description":"Organization ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Organization deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]},{"api_key":[]}]}},"/orgs/{org_id}/audit":{"get":{"tags":["Organizations"],"summary":"Get organization audit log","operationId":"get_audit_log","parameters":[{"name":"org_id","in":"path","description":"Organization ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"limit","in":"query","description":"Newest-first page size. Omitted or 0 defaults to 200. Maximum 500.","required":false,"schema":{"type":"integer","format":"int64","nullable":true,"minimum":0}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","format":"int64","nullable":true,"minimum":0}}],"responses":{"200":{"description":"Audit log entries (newest first, default 200, maximum 500)","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AuditLogResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]},{"api_key":[]}]}},"/orgs/{org_id}/members":{"get":{"tags":["Organizations"],"summary":"Get organization members","operationId":"get_organization_members","parameters":[{"name":"org_id","in":"path","description":"Organization ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of members","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OrgMemberResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]},{"api_key":[]}]},"post":{"tags":["Organizations"],"summary":"Invite member to organization","operationId":"invite_member","parameters":[{"name":"org_id","in":"path","description":"Organization ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InviteMemberRequest"}}},"required":true},"responses":{"201":{"description":"Member invited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgMemberResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"User not found"},"409":{"description":"Already a member"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]},{"api_key":[]}]}},"/orgs/{org_id}/members/{member_id}":{"put":{"tags":["Organizations"],"summary":"Update member role","operationId":"update_member_role","parameters":[{"name":"org_id","in":"path","description":"Organization ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"member_id","in":"path","description":"Member ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMemberRoleRequest"}}},"required":true},"responses":{"200":{"description":"Member role updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgMemberResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Member not found"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]},{"api_key":[]}]},"delete":{"tags":["Organizations"],"summary":"Remove member from organization","operationId":"remove_member","parameters":[{"name":"org_id","in":"path","description":"Organization ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"member_id","in":"path","description":"Member ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Member removed"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Member not found"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]},{"api_key":[]}]}},"/orgs/{org_id}/transfer-ownership":{"post":{"tags":["Organizations"],"summary":"Transfer organization ownership to another member","operationId":"transfer_ownership","parameters":[{"name":"org_id","in":"path","description":"Organization ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransferOwnershipRequest"}}},"required":true},"responses":{"200":{"description":"Ownership transferred","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgResponse"}}}},"400":{"description":"Invalid target (self, deleted user, or not a member)"},"401":{"description":"Unauthorized"},"403":{"description":"Only the owner can transfer ownership"},"404":{"description":"Organization or member not found"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]},{"api_key":[]}]}},"/tags":{"get":{"tags":["Tags"],"summary":"Get user's tags","operationId":"get_tags","parameters":[{"name":"org_id","in":"query","required":false,"schema":{"type":"integer","format":"int32","nullable":true}}],"responses":{"200":{"description":"List of tags","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TagResponse"}}}}},"401":{"description":"Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]},{"api_key":[]}]},"post":{"tags":["Tags"],"summary":"Create a new tag","operationId":"create_tag","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTagRequest"}}},"required":true},"responses":{"201":{"description":"Tag created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TagResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]},{"api_key":[]}]}},"/tags/{tag_id}":{"get":{"tags":["Tags"],"summary":"Get tag by ID","operationId":"get_tag","parameters":[{"name":"tag_id","in":"path","description":"Tag ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Tag details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TagResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]},{"api_key":[]}]},"put":{"tags":["Tags"],"summary":"Update tag","operationId":"update_tag","parameters":[{"name":"tag_id","in":"path","description":"Tag ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTagRequest"}}},"required":true},"responses":{"200":{"description":"Tag updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TagResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]},{"api_key":[]}]},"delete":{"tags":["Tags"],"summary":"Delete tag","operationId":"delete_tag","parameters":[{"name":"tag_id","in":"path","description":"Tag ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Tag deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]},{"api_key":[]}]}},"/tags/{tag_id}/links":{"get":{"tags":["Tags"],"summary":"Get links by tag","operationId":"get_links_by_tag","parameters":[{"name":"tag_id","in":"path","description":"Tag ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Non-deleted links with this tag"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Tag not found"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"bearer_auth":[]},{"api_key":[]}]}},"/{code}":{"get":{"tags":["Links"],"operationId":"redirect_link","parameters":[{"name":"code","in":"path","description":"Short link code","required":true,"schema":{"type":"string"}}],"responses":{"307":{"description":"Redirect to original URL"},"401":{"description":"Password required"},"404":{"description":"Link not found"},"410":{"description":"Link expired or inactive"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/{code}/preview":{"get":{"tags":["Links"],"summary":"Get link preview (add + to any short link URL to see preview)","operationId":"preview_link","parameters":[{"name":"code","in":"path","description":"Short link code","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Link preview","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LinkPreviewResponse"}}}},"404":{"description":"Link not found"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/{code}/verify":{"post":{"tags":["Links"],"summary":"Verify password for protected link","operationId":"verify_link_password","parameters":[{"name":"code","in":"path","description":"Short link code","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyPasswordRequest"}}},"required":true},"responses":{"200":{"description":"Password verified"},"401":{"description":"Invalid password"},"404":{"description":"Link not found"},"410":{"description":"Link expired"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}}},"components":{"schemas":{"ActivityDay":{"type":"object","required":["date","new_users","new_links","clicks"],"properties":{"clicks":{"type":"integer","format":"int64"},"date":{"type":"string"},"new_links":{"type":"integer","format":"int64"},"new_users":{"type":"integer","format":"int64"}}},"AddTagsToLinkRequest":{"type":"object","required":["tag_ids"],"properties":{"tag_ids":{"type":"array","items":{"type":"integer","format":"int32"},"description":"Tag IDs to attach. At most 50 are considered; duplicates are ignored."}}},"AdminActivityResponse":{"type":"object","required":["days"],"properties":{"days":{"type":"array","items":{"$ref":"#/components/schemas/ActivityDay"}}}},"AdminLinkResponse":{"type":"object","required":["id","code","original_url","click_count","created_at","is_pinned","burn_after_reading","safe_link_interstitial","bio_visible","has_password","is_active","suspicious"],"properties":{"bio_visible":{"type":"boolean"},"burn_after_reading":{"type":"boolean"},"burned_at":{"type":"string","nullable":true},"click_count":{"type":"integer","format":"int64"},"code":{"type":"string"},"created_at":{"type":"string"},"deleted_at":{"type":"string","nullable":true},"expires_at":{"type":"string","nullable":true},"folder_id":{"type":"integer","format":"int32","nullable":true},"has_password":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"inactive_reason":{"type":"string","nullable":true},"is_active":{"type":"boolean"},"is_pinned":{"type":"boolean"},"max_clicks":{"type":"integer","format":"int32","nullable":true},"org_id":{"type":"integer","format":"int32","nullable":true},"original_url":{"type":"string"},"safe_link_interstitial":{"type":"boolean"},"starts_at":{"type":"string","nullable":true},"suspicion_reason":{"type":"string","description":"Human-readable reason the link is flagged, when `suspicious`.","nullable":true},"suspicious":{"type":"boolean","description":"True when the destination trips an abuse heuristic (dangerous file type\nor raw-IP host). Computed live, independent of the creation-time guard."},"title":{"type":"string","nullable":true},"user_email":{"type":"string","nullable":true},"user_id":{"type":"integer","format":"int32","nullable":true}}},"AdminLinksListResponse":{"type":"object","required":["links","total","page","per_page"],"properties":{"links":{"type":"array","items":{"$ref":"#/components/schemas/AdminLinkResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"per_page":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"AdminOrgResponse":{"type":"object","required":["id","name","slug","owner_id","member_count","links_count","created_at"],"properties":{"created_at":{"type":"string"},"id":{"type":"integer","format":"int32"},"links_count":{"type":"integer","format":"int64"},"member_count":{"type":"integer","format":"int64"},"name":{"type":"string"},"owner_email":{"type":"string","nullable":true},"owner_id":{"type":"integer","format":"int32"},"slug":{"type":"string"}}},"AdminOrgsListResponse":{"type":"object","required":["orgs","total","page","per_page"],"properties":{"orgs":{"type":"array","items":{"$ref":"#/components/schemas/AdminOrgResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"per_page":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"AdminResponse":{"type":"object","required":["success","message"],"properties":{"message":{"type":"string"},"success":{"type":"boolean"}}},"AdminStatsResponse":{"type":"object","required":["total_users","active_users","verified_users","admin_users","total_links","active_links","total_clicks","total_orgs","users_today","links_today","clicks_today","blocked_links_count","blocked_domains_count","blocked_email_domains_count","disabled_users_count","suspicious_links_count"],"properties":{"active_links":{"type":"integer","format":"int64"},"active_users":{"type":"integer","format":"int64"},"admin_users":{"type":"integer","format":"int64"},"blocked_domains_count":{"type":"integer","format":"int64"},"blocked_email_domains_count":{"type":"integer","format":"int64"},"blocked_links_count":{"type":"integer","format":"int64"},"clicks_today":{"type":"integer","format":"int64"},"disabled_users_count":{"type":"integer","format":"int64"},"links_today":{"type":"integer","format":"int64"},"suspicious_links_count":{"type":"integer","format":"int64","description":"Live (non-deleted) links whose destination trips the abuse heuristic."},"total_clicks":{"type":"integer","format":"int64"},"total_links":{"type":"integer","format":"int64"},"total_orgs":{"type":"integer","format":"int64"},"total_users":{"type":"integer","format":"int64"},"users_today":{"type":"integer","format":"int64"},"verified_users":{"type":"integer","format":"int64"}}},"AdminUserResponse":{"type":"object","required":["id","email","is_admin","email_verified","created_at","bio_enabled","links_count","total_clicks","api_keys_count","passkeys_count","orgs_owned"],"properties":{"api_keys_count":{"type":"integer","format":"int64"},"bio_enabled":{"type":"boolean"},"bio_username":{"type":"string","nullable":true},"created_at":{"type":"string"},"deleted_at":{"type":"string","nullable":true},"disabled_at":{"type":"string","nullable":true},"disabled_by":{"type":"integer","format":"int32","nullable":true},"disabled_reason":{"type":"string","nullable":true},"display_name":{"type":"string","nullable":true},"email":{"type":"string"},"email_verified":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"is_admin":{"type":"boolean"},"links_count":{"type":"integer","format":"int64"},"orgs_owned":{"type":"integer","format":"int64"},"passkeys_count":{"type":"integer","format":"int64"},"total_clicks":{"type":"integer","format":"int64"}}},"AdminUsersListResponse":{"type":"object","required":["users","total","page","per_page"],"properties":{"page":{"type":"integer","format":"int64","minimum":0},"per_page":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0},"users":{"type":"array","items":{"$ref":"#/components/schemas/AdminUserResponse"}}}},"AnalyticsQuery":{"type":"object","properties":{"days":{"type":"integer","format":"int64","description":"Stats window in days. Omitted defaults to 30; values are clamped to 1..=366.","nullable":true}}},"ApiKeyInfo":{"type":"object","required":["id","name","key_prefix","created_at"],"properties":{"created_at":{"type":"string"},"id":{"type":"integer","format":"int32"},"key_prefix":{"type":"string"},"last_used_at":{"type":"string","nullable":true},"name":{"type":"string"}}},"AppSettingsResponse":{"type":"object","required":["account_deletion_enabled","custom_aliases_enabled","passkeys_enabled","min_alias_length","max_alias_length","url_sanitization_enabled","qr_branding_enabled","burn_after_reading_enabled","safe_link_interstitial_enabled","conditional_routing_enabled","link_in_bio_enabled","api_keys_enabled"],"properties":{"account_deletion_enabled":{"type":"boolean"},"api_keys_enabled":{"type":"boolean"},"burn_after_reading_enabled":{"type":"boolean"},"conditional_routing_enabled":{"type":"boolean"},"custom_aliases_enabled":{"type":"boolean"},"link_in_bio_enabled":{"type":"boolean"},"max_alias_length":{"type":"integer","minimum":0},"max_links_per_user":{"type":"integer","format":"int32","nullable":true},"min_alias_length":{"type":"integer","minimum":0},"passkeys_enabled":{"type":"boolean"},"qr_branding_enabled":{"type":"boolean"},"safe_link_interstitial_enabled":{"type":"boolean"},"url_sanitization_enabled":{"type":"boolean"}}},"AuditLogResponse":{"type":"object","required":["id","action","resource_type","created_at"],"properties":{"action":{"type":"string"},"created_at":{"type":"string"},"details":{"nullable":true},"id":{"type":"integer","format":"int32"},"ip_address":{"type":"string","nullable":true},"resource_id":{"type":"integer","format":"int32","nullable":true},"resource_type":{"type":"string"},"user_email":{"type":"string","nullable":true},"user_id":{"type":"integer","format":"int32","nullable":true}}},"AuditQuery":{"type":"object","properties":{"limit":{"type":"integer","format":"int64","description":"Newest-first page size. Omitted or 0 defaults to 200. Maximum 500.","nullable":true,"minimum":0},"offset":{"type":"integer","format":"int64","nullable":true,"minimum":0}}},"AuthResponse":{"type":"object","required":["token","user_id","email","email_verified","is_admin"],"properties":{"email":{"type":"string"},"email_verified":{"type":"boolean"},"is_admin":{"type":"boolean"},"token":{"type":"string"},"user_id":{"type":"integer","format":"int32"}}},"AvatarProxyQuery":{"type":"object","required":["url"],"properties":{"url":{"type":"string","description":"External http(s) avatar URL to fetch through this origin."}}},"BackupListResponse":{"type":"object","required":["backups"],"properties":{"backups":{"type":"array","items":{"type":"string"}}}},"BackupResponse":{"type":"object","required":["success","message"],"properties":{"filename":{"type":"string","nullable":true},"message":{"type":"string"},"success":{"type":"boolean"}}},"BioLink":{"type":"object","required":["code","short_url","label"],"properties":{"code":{"type":"string"},"label":{"type":"string"},"short_url":{"type":"string"}}},"BioProfileResponse":{"type":"object","required":["username","links"],"properties":{"avatar_url":{"type":"string","nullable":true},"bio":{"type":"string","nullable":true},"display_name":{"type":"string","nullable":true},"links":{"type":"array","items":{"$ref":"#/components/schemas/BioLink"}},"location":{"type":"string","nullable":true},"theme":{"type":"string","nullable":true},"username":{"type":"string"},"website":{"type":"string","nullable":true}}},"BioSettingsRequest":{"type":"object","properties":{"bio_enabled":{"type":"boolean","nullable":true},"bio_theme":{"type":"string","nullable":true},"bio_username":{"type":"string","nullable":true}}},"BioSettingsResponse":{"type":"object","required":["bio_enabled"],"properties":{"bio_enabled":{"type":"boolean"},"bio_theme":{"type":"string","nullable":true},"bio_username":{"type":"string","nullable":true}}},"BlockDomainRequest":{"type":"object","required":["domain"],"properties":{"domain":{"type":"string"},"reason":{"type":"string","nullable":true}}},"BlockEmailDomainRequest":{"type":"object","required":["domain"],"properties":{"domain":{"type":"string"},"reason":{"type":"string","nullable":true}}},"BlockFromLinkResponse":{"type":"object","required":["success","domain","affected_links","message"],"properties":{"affected_links":{"type":"integer","format":"int64","minimum":0},"domain":{"type":"string"},"message":{"type":"string"},"success":{"type":"boolean"}}},"BlockLinkRequest":{"type":"object","required":["url"],"properties":{"reason":{"type":"string","nullable":true},"url":{"type":"string"}}},"BlockedDomainResponse":{"type":"object","required":["id","domain","created_at","affected_links"],"properties":{"affected_links":{"type":"integer","format":"int64","minimum":0},"blocked_by":{"type":"integer","format":"int32","nullable":true},"created_at":{"type":"string"},"domain":{"type":"string"},"id":{"type":"integer","format":"int32"},"reason":{"type":"string","nullable":true}}},"BlockedEmailDomainResponse":{"type":"object","required":["id","domain","created_at","affected_users"],"properties":{"affected_users":{"type":"integer","format":"int64","minimum":0},"blocked_by":{"type":"integer","format":"int32","nullable":true},"created_at":{"type":"string"},"domain":{"type":"string"},"id":{"type":"integer","format":"int32"},"reason":{"type":"string","nullable":true}}},"BlockedLinkResponse":{"type":"object","required":["id","url","created_at"],"properties":{"blocked_by":{"type":"integer","format":"int32","nullable":true},"created_at":{"type":"string"},"id":{"type":"integer","format":"int32"},"reason":{"type":"string","nullable":true},"url":{"type":"string"}}},"BrowserStats":{"type":"object","required":["browser","count","percentage"],"properties":{"browser":{"type":"string"},"count":{"type":"integer","format":"int64"},"percentage":{"type":"number","format":"double"}}},"BuildUtmRequest":{"type":"object","required":["url"],"properties":{"url":{"type":"string"},"utm_campaign":{"type":"string","nullable":true},"utm_content":{"type":"string","nullable":true},"utm_medium":{"type":"string","nullable":true},"utm_source":{"type":"string","nullable":true},"utm_term":{"type":"string","nullable":true}}},"BuildUtmResponse":{"type":"object","required":["original_url","url_with_utm","utm_params"],"properties":{"original_url":{"type":"string"},"url_with_utm":{"type":"string"},"utm_params":{"type":"object","additionalProperties":{"type":"string"}}}},"BulkCreateLinkRequest":{"type":"object","required":["urls"],"properties":{"folder_id":{"type":"integer","format":"int32","nullable":true},"org_id":{"type":"integer","format":"int32","nullable":true},"urls":{"type":"array","items":{"type":"string"}}}},"BulkCreateLinkResponse":{"type":"object","required":["links","errors"],"properties":{"errors":{"type":"array","items":{"type":"string"}},"links":{"type":"array","items":{"$ref":"#/components/schemas/CreateLinkResponse"}}}},"BulkDeleteRequest":{"type":"object","required":["ids"],"properties":{"ids":{"type":"array","items":{"type":"integer","format":"int32"}}}},"BulkDeleteResponse":{"type":"object","required":["deleted"],"properties":{"deleted":{"type":"integer","format":"int64","minimum":0}}},"BulkLinkActionResponse":{"type":"object","required":["success","affected","message"],"properties":{"affected":{"type":"integer","format":"int64","minimum":0},"message":{"type":"string"},"success":{"type":"boolean"}}},"BulkLinkIdsRequest":{"type":"object","required":["ids"],"properties":{"ids":{"type":"array","items":{"type":"integer","format":"int32"},"description":"Link IDs to act on."}}},"BulkUpdateRequest":{"type":"object","required":["ids"],"properties":{"expires_at":{"type":"string","format":"date-time","nullable":true},"folder_id":{"type":"integer","format":"int32","nullable":true},"ids":{"type":"array","items":{"type":"integer","format":"int32"}},"remove_expiration":{"type":"boolean","nullable":true}}},"BulkUpdateResponse":{"type":"object","required":["updated"],"properties":{"updated":{"type":"integer","format":"int64","minimum":0}}},"ChangePasswordRequest":{"type":"object","required":["current_password","new_password"],"properties":{"current_password":{"type":"string"},"new_password":{"type":"string"}}},"CheckCodeResponse":{"type":"object","required":["available","code","message"],"properties":{"available":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}}},"CityStats":{"type":"object","required":["city","count","percentage"],"properties":{"city":{"type":"string"},"count":{"type":"integer","format":"int64"},"country":{"type":"string","nullable":true},"percentage":{"type":"number","format":"double"}}},"CloneLinkResponse":{"type":"object","required":["id","code","short_url","original_url","message"],"properties":{"code":{"type":"string"},"id":{"type":"integer","format":"int32"},"message":{"type":"string"},"original_url":{"type":"string"},"short_url":{"type":"string"}}},"ContactRequest":{"type":"object","required":["name","email","subject","message"],"properties":{"email":{"type":"string"},"message":{"type":"string"},"name":{"type":"string"},"subject":{"type":"string"}}},"ContactResponse":{"type":"object","required":["success","message"],"properties":{"message":{"type":"string"},"success":{"type":"boolean"}}},"CountryStats":{"type":"object","required":["country","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"country":{"type":"string"},"percentage":{"type":"number","format":"double"}}},"CreateApiKeyRequest":{"type":"object","properties":{"name":{"type":"string","nullable":true}}},"CreateApiKeyResponse":{"type":"object","required":["id","name","key","key_prefix","created_at"],"properties":{"created_at":{"type":"string"},"id":{"type":"integer","format":"int32"},"key":{"type":"string","description":"The full secret key — shown ONCE at creation and never again."},"key_prefix":{"type":"string"},"name":{"type":"string"}}},"CreateFolderRequest":{"type":"object","required":["name"],"properties":{"color":{"type":"string","nullable":true},"name":{"type":"string"},"org_id":{"type":"integer","format":"int32","nullable":true}}},"CreateLinkRequest":{"type":"object","properties":{"burn_after_reading":{"type":"boolean","nullable":true},"custom_alias":{"type":"string","nullable":true},"expires_at":{"type":"string","format":"date-time","nullable":true},"folder_id":{"type":"integer","format":"int32","nullable":true},"max_clicks":{"type":"integer","format":"int32","nullable":true},"notes":{"type":"string","nullable":true},"org_id":{"type":"integer","format":"int32","nullable":true},"original_url":{"type":"string"},"password":{"type":"string","nullable":true},"safe_link_interstitial":{"type":"boolean","nullable":true},"starts_at":{"type":"string","format":"date-time","nullable":true},"tag_ids":{"type":"array","items":{"type":"integer","format":"int32"},"nullable":true},"title":{"type":"string","nullable":true}}},"CreateLinkResponse":{"type":"object","required":["id","code","short_url"],"properties":{"code":{"type":"string"},"id":{"type":"integer","format":"int32"},"short_url":{"type":"string"}}},"CreateOrgRequest":{"type":"object","required":["name","slug"],"properties":{"name":{"type":"string"},"slug":{"type":"string"}}},"CreateTagRequest":{"type":"object","required":["name"],"properties":{"color":{"type":"string","nullable":true},"name":{"type":"string"},"org_id":{"type":"integer","format":"int32","nullable":true}}},"DashboardStats":{"type":"object","required":["total_links","total_clicks","active_links","clicks_today","clicks_this_week","clicks_this_month","top_links","clicks_by_day","top_countries","top_browsers"],"properties":{"active_links":{"type":"integer","format":"int64"},"clicks_by_day":{"type":"array","items":{"$ref":"#/components/schemas/DayStats"}},"clicks_this_month":{"type":"integer","format":"int64"},"clicks_this_week":{"type":"integer","format":"int64"},"clicks_today":{"type":"integer","format":"int64","description":"Clicks since 00:00:00 UTC of the current UTC day. Not the caller's local day."},"top_browsers":{"type":"array","items":{"$ref":"#/components/schemas/BrowserStats"}},"top_countries":{"type":"array","items":{"$ref":"#/components/schemas/CountryStats"}},"top_links":{"type":"array","items":{"$ref":"#/components/schemas/TopLink"}},"total_clicks":{"type":"integer","format":"int64"},"total_links":{"type":"integer","format":"int64"}}},"DayStats":{"type":"object","required":["date","count"],"properties":{"count":{"type":"integer","format":"int64"},"date":{"type":"string"}}},"DeleteAccountRequest":{"type":"object","required":["password"],"properties":{"password":{"type":"string"}}},"DeletePasskeyRequest":{"type":"object","required":["passkey_id"],"properties":{"passkey_id":{"type":"integer","format":"int32"}}},"DeviceStats":{"type":"object","required":["device","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"device":{"type":"string"},"percentage":{"type":"number","format":"double"}}},"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"type":"string"}}},"FolderQuery":{"type":"object","properties":{"org_id":{"type":"integer","format":"int32","nullable":true}}},"FolderResponse":{"type":"object","required":["id","name","created_at","link_count"],"properties":{"color":{"type":"string","nullable":true},"created_at":{"type":"string"},"id":{"type":"integer","format":"int32"},"link_count":{"type":"integer","format":"int64"},"name":{"type":"string"},"org_id":{"type":"integer","format":"int32","nullable":true},"user_id":{"type":"integer","format":"int32","nullable":true}}},"ForgotPasswordRequest":{"type":"object","required":["email"],"properties":{"email":{"type":"string"}}},"GeoPoint":{"type":"object","required":["latitude","longitude","count"],"properties":{"city":{"type":"string","nullable":true},"count":{"type":"integer","format":"int64"},"country":{"type":"string","nullable":true},"latitude":{"type":"number","format":"double"},"longitude":{"type":"number","format":"double"}}},"HealthCheckRequest":{"type":"object","required":["url"],"properties":{"url":{"type":"string"}}},"InviteMemberRequest":{"type":"object","required":["email","role"],"properties":{"email":{"type":"string"},"role":{"type":"string"}}},"LinkPreviewData":{"type":"object","required":["url"],"properties":{"description":{"type":"string","nullable":true},"favicon":{"type":"string","nullable":true},"image":{"type":"string","nullable":true},"site_name":{"type":"string","nullable":true},"title":{"type":"string","nullable":true},"url":{"type":"string"}}},"LinkPreviewResponse":{"type":"object","required":["code","short_url","original_url","domain","has_password","is_expired","is_active","created_at","click_count","reputation","interstitial_enabled","safe_link_interstitial"],"properties":{"click_count":{"type":"integer","format":"int64"},"code":{"type":"string"},"created_at":{"type":"string"},"domain":{"type":"string"},"has_password":{"type":"boolean"},"interstitial_enabled":{"type":"boolean","description":"Whether the instance has the safe-link interstitial feature enabled."},"is_active":{"type":"boolean","description":"False when the link is not currently live (scheduled, expired, capped, or burned)."},"is_expired":{"type":"boolean"},"original_url":{"type":"string"},"reputation":{"$ref":"#/components/schemas/ReputationInfo"},"safe_link_interstitial":{"type":"boolean","description":"Whether this link opted into showing the interstitial before redirecting."},"short_url":{"type":"string"}}},"LinkResponse":{"type":"object","required":["id","code","short_url","api_url","original_url","click_count","created_at","has_password","burn_after_reading","safe_link_interstitial","bio_visible","is_active","is_pinned","tags"],"properties":{"api_url":{"type":"string"},"bio_visible":{"type":"boolean"},"burn_after_reading":{"type":"boolean"},"burned_at":{"type":"string","nullable":true},"click_count":{"type":"integer","format":"int64"},"code":{"type":"string"},"created_at":{"type":"string"},"expires_at":{"type":"string","nullable":true},"folder_id":{"type":"integer","format":"int32","nullable":true},"has_password":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"is_pinned":{"type":"boolean"},"max_clicks":{"type":"integer","format":"int32","nullable":true},"notes":{"type":"string","nullable":true},"org_id":{"type":"integer","format":"int32","nullable":true},"original_url":{"type":"string"},"safe_link_interstitial":{"type":"boolean"},"short_url":{"type":"string"},"starts_at":{"type":"string","nullable":true},"tags":{"type":"array","items":{"$ref":"#/components/schemas/TagInfo"}},"title":{"type":"string","nullable":true}}},"LinkStatsResponse":{"type":"object","required":["link_id","code","original_url","total_clicks","truncated","unique_visitors","clicks_by_day","clicks_by_country","clicks_by_city","clicks_by_device","clicks_by_browser","clicks_by_os","clicks_by_referer","recent_clicks","geo_data"],"properties":{"clicks_by_browser":{"type":"array","items":{"$ref":"#/components/schemas/BrowserStats"}},"clicks_by_city":{"type":"array","items":{"$ref":"#/components/schemas/CityStats"}},"clicks_by_country":{"type":"array","items":{"$ref":"#/components/schemas/CountryStats"}},"clicks_by_day":{"type":"array","items":{"$ref":"#/components/schemas/DayStats"}},"clicks_by_device":{"type":"array","items":{"$ref":"#/components/schemas/DeviceStats"}},"clicks_by_os":{"type":"array","items":{"$ref":"#/components/schemas/OsStats"}},"clicks_by_referer":{"type":"array","items":{"$ref":"#/components/schemas/RefererStats"}},"code":{"type":"string"},"geo_data":{"type":"array","items":{"$ref":"#/components/schemas/GeoPoint"}},"link_id":{"type":"integer","format":"int32"},"original_url":{"type":"string"},"recent_clicks":{"type":"array","items":{"$ref":"#/components/schemas/RecentClick"}},"total_clicks":{"type":"integer","format":"int32","description":"Clicks in the requested window, from a `COUNT(*)` over that window.\nBreakdown maps below may be computed from a newest-first sample when\n`truncated` is true."},"truncated":{"type":"boolean","description":"True when the window contained more click rows than the per-request\ncap, so country/city/day percentages describe the newest sample."},"unique_visitors":{"type":"integer","format":"int32"}}},"LinksQuery":{"type":"object","properties":{"folder_id":{"type":"integer","format":"int32","nullable":true},"limit":{"type":"integer","format":"int64","description":"Page size. Omitted or 0 defaults to 1000. Maximum 1000.","nullable":true,"minimum":0},"offset":{"type":"integer","format":"int64","nullable":true,"minimum":0},"org_id":{"type":"integer","format":"int32","nullable":true},"search":{"type":"string","nullable":true},"tag_id":{"type":"integer","format":"int32","nullable":true}}},"LoginFinishRequest":{"type":"object","required":["username","credential"],"properties":{"credential":{"type":"object","description":"Standard WebAuthn assertion credential — not expanded."},"username":{"type":"string"}}},"LoginRequest":{"type":"object","required":["email","password"],"properties":{"email":{"type":"string"},"password":{"type":"string"}}},"LoginStartRequest":{"type":"object","required":["username"],"properties":{"username":{"type":"string"}}},"MessageResponse":{"type":"object","required":["message"],"properties":{"message":{"type":"string"}}},"MoveLinkToFolderRequest":{"type":"object","required":["link_ids"],"properties":{"link_ids":{"type":"array","items":{"type":"integer","format":"int32"}}}},"OrgMemberResponse":{"type":"object","required":["id","user_id","email","role","joined_at"],"properties":{"email":{"type":"string"},"id":{"type":"integer","format":"int32"},"joined_at":{"type":"string"},"role":{"type":"string"},"user_id":{"type":"integer","format":"int32"}}},"OrgResponse":{"type":"object","required":["id","name","slug","owner_id","created_at","member_count","link_count"],"properties":{"created_at":{"type":"string"},"id":{"type":"integer","format":"int32"},"link_count":{"type":"integer","format":"int64"},"member_count":{"type":"integer","format":"int64"},"name":{"type":"string"},"owner_id":{"type":"integer","format":"int32"},"slug":{"type":"string"}}},"OsStats":{"type":"object","required":["os","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"os":{"type":"string"},"percentage":{"type":"number","format":"double"}}},"PasskeyAuthResponse":{"type":"object","required":["token","email_verified","is_admin"],"properties":{"email_verified":{"type":"boolean"},"is_admin":{"type":"boolean"},"token":{"type":"string"}}},"PasskeyInfo":{"type":"object","required":["id","name","created_at"],"properties":{"created_at":{"type":"string"},"id":{"type":"integer","format":"int32"},"last_used":{"type":"string","nullable":true},"name":{"type":"string"}}},"PasskeyListResponse":{"type":"object","required":["passkeys"],"properties":{"passkeys":{"type":"array","items":{"$ref":"#/components/schemas/PasskeyInfo"}}}},"PinResponse":{"type":"object","required":["is_pinned","message"],"properties":{"is_pinned":{"type":"boolean"},"message":{"type":"string"}}},"PreviewMetadataRequest":{"type":"object","required":["url"],"properties":{"url":{"type":"string"}}},"RateLimitResponse":{"type":"object","description":"Body of a `429 Too Many Requests` answer from the rate limiter.","required":["error","retry_after","message"],"properties":{"error":{"type":"string","description":"Always `Too many requests`."},"message":{"type":"string","description":"Human-readable explanation."},"retry_after":{"type":"integer","format":"int64","description":"Seconds until the budget refills, the same value as `Retry-After`.","minimum":0}}},"RecentClick":{"type":"object","required":["id","timestamp"],"properties":{"browser":{"type":"string","nullable":true},"city":{"type":"string","nullable":true},"country":{"type":"string","nullable":true},"device":{"type":"string","nullable":true},"id":{"type":"integer","format":"int64"},"os":{"type":"string","nullable":true},"referer":{"type":"string","nullable":true},"timestamp":{"type":"string"}}},"RefererStats":{"type":"object","required":["referer","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"percentage":{"type":"number","format":"double"},"referer":{"type":"string"}}},"RegisterFinishRequest":{"type":"object","required":["username","credential"],"properties":{"credential":{"type":"object","description":"Standard WebAuthn registration credential — not expanded."},"username":{"type":"string","description":"Accepted for wire compatibility but IGNORED server-side: the credential\nis bound to the caller's authenticated identity (see `register_finish`)."}}},"RegisterRequest":{"type":"object","required":["email","password"],"properties":{"email":{"type":"string"},"password":{"type":"string"}}},"RegisterStartRequest":{"type":"object","required":["username"],"properties":{"username":{"type":"string","description":"Accepted for wire compatibility but IGNORED server-side: the target\naccount is taken from the caller's authenticated identity, never from\nthis field (see `register_start`)."}}},"RemoveTagsFromLinkRequest":{"type":"object","required":["tag_ids"],"properties":{"tag_ids":{"type":"array","items":{"type":"integer","format":"int32"}}}},"RenamePasskeyRequest":{"type":"object","required":["passkey_id","name"],"properties":{"name":{"type":"string"},"passkey_id":{"type":"integer","format":"int32"}}},"ReplaceRoutingRulesRequest":{"type":"object","required":["rules"],"properties":{"rules":{"type":"array","items":{"$ref":"#/components/schemas/RoutingRuleInput"}}}},"ReputationInfo":{"type":"object","required":["verdict","source"],"properties":{"source":{"type":"string","description":"Where the verdict came from, e.g. \"internal_blocklist\"."},"verdict":{"type":"string","description":"\"safe\" | \"suspicious\" | \"malicious\" | \"unknown\""}}},"ResendVerificationRequest":{"type":"object","required":["email"],"properties":{"email":{"type":"string"}}},"ResetPasswordRequest":{"type":"object","required":["token","password"],"properties":{"password":{"type":"string"},"token":{"type":"string"}}},"RoutingRuleInput":{"type":"object","description":"A single routing rule as accepted from the API.","required":["destination_url"],"properties":{"destination_url":{"type":"string"},"match_country":{"type":"string","nullable":true},"match_device":{"type":"string","nullable":true},"match_lang":{"type":"string","nullable":true},"match_os":{"type":"string","nullable":true},"priority":{"type":"integer","format":"int32","nullable":true},"weight":{"type":"integer","format":"int32","nullable":true}}},"RoutingRuleResponse":{"type":"object","required":["id","priority","destination_url","weight"],"properties":{"destination_url":{"type":"string"},"id":{"type":"integer","format":"int32"},"match_country":{"type":"string","nullable":true},"match_device":{"type":"string","nullable":true},"match_lang":{"type":"string","nullable":true},"match_os":{"type":"string","nullable":true},"priority":{"type":"integer","format":"int32"},"weight":{"type":"integer","format":"int32"}}},"RoutingRulesSavedResponse":{"type":"object","required":["count"],"properties":{"count":{"type":"integer","minimum":0}}},"SparklineData":{"type":"object","required":["link_id","data","labels","total"],"properties":{"data":{"type":"array","items":{"type":"integer","format":"int64"}},"labels":{"type":"array","items":{"type":"string"}},"link_id":{"type":"integer","format":"int32"},"total":{"type":"integer","format":"int64"}}},"SparklineResponse":{"type":"object","required":["sparklines"],"properties":{"sparklines":{"type":"array","items":{"$ref":"#/components/schemas/SparklineData"}}}},"SuccessResponse":{"type":"object","required":["message"],"properties":{"message":{"type":"string"}}},"TagInfo":{"type":"object","required":["id","name"],"properties":{"color":{"type":"string","nullable":true},"id":{"type":"integer","format":"int32"},"name":{"type":"string"}}},"TagQuery":{"type":"object","properties":{"org_id":{"type":"integer","format":"int32","nullable":true}}},"TagResponse":{"type":"object","required":["id","name","created_at","link_count"],"properties":{"color":{"type":"string","nullable":true},"created_at":{"type":"string"},"id":{"type":"integer","format":"int32"},"link_count":{"type":"integer","format":"int64"},"name":{"type":"string"},"org_id":{"type":"integer","format":"int32","nullable":true},"user_id":{"type":"integer","format":"int32","nullable":true}}},"TopLink":{"type":"object","required":["id","code","original_url","click_count"],"properties":{"click_count":{"type":"integer","format":"int64"},"code":{"type":"string"},"id":{"type":"integer","format":"int32"},"original_url":{"type":"string"}}},"TransferOwnershipRequest":{"type":"object","required":["new_owner_user_id"],"properties":{"new_owner_user_id":{"type":"integer","format":"int32","description":"User ID of the member who becomes the new owner."}}},"UpdateFolderRequest":{"type":"object","properties":{"color":{"type":"string","nullable":true},"name":{"type":"string","nullable":true}}},"UpdateLinkRequest":{"type":"object","properties":{"bio_visible":{"type":"boolean","nullable":true},"burn_after_reading":{"type":"boolean","nullable":true},"custom_alias":{"type":"string","description":"Accepted so a client that echoes the current code is not ignored\nsilently. A different value is rejected: the code is not editable.","nullable":true},"expires_at":{"type":"string","format":"date-time","nullable":true},"folder_id":{"type":"integer","format":"int32","nullable":true},"max_clicks":{"type":"integer","format":"int32","nullable":true},"notes":{"type":"string","nullable":true},"original_url":{"type":"string","nullable":true},"password":{"type":"string","nullable":true},"remove_expiration":{"type":"boolean","nullable":true},"remove_max_clicks":{"type":"boolean","nullable":true},"remove_password":{"type":"boolean","nullable":true},"remove_starts_at":{"type":"boolean","nullable":true},"safe_link_interstitial":{"type":"boolean","nullable":true},"starts_at":{"type":"string","format":"date-time","nullable":true},"title":{"type":"string","nullable":true}}},"UpdateMemberRoleRequest":{"type":"object","required":["role"],"properties":{"role":{"type":"string"}}},"UpdateOrgRequest":{"type":"object","properties":{"name":{"type":"string","nullable":true},"slug":{"type":"string","nullable":true}}},"UpdateProfileRequest":{"type":"object","properties":{"avatar_url":{"type":"string","nullable":true},"bio":{"type":"string","nullable":true},"display_name":{"type":"string","nullable":true},"location":{"type":"string","nullable":true},"website":{"type":"string","nullable":true}}},"UpdateTagRequest":{"type":"object","properties":{"color":{"type":"string","nullable":true},"name":{"type":"string","nullable":true}}},"UrlHealthResponse":{"type":"object","required":["url","reachable"],"properties":{"error":{"type":"string","nullable":true},"reachable":{"type":"boolean"},"response_time_ms":{"type":"integer","format":"int64","nullable":true,"minimum":0},"status_code":{"type":"integer","format":"int32","nullable":true,"minimum":0},"url":{"type":"string"}}},"UserProfileResponse":{"type":"object","required":["id","email","email_verified","is_admin","created_at","link_count","total_clicks","bio_enabled"],"properties":{"avatar_url":{"type":"string","nullable":true},"bio":{"type":"string","nullable":true},"bio_enabled":{"type":"boolean"},"bio_theme":{"type":"string","nullable":true},"bio_username":{"type":"string","nullable":true},"created_at":{"type":"string"},"display_name":{"type":"string","nullable":true},"email":{"type":"string"},"email_verified":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"is_admin":{"type":"boolean"},"link_count":{"type":"integer","format":"int64"},"location":{"type":"string","nullable":true},"total_clicks":{"type":"integer","format":"int64"},"website":{"type":"string","nullable":true}}},"VerifyEmailRequest":{"type":"object","required":["token"],"properties":{"token":{"type":"string"}}},"VerifyPasswordRequest":{"type":"object","required":["password"],"properties":{"password":{"type":"string"}}}},"responses":{"TooManyRequests":{"description":"Rate limit exceeded. Retry after the number of seconds in `Retry-After`. The budgets are listed under Rate limits in the API description.","headers":{"Retry-After":{"schema":{"type":"integer","format":"int64","minimum":0},"description":"Seconds until the budget refills, rounded up"},"X-RateLimit-Limit":{"schema":{"type":"integer","format":"int32","minimum":0},"description":"Size of the budget that ran out"},"X-RateLimit-Remaining":{"schema":{"type":"integer","format":"int32","minimum":0},"description":"Requests left in that budget (0)"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitResponse"}}}}},"securitySchemes":{"api_key":{"type":"http","scheme":"bearer","bearerFormat":"opn_ API key","description":"Personal API key from `POST /auth/api-keys`, sent as `Authorization: Bearer opn_...`."},"bearer_auth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Session JWT from `POST /auth/register`, `POST /auth/login`, or `POST /auth/passkey/login/finish`."}}},"tags":[{"name":"Authentication","description":"User registration, login, and passkey management"},{"name":"Links","description":"Create, manage, and redirect shortened URLs"},{"name":"Analytics","description":"View click statistics and analytics"},{"name":"Organizations","description":"Team and organization management"},{"name":"Folders","description":"Organize links into folders"},{"name":"Tags","description":"Tag and categorize links"},{"name":"Admin","description":"Instance administration: users, links, organizations, blocking, backups"},{"name":"Contact","description":"Contact form"},{"name":"Bio","description":"Public link-in-bio pages"}]}