mytmn-hub
REST API that fetches, normalizes, and caches MyTaman billing data as structured JSON. Integrate using the endpoints below; use the machine-readable OpenAPI spec or Postman collection for your stack.
OpenAPI Spec
GET /openapi.json
Postman Collection
GET /postman/collection.json
Health Check
GET /health
Release notes
GET /release-notes
Base URL
Quick start
1. Authenticate with your MyTaman credentials to get a session token:
# Login curl -X POST https://mytmn.sofehaus.com/api/auth/login \ -H "Content-Type: application/json" \ -d '{"email":"user@example.com","password":"s3cret"}' # Response: {"token":"c0a80164-..."}
2. Use the token for all subsequent requests:
# Get your taman profile curl https://mytmn.sofehaus.com/api/profile \ -H "Authorization: Bearer <token>" # List all invoice profiles curl https://mytmn.sofehaus.com/api/billing/invoices \ -H "Authorization: Bearer <token>" # Get stats for a specific invoice curl https://mytmn.sofehaus.com/api/billing/invoices/9978/stats \ -H "Authorization: Bearer <token>"
3. Logout when done (invalidates token + clears cache):
curl -X POST https://mytmn.sofehaus.com/api/auth/logout \
-H "Authorization: Bearer <token>"
API reference
GET /health
Service health check. No authentication required.
// 200 OK { "ok": true, "service": "mytmn-hub" }
POST /api/auth/login
Authenticate with MyTaman. Returns a session token (UUID). The token maps to the upstream session cookie server-side.
| Body Field | Type | Required | Description |
|---|---|---|---|
email | string | Yes | MyTaman email |
password | string | Yes | MyTaman password |
// 201 Created { "token": "c0a80164-1234-5678-9abc-def012345678" }
| Status | Meaning |
|---|---|
201 | Token created |
400 | Invalid JSON or missing email/password |
401 | MyTaman rejected credentials |
POST /api/auth/logout Bearer
Destroy session and evict all cached data for this token. Returns 204 regardless of token validity.
GET /api/profile Bearer
Taman name and address parsed from MyTaman navigation bar. Cached 30 min.
TamanInfo
// 200 OK { "name": "Taman Bukit Indah", "address": "No 1, Jalan Bukit Indah 1/1" }
GET /api/billing/invoices Bearer
All invoice profiles from the dashboard dropdown. Cached 10 min.
InvoiceProfileOption[]
// 200 OK [ { "id": 9978, "name": "Monthly Maintenance", "selected": true }, { "id": 10234, "name": "Sinking Fund", "selected": false } ]
GET /api/billing/invoices/:id/stats Bearer
Billing statistics for one invoice profile. Cached 5 min. The :id is an invoice_profile_id from the list above.
CurrentInvoiceProfile
// 200 OK { "id": 9978, "title": "Monthly Maintenance", "frequency": "Monthly", "startDate": "2024-01-01", "totalIssued": { "count": 271, "amount": 21680.00 }, "totalCollected": { "count": 258, "amount": 19820.00 }, "totalOutstanding": { "count": 13, "amount": 1860.00 }, "paidHouses": { "paid": 279, "unpaid": 18 } }
GET /api/billing/dashboard Bearer
Full composite dashboard: taman info + all invoice profiles + current profile stats. Optional ?profile_id= to load a specific profile. Cached 5 min.
| Query Param | Type | Required | Description |
|---|---|---|---|
profile_id | integer | No | Load specific invoice profile |
// 200 OK { "taman": { "name": "...", "address": "..." }, "profiles": [ ... ], "current": { ... } }
Error handling
All errors return JSON with an error code and optional detail.
ErrorResponse
| Status | Error Code | When |
|---|---|---|
400 | invalid_json | Request body is not valid JSON |
400 | invalid_body | Missing required fields or invalid path param |
401 | unauthorized | Missing / invalid / expired Bearer token |
401 | login_failed | MyTaman rejected credentials or session expired |
404 | not_found | Unknown route |
502 | upstream_error | MyTaman returned non-200 |
500 | internal_error | Unexpected server error |
Caching strategy
Responses are cached in-memory per session token. This reduces load on MyTaman while keeping data reasonably fresh.
| Resource | Cache Key | TTL |
|---|---|---|
| Taman profile | {token}:profile | 30 min |
| Invoice list | {token}:invoices | 10 min |
| Invoice stats | {token}:invoice:{id} | 5 min |
| Full dashboard | {token}:dashboard:{id|default} | 5 min |
POST /api/auth/logout) evicts all cached entries for that session token. Cache entries also self-expire via lazy TTL check on read.
Architecture
How a protected read flows through the hub: session token resolves to a MyTaman cookie; repositories consult the TTL cache before touching upstream.
Authorization: Bearerapplication/json · same shape as OpenAPI schemasNew MyTaman screens follow the same pattern: dedicated fetch module + parser + repository slice, sharing the global CacheStore and session cookie from login.
Release notes
API Changelog below describe changes that may affect your integration (HTTP surface, auth, JSON fields, caching visible to clients). Fetch GET /release-notes for this same content over the wire.
Downloads & tools
baseUrl variable to this API’s base URL, and run Auth > Login first — the test script auto-saves the token for all other requests.