{"openapi":"3.1.0","info":{"title":"FastAPI Template","description":"A template for FastAPI applications with user authentication","version":"1.0.0"},"paths":{"/o/{tracking_id}.png":{"get":{"summary":"Short Track Email Open","description":"Track email opens via a 1x1 transparent PNG pixel (short URL).\n\nThis endpoint is embedded in HTML emails as an invisible image.\nRequests arrive at t.skyp.ai/o/{tracking_id}.png.","operationId":"short_track_email_open_o__tracking_id__png_get","parameters":[{"name":"tracking_id","in":"path","required":true,"schema":{"type":"string","title":"Tracking Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/c/{tracking_id}":{"get":{"summary":"Short Track Link Click","description":"Track link clicks and redirect to the original URL (short URL).\n\nRequests arrive at t.skyp.ai/c/{tracking_id}.","operationId":"short_track_link_click_c__tracking_id__get","parameters":[{"name":"tracking_id","in":"path","required":true,"schema":{"type":"string","title":"Tracking Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/u/{token}":{"post":{"summary":"Short One Click Unsubscribe","description":"Branded subdomain variant of one_click_unsubscribe.","operationId":"short_one_click_unsubscribe_u__token__post","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","title":"Token"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"summary":"Short Unsubscribe Page","description":"Branded subdomain variant of unsubscribe_page.","operationId":"short_unsubscribe_page_u__token__get","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","title":"Token"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/.well-known/oauth-authorization-server":{"get":{"tags":["oauth-discovery"],"summary":"Authorization Server Metadata","operationId":"authorization_server_metadata__well_known_oauth_authorization_server_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/.well-known/oauth-protected-resource/mcp":{"get":{"tags":["oauth-discovery"],"summary":"Protected Resource Metadata","operationId":"protected_resource_metadata__well_known_oauth_protected_resource_mcp_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/.well-known/oauth-protected-resource":{"get":{"tags":["oauth-discovery"],"summary":"Protected Resource Metadata","operationId":"protected_resource_metadata__well_known_oauth_protected_resource_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/oauth/register":{"post":{"tags":["oauth"],"summary":"Register Client","operationId":"register_client_oauth_register_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientRegistrationRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientRegistrationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/oauth/authorize":{"get":{"tags":["oauth"],"summary":"Authorize","operationId":"authorize_oauth_authorize_get","parameters":[{"name":"response_type","in":"query","required":true,"schema":{"type":"string","title":"Response Type"}},{"name":"client_id","in":"query","required":true,"schema":{"type":"string","title":"Client Id"}},{"name":"redirect_uri","in":"query","required":true,"schema":{"type":"string","title":"Redirect Uri"}},{"name":"code_challenge","in":"query","required":true,"schema":{"type":"string","title":"Code Challenge"}},{"name":"code_challenge_method","in":"query","required":false,"schema":{"type":"string","default":"S256","title":"Code Challenge Method"}},{"name":"scope","in":"query","required":false,"schema":{"type":"string","default":"mcp","title":"Scope"}},{"name":"state","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"State"}},{"name":"resource","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Resource"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/oauth/authorize/details":{"get":{"tags":["oauth"],"summary":"Authorize Details","description":"Return client metadata for the consent screen. No auth required.","operationId":"authorize_details_oauth_authorize_details_get","parameters":[{"name":"ticket","in":"query","required":true,"schema":{"type":"string","title":"Ticket"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthorizeDetailsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/oauth/authorize/consent":{"post":{"tags":["oauth"],"summary":"Authorize Consent","description":"Complete the authorization request.\n\nRequires the user's Skyp JWT (bearer) — this is how we bind the issued\nauthorization code to a specific user.","operationId":"authorize_consent_oauth_authorize_consent_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConsentRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConsentResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/oauth/authorize/status":{"get":{"tags":["oauth"],"summary":"Authorize Status","description":"Check whether an authorization code has been exchanged for tokens.","operationId":"authorize_status_oauth_authorize_status_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"code_id","in":"query","required":true,"schema":{"type":"string","title":"Code Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CodeStatusResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/oauth/token":{"post":{"tags":["oauth"],"summary":"Token","operationId":"token_oauth_token_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_token_oauth_token_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/oauth/userinfo":{"get":{"tags":["oauth-userinfo"],"summary":"Userinfo","description":"Return identity info for the bearer token's owner.","operationId":"userinfo_oauth_userinfo_get","parameters":[{"name":"authorization","in":"header","required":true,"schema":{"type":"string","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/SKILL.md":{"get":{"summary":"Serve Skill Md","operationId":"serve_skill_md_SKILL_md_get","responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/SKILL_ADMIN.md":{"get":{"summary":"Serve Skill Admin Md","operationId":"serve_skill_admin_md_SKILL_ADMIN_md_get","responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/":{"get":{"summary":"Root","operationId":"root__get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/health":{"get":{"summary":"Health","description":"Deploy healthcheck: 200 only when the app is serving AND both database\npools are reachable — the app's and DBOS's separate system-DB pool — so\nRailway doesn't cut traffic over to an instance that booted but can't\nreach Postgres or can't start workflows. Railway only probes this at\ndeploy time (it does not restart a running container on failure), so\nruntime detection still needs an external monitor.","operationId":"health_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}}},"components":{"schemas":{"AuthorizeDetailsResponse":{"properties":{"client_id":{"type":"string","title":"Client Id"},"client_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Client Name"},"redirect_uri":{"type":"string","title":"Redirect Uri"},"scope":{"type":"string","title":"Scope"},"resource":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Resource"}},"type":"object","required":["client_id","client_name","redirect_uri","scope","resource"],"title":"AuthorizeDetailsResponse"},"Body_token_oauth_token_post":{"properties":{"grant_type":{"type":"string","title":"Grant Type"},"code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Code"},"redirect_uri":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Redirect Uri"},"code_verifier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Code Verifier"},"refresh_token":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Refresh Token"},"resource":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Resource"},"scope":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Scope"},"client_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Client Id"},"client_secret":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Client Secret"}},"type":"object","required":["grant_type"],"title":"Body_token_oauth_token_post"},"ClientRegistrationRequest":{"properties":{"redirect_uris":{"items":{"type":"string"},"type":"array","minItems":1,"title":"Redirect Uris"},"client_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Client Name"},"grant_types":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Grant Types"},"response_types":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Response Types"},"token_endpoint_auth_method":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Token Endpoint Auth Method"},"scope":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Scope"}},"type":"object","required":["redirect_uris"],"title":"ClientRegistrationRequest"},"ClientRegistrationResponse":{"properties":{"client_id":{"type":"string","title":"Client Id"},"client_secret":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Client Secret"},"client_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Client Name"},"redirect_uris":{"items":{"type":"string"},"type":"array","title":"Redirect Uris"},"grant_types":{"items":{"type":"string"},"type":"array","title":"Grant Types"},"response_types":{"items":{"type":"string"},"type":"array","title":"Response Types"},"token_endpoint_auth_method":{"type":"string","title":"Token Endpoint Auth Method"},"scope":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Scope"}},"type":"object","required":["client_id","redirect_uris","grant_types","response_types","token_endpoint_auth_method"],"title":"ClientRegistrationResponse"},"CodeStatusResponse":{"properties":{"status":{"type":"string","title":"Status"}},"type":"object","required":["status"],"title":"CodeStatusResponse"},"ConsentRequest":{"properties":{"ticket":{"type":"string","title":"Ticket"},"decision":{"type":"string","title":"Decision"}},"type":"object","required":["ticket","decision"],"title":"ConsentRequest"},"ConsentResponse":{"properties":{"redirect_url":{"type":"string","title":"Redirect Url"},"code_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Code Id"}},"type":"object","required":["redirect_url"],"title":"ConsentResponse"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"TokenResponse":{"properties":{"access_token":{"type":"string","title":"Access Token"},"token_type":{"type":"string","title":"Token Type","default":"Bearer"},"expires_in":{"type":"integer","title":"Expires In"},"refresh_token":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Refresh Token"},"scope":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Scope"}},"type":"object","required":["access_token","expires_in"],"title":"TokenResponse"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}},"securitySchemes":{"OAuth2PasswordBearer":{"type":"oauth2","flows":{"password":{"scopes":{},"tokenUrl":"/api/internal/auth/jwt/login"}}}}}}