{"openapi":"3.0.3","info":{"title":"mytmn-hub","version":"1.1.0","description":"REST API that fetches and caches MyTaman (mytaman.com) billing data from the web app. Authenticate once, then query structured JSON for invoice profiles, billing statistics, and taman info.","contact":{"name":"mytmn-hub"},"license":{"name":"MIT"}},"servers":[{"url":"http://localhost:8787","description":"Local dev"}],"tags":[{"name":"Health","description":"Service health"},{"name":"Documentation","description":"Specs, tooling, and changelog"},{"name":"Auth","description":"Session management (login / logout)"},{"name":"Profile","description":"Taman / user profile info"},{"name":"Billing","description":"Invoice profiles and billing statistics"}],"paths":{"/health":{"get":{"tags":["Health"],"summary":"Health check","operationId":"healthCheck","responses":{"200":{"description":"Service is running","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","example":true},"service":{"type":"string","example":"mytmn-hub"}}}}}}}}},"/release-notes":{"get":{"tags":["Documentation"],"summary":"Release notes (changelog)","operationId":"getReleaseNotes","description":"Public API changelog only (Markdown). Omits internal development; see repo `CHANGELOG.md` section **Internal** for full project history.","responses":{"200":{"description":"Markdown body","content":{"text/markdown":{"schema":{"type":"string"}}}}}}},"/api/auth/login":{"post":{"tags":["Auth"],"summary":"Login with MyTaman credentials","operationId":"login","description":"Authenticates against mytaman.com and returns a session token. The token is an opaque UUID that maps to the upstream session cookie. Use it as `Authorization: Bearer <token>` for all protected endpoints.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginRequest"}}}},"responses":{"201":{"description":"Authenticated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginResponse"}}}},"400":{"description":"Invalid JSON or missing fields","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"MyTaman login failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/auth/logout":{"post":{"tags":["Auth"],"summary":"Destroy session","operationId":"logout","description":"Deletes the in-memory session and evicts all cached data for this token.","security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Session destroyed (or token was already invalid)"}}}},"/api/profile":{"get":{"tags":["Profile"],"summary":"Get taman info","operationId":"getProfile","description":"Returns taman name and address extracted from the MyTaman dashboard navigation bar. Cached for 30 minutes per session.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Taman info","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TamanInfo"}}}},"401":{"description":"Missing or invalid token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/billing/invoices":{"get":{"tags":["Billing"],"summary":"List invoice profiles","operationId":"listInvoiceProfiles","description":"Returns all invoice profile options available in the dashboard dropdown. The `selected` field indicates which profile is currently active. Cached for 10 minutes per session.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Array of invoice profiles","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/InvoiceProfileOption"}}}}},"401":{"description":"Missing or invalid token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/billing/invoices/{id}/stats":{"get":{"tags":["Billing"],"summary":"Get invoice profile statistics","operationId":"getInvoiceStats","description":"Returns billing statistics for a specific invoice profile: title, frequency, start date, total issued/collected/outstanding, and paid vs unpaid house counts. Cached for 5 minutes per session.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Invoice profile ID (from `/api/billing/invoices`)","schema":{"type":"integer","example":9978}}],"responses":{"200":{"description":"Invoice profile statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CurrentInvoiceProfile"}}}},"401":{"description":"Missing or invalid token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/billing/dashboard":{"get":{"tags":["Billing"],"summary":"Full billing dashboard","operationId":"getBillingDashboard","description":"Returns the complete billing dashboard: taman info, all invoice profiles, and current profile statistics. Optionally load a specific profile via `profile_id` query parameter. Cached for 5 minutes per session.","security":[{"bearerAuth":[]}],"parameters":[{"name":"profile_id","in":"query","required":false,"description":"Load a specific invoice profile (default: currently selected)","schema":{"type":"integer","example":9978}}],"responses":{"200":{"description":"Full billing dashboard","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BillingDashboard"}}}},"401":{"description":"Missing or invalid token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"502":{"description":"Upstream MyTaman error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"Token from POST /api/auth/login"}},"schemas":{"LoginRequest":{"type":"object","required":["email","password"],"properties":{"email":{"type":"string","format":"email","example":"user@example.com"},"password":{"type":"string","example":"s3cret"}}},"LoginResponse":{"type":"object","properties":{"token":{"type":"string","format":"uuid","example":"c0a80164-1234-5678-9abc-def012345678"}}},"ErrorResponse":{"type":"object","properties":{"error":{"type":"string","example":"unauthorized"},"detail":{"type":"string","example":"login_failed"}}},"TamanInfo":{"type":"object","properties":{"name":{"type":"string","example":"Taman Bukit Indah"},"address":{"type":"string","example":"No 1, Jalan Bukit Indah 1/1"}}},"BillTotal":{"type":"object","properties":{"count":{"type":"integer","example":271},"amount":{"type":"number","format":"double","example":21680}}},"InvoiceProfileOption":{"type":"object","properties":{"id":{"type":"integer","example":9978},"name":{"type":"string","example":"Monthly Maintenance Fee"},"selected":{"type":"boolean","example":true}}},"CurrentInvoiceProfile":{"type":"object","properties":{"id":{"type":"integer","example":9978},"title":{"type":"string","example":"Monthly Maintenance Fee"},"frequency":{"type":"string","example":"Monthly"},"startDate":{"type":"string","example":"2024-01-01"},"totalIssued":{"$ref":"#/components/schemas/BillTotal"},"totalCollected":{"$ref":"#/components/schemas/BillTotal"},"totalOutstanding":{"$ref":"#/components/schemas/BillTotal"},"paidHouses":{"type":"object","properties":{"paid":{"type":"integer","example":279},"unpaid":{"type":"integer","example":18}}}}},"BillingDashboard":{"type":"object","properties":{"taman":{"$ref":"#/components/schemas/TamanInfo"},"profiles":{"type":"array","items":{"$ref":"#/components/schemas/InvoiceProfileOption"}},"current":{"$ref":"#/components/schemas/CurrentInvoiceProfile"}}}}}}