{"openapi":"3.1.0","info":{"title":"Tophhie Cloud API","version":"1.1.0","description":"This is the documentation for the Tophhie Cloud API (ran on Cloudflare Workers).\n\n**Rate Limiting:** Requests are limited to 500 requests every 30 seconds per IP address. If you exceed this limit, you will receive a 429 Too Many Requests response. Please implement appropriate retry logic in your application to handle rate limiting.\n\n**Request Logging:** All API requests are logged for operational and analytics purposes. Each request records the HTTP method, path, query string, response status code, response time, whether an API key was present, and request metadata including your IP address, country (ISO 3166-1 alpha-2), User-Agent, Referer, and Cloudflare Ray ID. A unique trace ID is also assigned to every request. Logged data is retained in accordance with our privacy policy.","contact":{"name":"Tophhie Cloud Support","url":"https://support.tophhie.cloud","email":"api-support@tophhie.cloud"}},"servers":[{"url":"https://api.tophhie.cloud","description":"Primary API server."},{"url":"https://api.tophhie.dev","description":"API server in dev environment."}],"components":{"schemas":{},"parameters":{}},"paths":{"/appleosversion/{appleDeviceModel}":{"get":{"tags":["Apple OS Version API"],"summary":"Fetches the latest Apple OS version for a specific Apple device model.","description":"Queries Apple's public device management feed (gdmf.apple.com) and returns the highest available OS version for the given hardware identifier. Optionally compares against a supplied version to indicate whether an update is required.","operationId":"get_GetAppleOSVersion","parameters":[{"schema":{"type":"string","description":"The Apple hardware identifier. E.g. iPhone17,1."},"required":true,"description":"The Apple hardware identifier. E.g. iPhone17,1.","name":"appleDeviceModel","in":"path"},{"schema":{"type":"string","default":"","description":"The Apple OS version to compare against. If the latest version is higher, updateRequired will be true."},"required":false,"description":"The Apple OS version to compare against. If the latest version is higher, updateRequired will be true.","name":"currentOSVersion","in":"query"}],"responses":{"200":{"description":"OS version information found.","content":{"application/json":{"schema":{"type":"object","properties":{"appleDeviceModel":{"type":"string"},"os":{"type":"string"},"latestVersion":{"type":"string"},"updatePosted":{"type":"string"},"updateRequired":{"type":["boolean","null"]},"errorMessage":{"type":["string","null"]},"support":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"email":{"type":"string","format":"email"}},"required":["url","email"]}},"required":["appleDeviceModel","os","latestVersion","updatePosted","updateRequired","errorMessage","support"]}}}},"404":{"description":"No OS found for the specified device model.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["error"]},"message":{"type":"string"}},"required":["status","message"]}}}},"500":{"description":"Failed to fetch data from Apple's servers.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["error"]},"message":{"type":"string"}},"required":["status","message"]}}}}}}},"/bookings/{upn}":{"get":{"tags":["Bookings API (Experimental)"],"summary":"Redirects to the Microsoft Bookings page for a Tophhie Cloud user.","description":"Looks up the user's primary Exchange Online mailbox ID via Microsoft Graph (beta) and issues a 302 redirect to their Bookings 'book with me' page. The user must have a primary mailbox in Exchange Online.","operationId":"get_GetBookingsLink","parameters":[{"schema":{"type":"string","description":"The User Principal Name (email address) of the Tophhie Cloud user."},"required":true,"description":"The User Principal Name (email address) of the Tophhie Cloud user.","name":"upn","in":"path"}],"responses":{"302":{"description":"Redirect to the user's Microsoft Bookings link."},"400":{"description":"Bad request — invalid UPN format.","content":{"text/plain":{"schema":{"type":"string"}}}},"404":{"description":"Primary mailbox not found for the user.","content":{"text/plain":{"schema":{"type":"string"}}}},"500":{"description":"Graph API error or the user does not exist.","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/domains":{"get":{"tags":["Domains API"],"summary":"Fetches the list of Tophhie Cloud domains.","operationId":"get_GetDomains","responses":{"200":{"description":"OK.","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"array","items":{"type":"string"}}},"required":["result"]}}}}}}},"/domains/{domainName}":{"get":{"tags":["Domains API"],"summary":"Fetches a specific Tophhie Cloud domain details by its name.","operationId":"get_GetSpecificDomain","parameters":[{"schema":{"type":"string"},"required":true,"name":"domainName","in":"path"}],"responses":{"200":{"description":"OK.","content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"registeredSince":{"type":"string","format":"date-time"},"authoritativeNameServers":{"type":"array","items":{"type":"string"}},"mxRecords":{"type":"array","items":{"type":"string"}},"mxRecordsV2":{"type":"array","items":{"type":"object","properties":{"priority":{"type":"number"},"host":{"type":"string"}},"required":["priority","host"]}},"isPrimaryDomain":{"type":"boolean"},"dmarcPolicy":{"type":"string","enum":["none","quarantine","reject"]},"dmarcRuaContacts":{"type":"array","items":{"type":"string"}},"spfPolicy":{"type":"string","enum":["none","softfail","hardfail"]},"mtaStsEnabled":{"type":"boolean"},"mtaStsEnforcementMode":{"type":"string","enum":["enforce","testing","none"]},"mtaStsPolicyUrl":{"type":["string","null"],"format":"uri"},"is365DkimConfigured":{"type":"boolean"},"dnssecEnabled":{"type":"boolean"},"cfSettings":{"type":"object","additionalProperties":{}},"abuseContact":{"type":["string","null"],"format":"email"}},"required":["name","registeredSince","authoritativeNameServers","mxRecords","mxRecordsV2","isPrimaryDomain","dmarcPolicy","dmarcRuaContacts","spfPolicy","mtaStsEnabled","mtaStsEnforcementMode","mtaStsPolicyUrl","is365DkimConfigured","dnssecEnabled","cfSettings","abuseContact"]}}}}}}},"/entra/convertid/{id}":{"get":{"tags":["Entra ID Converter API"],"summary":"Converts an Entra ID Object ID to a SID or vice versa.","query":{"_def":{"unknownKeys":"strip","catchall":{"_def":{"typeName":"ZodNever"},"~standard":{"version":1,"vendor":"zod"}},"typeName":"ZodObject"},"~standard":{"version":1,"vendor":"zod"},"_cached":null},"operationId":"get_IDConverter","parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"OK.","content":{"application/json":{"schema":{"type":"object","properties":{"originalId":{"type":"string"},"returnId":{"type":"string"},"convertDirection":{"type":"string"}},"required":["originalId","returnId","convertDirection"]}}}}}}},"/entra/ipupdate":{"post":{"tags":["Internal APIs (Not for public use)"],"summary":"INTERNAL: Update the IP address in a Microsoft Entra Named Location.","security":[{"ApiKeyAuth":[]}],"operationId":"post_UpdateConditionalAccessIP","parameters":[{"schema":{"type":"string","minLength":1,"description":"The IP address to update the named location with."},"required":true,"description":"The IP address to update the named location with.","name":"ip","in":"query"},{"schema":{"type":"string","description":"Internal API key for authorising this operation."},"required":true,"description":"Internal API key for authorising this operation.","name":"x-tc-api-key","in":"header"}],"responses":{"200":{"description":"Named location updated successfully.","content":{"text/plain":{"schema":{"type":"string"}}}},"403":{"description":"Missing or invalid API key.","content":{"text/plain":{"schema":{"type":"string"}}}},"500":{"description":"Graph or upstream failure.","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/entra/tenantinfo":{"get":{"tags":["Entra ID Tenant Information API"],"summary":"Fetches public information about a Microsoft Entra ID tenant.","description":"Provide either a tenant ID (GUID) or a domain name registered within the tenant. Returns branding, federated domain, email configuration and SharePoint presence details.","operationId":"get_GetEntraTenantInfo","parameters":[{"schema":{"type":"string","description":"The Entra ID tenant GUID."},"required":false,"description":"The Entra ID tenant GUID.","name":"tenantId","in":"query"},{"schema":{"type":"string","description":"A domain name registered within the Entra ID tenant."},"required":false,"description":"A domain name registered within the Entra ID tenant.","name":"domainName","in":"query"},{"schema":{"type":"boolean","default":false,"description":"When true, only custom (non-onmicrosoft.com) domains are analysed for email configuration."},"required":false,"description":"When true, only custom (non-onmicrosoft.com) domains are analysed for email configuration.","name":"customDomainsOnly","in":"query"},{"schema":{"type":"boolean","default":false,"description":"When true, MX record and email configuration lookups are skipped."},"required":false,"description":"When true, MX record and email configuration lookups are skipped.","name":"skipEmailConfig","in":"query"}],"responses":{"200":{"description":"Tenant information retrieved successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"tenantId":{"type":"string"},"federationBrandName":{"type":["string","null"]},"tenantDisplayName":{"type":["string","null"]},"defaultDomainName":{"type":"string"},"bannerLogo":{"type":["string","null"]},"tenantRegion":{"type":["string","null"]},"desktopSsoEnabled":{"type":"boolean"},"verifiedEmailSignUpDisallowed":{"type":"boolean"},"tenantIsUnmanaged":{"type":"boolean"},"tenantLeaveUrl":{"type":"string","format":"uri"},"tenantUsesExo":{"type":"boolean"},"mxRecords":{"type":"array","items":{"type":"string"}},"emailConfiguration":{"type":"array","items":{"type":"object","properties":{"domain":{"type":"string"},"mxRecords":{"type":"array","items":{"type":"string"}},"exoSmtpDaneDnsSecEnabled":{"type":"boolean"}},"required":["domain","mxRecords","exoSmtpDaneDnsSecEnabled"]}},"tenantUsesSpo":{"type":"boolean"},"spoDomains":{"type":"array","items":{"type":"string"}},"verifiedDomains":{"type":"integer"},"additionalDomains":{"type":"array","items":{"type":"string"}}},"required":["tenantId","federationBrandName","tenantDisplayName","defaultDomainName","bannerLogo","tenantRegion","desktopSsoEnabled","verifiedEmailSignUpDisallowed","tenantIsUnmanaged","tenantLeaveUrl","tenantUsesExo","mxRecords","emailConfiguration","tenantUsesSpo","spoDomains","verifiedDomains","additionalDomains"]}}}},"400":{"description":"Bad request — provide exactly one of tenantId or domainName.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"}},"required":["success","error"]}}}},"404":{"description":"Tenant not found.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"}},"required":["success","error"]}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"}},"required":["success","error"]}}}}}}},"/generate/guid":{"get":{"tags":["Generator API"],"summary":"Generates a specified number of GUIDs.","operationId":"get_GenerateGuid","parameters":[{"schema":{"type":"integer","minimum":1,"maximum":500,"default":1,"description":"Number of GUIDs you'd like. Default is 1. Max is 500."},"required":false,"description":"Number of GUIDs you'd like. Default is 1. Max is 500.","name":"numberOfGuids","in":"query"}],"responses":{"200":{"description":"OK.","content":{"application/json":{"schema":{"type":"object","properties":{"guids":{"type":"array","items":{"type":"string"}}},"required":["guids"]}}}}}}},"/generate/timestamp/ticks":{"get":{"tags":["Generator API"],"summary":"Generate timestamp in ticks. The value is in ticks (100-nanosecond intervals since 1 January 0001). Uses UTC.","operationId":"get_GenerateTimestampTicks","responses":{"200":{"description":"OK.","content":{"application/json":{"schema":{"type":"object","properties":{"dateTime":{"type":"string"},"ticks":{"type":"string"}},"required":["dateTime","ticks"]}}}}}}},"/health":{"get":{"tags":["Health API"],"summary":"Get the health status of the Tophhie Cloud API.","operationId":"get_HealthGet","responses":{"200":{"description":"OK.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["ok","error"]}},"required":["status"]}}}}}}},"/ipcheck":{"get":{"tags":["IP Checker API"],"summary":"Fetches IP address information for specific IPs, locations, or self.","description":"Pass an `ip` to look up any address, a `location` shortcut (`me` returns your own IP, `hoyland` resolves the Hoyland DDNS record), or omit both to default to `me`.","operationId":"get_ProcessIPCheck","parameters":[{"schema":{"type":"string","default":"","description":"The IP address you'd like to query."},"required":false,"description":"The IP address you'd like to query.","name":"ip","in":"query"},{"schema":{"type":"string","default":"","description":"A predefined location you'd like to query. Supported values: me, hoyland."},"required":false,"description":"A predefined location you'd like to query. Supported values: me, hoyland.","name":"location","in":"query"},{"schema":{"type":"boolean","default":false,"description":"Indicates whether to perform a reverse DNS lookup on the IP address."},"required":false,"description":"Indicates whether to perform a reverse DNS lookup on the IP address.","name":"reverseCheck","in":"query"}],"responses":{"200":{"description":"IP lookup successful.","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"string"},"ipVersion":{"type":"integer"},"mapsUrl":{"type":"object","properties":{"google":{"type":["string","null"],"format":"uri"},"bing":{"type":["string","null"],"format":"uri"},"apple":{"type":["string","null"],"format":"uri"}},"required":["google","bing","apple"]},"metadata":{"type":"object","properties":{"status":{"type":"string"},"country":{"type":"string"},"countryCode":{"type":"string"},"region":{"type":"string"},"regionName":{"type":"string"},"city":{"type":"string"},"zip":{"type":"string"},"lat":{"type":"number"},"lon":{"type":"number"},"timezone":{"type":"string"},"utcOffset":{"type":"integer"},"isp":{"type":"string"},"org":{"type":"string"},"as":{"type":"string"},"reverse":{"type":["string","null"]},"mobile":{"type":"boolean"},"proxy":{"type":"boolean"},"hosting":{"type":"boolean"}},"required":["status","country","countryCode","region","regionName","city","zip","lat","lon","timezone","utcOffset","isp","org","as","reverse","mobile","proxy","hosting"]},"contacts":{"type":"array","items":{"type":"string"}},"loc_disclaimer":{"type":"string"},"support":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"email":{"type":"string","format":"email"}},"required":["url","email"]}},"required":["result","ipVersion","mapsUrl","metadata","contacts","loc_disclaimer","support"]}}}},"400":{"description":"Bad request — invalid IP address or unsupported location.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["error"]},"message":{"type":"string"}},"required":["status","message"]}}}},"404":{"description":"Not found — requested location could not be resolved.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["error"]},"message":{"type":"string"}},"required":["status","message"]}}}},"500":{"description":"Upstream lookup failed.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["error"]},"message":{"type":"string"}},"required":["status","message"]}}}}}}},"/m365/messagecenter/publish":{"post":{"tags":["M365 Message Center Publisher API (Internal)"],"summary":"INTERNAL: Fetches Microsoft 365 Message Center posts for a time period (default: yesterday) and publishes them to the Tophhie Cloud Blog.","security":[{"ApiKeyAuth":[]}],"operationId":"post_StartMessageCenterPublisher","parameters":[{"schema":{"type":"number","exclusiveMinimum":0,"description":"Rolling window: publish messages from the last N hours (ending now). Mutually exclusive with from/to."},"required":false,"description":"Rolling window: publish messages from the last N hours (ending now). Mutually exclusive with from/to.","name":"lastHours","in":"query"},{"schema":{"type":"string","description":"Start of the window as an ISO 8601 datetime (inclusive). Requires no lastHours."},"required":false,"description":"Start of the window as an ISO 8601 datetime (inclusive). Requires no lastHours.","name":"from","in":"query"},{"schema":{"type":"string","description":"End of the window as an ISO 8601 datetime (exclusive). Defaults to now; only valid alongside from."},"required":false,"description":"End of the window as an ISO 8601 datetime (exclusive). Defaults to now; only valid alongside from.","name":"to","in":"query"},{"schema":{"type":"string","description":"Internal API key for authorising this operation."},"required":true,"description":"Internal API key for authorising this operation.","name":"x-tc-api-key","in":"header"}],"responses":{"200":{"description":"Publisher completed.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"},"total":{"type":"number"},"succeeded":{"type":"number"},"failed":{"type":"number"},"skipped":{"type":"number","description":"Number of posts skipped because a Ghost post with that Message Center ID already exists."},"blueskySucceeded":{"type":"number","description":"Number of posts also cross-posted to Bluesky."},"blueskyFailed":{"type":"number","description":"Number of Bluesky cross-posts that failed (independent of the Ghost publish)."}},"required":["message","total","succeeded","failed","skipped","blueskySucceeded","blueskyFailed"]}}}},"400":{"description":"Bad request — invalid time period parameters.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"403":{"description":"Forbidden — invalid or missing API key.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}}}},"/m365/messagecenter/deduplicate":{"post":{"tags":["M365 Message Center Publisher API (Internal)"],"summary":"INTERNAL: Finds and removes duplicate Message Center posts on the Tophhie Cloud Blog (auto-suffixed slugs like 'mc123456-2'). Dry-run by default.","security":[{"ApiKeyAuth":[]}],"operationId":"post_DeduplicateMessageCenterPosts","parameters":[{"schema":{"type":"string","enum":["true","false"],"description":"When 'true' (the default), only report duplicates without deleting. Pass 'false' to actually delete them."},"required":false,"description":"When 'true' (the default), only report duplicates without deleting. Pass 'false' to actually delete them.","name":"dryRun","in":"query"},{"schema":{"type":"string","description":"Internal API key for authorising this operation."},"required":true,"description":"Internal API key for authorising this operation.","name":"x-tc-api-key","in":"header"}],"responses":{"200":{"description":"Deduplication completed.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"},"dryRun":{"type":"boolean"},"scanned":{"type":"number"},"duplicatesFound":{"type":"number"},"deleted":{"type":"number"},"failed":{"type":"number"},"duplicates":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"slug":{"type":"string"},"title":{"type":"string"},"url":{"type":"string"},"deleted":{"type":"boolean"}},"required":["id","slug","title","url","deleted"]}}},"required":["message","dryRun","scanned","duplicatesFound","deleted","failed","duplicates"]}}}},"403":{"description":"Forbidden — invalid or missing API key.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}}}},"/policies/getAllPolicies":{"get":{"tags":["Policies API"],"summary":"Fetches the list of policies currently applied to Tophhie Cloud.","operationId":"get_GetPolicies","responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{}}}}}}},"/blog/info":{"get":{"tags":["Tophhie Cloud Blog API"],"summary":"Get generic information about the Tophhie Cloud Blog.","operationId":"get_GetBlogInfo","responses":{"200":{"description":"OK.","content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string"},"description":{"type":"string"},"logo":{"type":["string","null"],"default":null},"icon":{"type":["string","null"],"default":null},"accent_color":{"type":["string","null"],"default":null},"facebook":{"type":["string","null"],"default":null},"twitter":{"type":["string","null"],"default":null},"locale":{"type":"string"},"timezone":{"type":"string"},"members_support_address":{"type":"string"},"lang":{"type":"string"},"url":{"type":"string"}},"required":["title","description","locale","timezone","members_support_address","lang","url"]}}}},"500":{"description":"Error fetching blog information.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}}}}}}},"/blog/authors":{"get":{"tags":["Tophhie Cloud Blog API"],"summary":"Fetch the list of authors for the Tophhie Cloud Blog.","operationId":"get_GetBlogAuthors","responses":{"200":{"description":"OK.","content":{"application/json":{"schema":{"type":"object","properties":{"authors":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"profile_image":{"type":["string","null"],"default":null},"cover_image":{"type":["string","null"],"default":null},"bio":{"type":["string","null"],"default":null},"website":{"type":["string","null"],"default":null},"location":{"type":["string","null"],"default":null},"facebook":{"type":["string","null"],"default":null},"twitter":{"type":["string","null"],"default":null},"meta_title":{"type":["string","null"],"default":null},"meta_description":{"type":["string","null"],"default":null},"threads":{"type":["string","null"],"default":null},"bluesky":{"type":["string","null"],"default":null},"mastodon":{"type":["string","null"],"default":null},"tiktok":{"type":["string","null"],"default":null},"youtube":{"type":["string","null"],"default":null},"instagram":{"type":["string","null"],"default":null},"linkedin":{"type":["string","null"],"default":null},"url":{"type":"string"}},"required":["id","name","slug","url"]}}},"required":["authors"]}}}},"500":{"description":"Error fetching blog authors.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}}}}}}},"/blog/posts/m365-message-center":{"get":{"tags":["Tophhie Cloud Blog API"],"summary":"Fetch Microsoft 365 Message Center posts from the Tophhie Cloud Blog.","operationId":"get_GetM365MessageCenterPosts","parameters":[{"schema":{"type":"string","default":"1","description":"Page number."},"required":false,"description":"Page number.","name":"page","in":"query"},{"schema":{"type":"string","default":"15","description":"Number of posts per page."},"required":false,"description":"Number of posts per page.","name":"limit","in":"query"}],"responses":{"200":{"description":"OK.","content":{"application/json":{"schema":{"type":"object","properties":{"next_page":{"type":["string","null"],"format":"uri"},"posts":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"uuid":{"type":"string"},"title":{"type":"string"},"featured":{"type":"boolean"},"visibility":{"type":"string"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"published_at":{"type":"string","format":"date-time"},"custom_excerpt":{"type":["string","null"],"default":null},"url":{"type":"string"},"excerpt":{"type":"string"},"custom_data":{"type":["object","null"],"properties":{"mc_id":{"type":"string"}},"default":null}},"required":["id","uuid","title","featured","visibility","created_at","updated_at","published_at","url","excerpt"]}}},"required":["next_page","posts"]}}}},"500":{"description":"Error fetching M365 Message Center posts.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}}}}}}},"/blog/posts/{id}":{"get":{"tags":["Tophhie Cloud Blog API"],"summary":"Fetch a specific blog post by its ID.","operationId":"get_GetBlogPost","parameters":[{"schema":{"type":"string","description":"The ID of the blog post."},"required":true,"description":"The ID of the blog post.","name":"id","in":"path"}],"responses":{"200":{"description":"OK.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"uuid":{"type":"string"},"title":{"type":"string"},"featured":{"type":"boolean"},"visibility":{"type":"string"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"published_at":{"type":"string","format":"date-time"},"custom_excerpt":{"type":["string","null"],"default":null},"url":{"type":"string"},"excerpt":{"type":"string"},"custom_data":{"type":["object","null"],"properties":{"mc_id":{"type":"string"}},"default":null}},"required":["id","uuid","title","featured","visibility","created_at","updated_at","published_at","url","excerpt"]}}}},"500":{"description":"Error fetching blog post.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}}}}}}},"/blog/posts":{"get":{"tags":["Tophhie Cloud Blog API"],"summary":"Fetch the list of blog posts for the Tophhie Cloud Blog.","operationId":"get_GetBlogPosts","parameters":[{"schema":{"type":"string","default":"1","description":"Page number."},"required":false,"description":"Page number.","name":"page","in":"query"},{"schema":{"type":"string","default":"15","description":"Number of posts per page."},"required":false,"description":"Number of posts per page.","name":"limit","in":"query"}],"responses":{"200":{"description":"OK.","content":{"application/json":{"schema":{"type":"object","properties":{"next_page":{"type":["string","null"],"format":"uri"},"posts":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"uuid":{"type":"string"},"title":{"type":"string"},"featured":{"type":"boolean"},"visibility":{"type":"string"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"published_at":{"type":"string","format":"date-time"},"custom_excerpt":{"type":["string","null"],"default":null},"url":{"type":"string"},"excerpt":{"type":"string"},"custom_data":{"type":["object","null"],"properties":{"mc_id":{"type":"string"}},"default":null}},"required":["id","uuid","title","featured","visibility","created_at","updated_at","published_at","url","excerpt"]}}},"required":["next_page","posts"]}}}},"500":{"description":"Error fetching blog posts.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}}}}}}},"/pds/repos":{"get":{"tags":["Tophhie Social (PDS)"],"summary":"Retrieves the list of repositories currently stored on Tophhie Social.","operationId":"get_GetRepos","responses":{"200":{"description":"OK.","content":{"application/json":{"schema":{"type":"object","properties":{"total":{"type":"number"},"active":{"type":"number"},"inactive":{"type":"number"},"repos":{"type":"array","items":{"type":"object","properties":{"did":{"type":"string"},"head":{"type":"string"},"rev":{"type":"string"},"active":{"type":"boolean"},"status":{"type":["string","null"]}},"required":["did","head","rev","active"]}}},"required":["total","active","inactive","repos"]}}}}}}},"/pds/verifyHandle":{"get":{"tags":["Tophhie Social (PDS)"],"summary":"Verifies if a given handle is available in the Tophhie Social PDS.","operationId":"get_CheckHandleAvail","parameters":[{"schema":{"type":"string","description":"Handle you'd like to check."},"required":true,"description":"Handle you'd like to check.","name":"handle","in":"query"}],"responses":{"200":{"description":"OK.","content":{"application/json":{"schema":{"type":"object","properties":{"available":{"type":"boolean"}},"required":["available"]}}}}}}},"/pds/tls-check":{"get":{"tags":["Tophhie Social (PDS)"],"summary":"Check if a domain or handle is allowed for TLS certificate validation. Used for Caddy SSL certificate issuance.","operationId":"get_TlsCheck","parameters":[{"schema":{"type":"string"},"required":true,"name":"domain","in":"query"}],"responses":{"200":{"description":"OK.","content":{"text/plain":{"schema":{"type":"string"}}}},"400":{"description":"Input Validation Error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"errors":{"type":"array","items":{"type":"object","properties":{"code":{"type":"number","example":7001},"message":{"type":"string","example":"Input Validation Error"},"path":{"type":"array","items":{"type":"string","example":"body"}}},"required":["code","message","path"]}}},"required":["success","errors"]}}}}}}},"/pds/blueskyHeatmap":{"get":{"tags":["Tophhie Social (PDS)"],"summary":"Retrieves Bluesky heatmap data for Tophhie Social repositories. Returns current year by default or can filter by specified year.","operationId":"get_GetHeatmapData","parameters":[{"schema":{"type":"string"},"required":false,"name":"forYear","in":"query"}],"responses":{"200":{"description":"OK.","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"number"}}}}}}}},"/pds/blobStorageUsageBytes":{"get":{"tags":["Tophhie Social (PDS)"],"summary":"Retrieves the current blob storage usage in bytes for Tophhie Social PDS.","operationId":"get_GetBlobStorageUsage","responses":{"200":{"description":"OK.","content":{"application/json":{"schema":{"type":"object","properties":{"usageBytes":{"type":"string"},"blobCount":{"type":"number"}},"required":["usageBytes","blobCount"]}}}}}}},"/pds/blobStorageStats":{"get":{"tags":["Tophhie Social (PDS)"],"summary":"Retrieves the current blob storage usage in bytes for Tophhie Social PDS.","operationId":"get_GetBlobStorageUsage","responses":{"200":{"description":"OK.","content":{"application/json":{"schema":{"type":"object","properties":{"usageBytes":{"type":"string"},"blobCount":{"type":"number"}},"required":["usageBytes","blobCount"]}}}}}}},"/pds/blobStorageUsageBytes/{did}":{"get":{"tags":["Tophhie Social (PDS)"],"summary":"Retrieves the current blob storage usage in bytes for a specific DID in Tophhie Social PDS.","operationId":"get_GetBlobStorageUsageForDid","parameters":[{"schema":{"type":"string","pattern":"^(did:(plc|web))[a-zA-Z0-9:\\-\\.]*$"},"required":true,"name":"did","in":"path"}],"responses":{"200":{"description":"OK.","content":{"application/json":{"schema":{"type":"object","properties":{"usageBytes":{"type":"string"},"blobCount":{"type":"number"}},"required":["usageBytes","blobCount"]}}}}}}},"/pds/uptimeStats":{"get":{"tags":["Tophhie Social (PDS)"],"summary":"Retrieves uptime statistics for Tophhie Social.","operationId":"get_GetUptime","parameters":[{"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"required":false,"name":"startDate","in":"query"},{"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"required":false,"name":"endDate","in":"query"}],"responses":{"200":{"description":"OK.","content":{"application/json":{"schema":{"type":"object","properties":{"availability":{"type":"number"},"total_downtime":{"type":"number"},"number_of_incidents":{"type":"number"},"longest_incident":{"type":"number"},"average_incident":{"type":"number"}},"required":["availability","total_downtime","number_of_incidents","longest_incident","average_incident"]}}}}}}}},"webhooks":{}}