Time Tracking
Track billable time by project and client for accurate invoicing and profitability analysis.
Dashboard
The Time Tracking dashboard gives you a complete overview of your tracked time:
- Project sidebar - All your projects listed with colour dots and per-project time totals. Click any project to filter the dashboard to just that project's entries.
- Live timer - Start/stop timer with project and description. Compact gradient bar at the top of the dashboard.
- Stats cards - Today's total, this week's total, billable hours with earnings, and active project count.
- Time per Project chart - Stacked bar chart showing hours tracked per project per day.
- Project Breakdown donut - Visual split of time across projects.
- Day-grouped entries - Recent entries grouped by day with per-day totals.
Projects
Manage projects from the dedicated Projects page (Time Tracking → Projects):
| Field | Description |
|---|---|
| Name | Project/client name |
| Rate | Hourly rate (£) |
| Client | Associated client name |
| Colour | Visual identifier across dashboard and charts |
| Status | Active or Archived |
Projects can be created, edited, archived, and deleted. Archiving hides a project from the dashboard sidebar while preserving all linked time entries.
Logging Time
Each time entry records:
- Date and duration (hours:minutes)
- Project association
- Description of work performed
- Billable flag (included on invoices)
Timing App Import
Import time entries from the macOS Timing app with full preview and selection before anything touches your database.
Import Flow
- Click Import on the Time Tracking dashboard
- Choose your source: Web API (with optional date range) or CSV Export (drag-drop file)
- Click Preview to see all projects and entries that would be imported
- Select or deselect individual projects and entries - duplicates are automatically flagged and disabled
- Click Import to bring in only your selected items
API Mode (Cloud)
Connect via the Timing Web API for importing from any device:
- Go to web.timingapp.com → Account → API Keys
- Generate a new API token
- In TaxMTD, click Import → Connect Timing API
- Paste your token and click Connect
CSV Export (Any Timing User)
For users who don't sync Timing data to the cloud - export directly from the app:
- In the Timing app, select the date range you want to export
- Go to File → Export Report and save as CSV
- In TaxMTD, click Import → drop the CSV file → Preview
How It Works
- Preview before import - See exactly what will be imported. Select only the projects and entries you want.
- Project mapping - Timing projects are automatically created as TaxMTD projects on first import. Subsequent imports reuse the mapped project.
- Deduplication - Each imported entry is tagged with a unique
provider_reference. Already-imported entries are flagged as duplicates in the preview and cannot be re-imported. - Date range filtering - Optionally specify start/end dates to import a specific period.
- Entry mapping - Timing's title and notes become the description, duration is converted to hours, and entries are marked as billable by default.
API
JavaScript
// List projects
const projects = await $fetch('https://dev.taxmtd.uk/api/projects')
// Create time entry
await $fetch('https://dev.taxmtd.uk/api/time-entries', {
method: 'POST',
body: {
projectId: 1,
date: '2026-03-01',
duration: 3.5,
description: 'Frontend development',
billable: true
}
})
// Get all time entries
const entries = await $fetch('https://dev.taxmtd.uk/api/time-entries')
Python
# List projects
projects = requests.get(
"https://dev.taxmtd.uk/api/projects",
cookies=session_cookies,
).json()["data"]
# Create time entry
requests.post(
"https://dev.taxmtd.uk/api/time-entries",
json={
"projectId": 1,
"date": "2026-03-01",
"duration": 3.5,
"description": "Frontend development",
"billable": True,
},
cookies=session_cookies,
)
# Get all time entries
entries = requests.get(
"https://dev.taxmtd.uk/api/time-entries",
cookies=session_cookies,
).json()["data"]
PHP
// List projects
$projects = Http::withCookies($session)
->get('https://dev.taxmtd.uk/api/projects')
->json()['data'];
// Create time entry
Http::withCookies($session)
->post('https://dev.taxmtd.uk/api/time-entries', [
'projectId' => 1,
'date' => '2026-03-01',
'duration' => 3.5,
'description' => 'Frontend development',
'billable' => true,
]);
// Get all time entries
$entries = Http::withCookies($session)
->get('https://dev.taxmtd.uk/api/time-entries')
->json()['data'];
Rust
// List projects
let projects = client
.get("https://dev.taxmtd.uk/api/projects")
.send().await?
.json::<serde_json::Value>().await?;
// Create time entry
client.post("https://dev.taxmtd.uk/api/time-entries")
.json(&serde_json::json!({
"projectId": 1,
"date": "2026-03-01",
"duration": 3.5,
"description": "Frontend development",
"billable": true
}))
.send().await?;
// Get all time entries
let entries = client
.get("https://dev.taxmtd.uk/api/time-entries")
.send().await?
.json::<serde_json::Value>().await?;
cURL
# List projects
curl https://dev.taxmtd.uk/api/projects
# Create time entry
curl -X POST https://dev.taxmtd.uk/api/time-entries \
-H "Content-Type: application/json" \
-d '{"projectId":1,"date":"2026-03-01","duration":3.5,"description":"Frontend dev","billable":true}'