Mileage, Receipts & Time
API reference for mileage logging, receipt capture, time entries, and project management.
Mileage
List Mileage Entries
JavaScript
const entries = await $fetch('https://dev.taxmtd.uk/api/mileage')
Python
res = requests.get(
"https://dev.taxmtd.uk/api/mileage",
cookies=session_cookies,
)
entries = res.json()["data"]
PHP
$response = Http::withCookies($session)
->get('https://dev.taxmtd.uk/api/mileage');
$entries = $response->json()['data'];
Rust
#[derive(Deserialize)]
struct MileageEntry {
id: i64,
date: String,
from: String,
to: String,
miles: f64,
purpose: String,
vehicle_type: String,
}
let entries: Vec<MileageEntry> = client
.get("https://dev.taxmtd.uk/api/mileage")
.send().await?
.json::<serde_json::Value>().await?["data"]
.as_array().unwrap()
.iter()
.map(|v| serde_json::from_value(v.clone()).unwrap())
.collect();
cURL
curl https://dev.taxmtd.uk/api/mileage
Log Mileage
JavaScript
await $fetch('https://dev.taxmtd.uk/api/mileage', {
method: 'POST',
body: {
date: '2026-03-01',
from: 'London',
to: 'Manchester',
miles: 200,
purpose: 'Client meeting',
vehicleType: 'car' // car, motorcycle, bicycle
}
})
Python
res = requests.post(
"https://dev.taxmtd.uk/api/mileage",
json={
"date": "2026-03-01",
"from": "London",
"to": "Manchester",
"miles": 200,
"purpose": "Client meeting",
"vehicleType": "car",
},
cookies=session_cookies,
)
data = res.json()["data"]
PHP
$response = Http::withCookies($session)->post(
'https://dev.taxmtd.uk/api/mileage',
[
'date' => '2026-03-01',
'from' => 'London',
'to' => 'Manchester',
'miles' => 200,
'purpose' => 'Client meeting',
'vehicleType' => 'car',
]
);
$data = $response->json()['data'];
Rust
let res = client.post("https://dev.taxmtd.uk/api/mileage")
.json(&serde_json::json!({
"date": "2026-03-01",
"from": "London",
"to": "Manchester",
"miles": 200,
"purpose": "Client meeting",
"vehicleType": "car"
}))
.send().await?;
cURL
curl -X POST https://dev.taxmtd.uk/api/mileage \
-H "Content-Type: application/json" \
-d '{"date":"2026-03-01","from":"London","to":"Manchester","miles":200,"purpose":"Client meeting"}'
Update & Delete
JavaScript
// Update
await $fetch('https://dev.taxmtd.uk/api/mileage', {
method: 'PUT',
body: { id: 1, miles: 210, purpose: 'Client meeting (return)' }
})
// Delete
await $fetch('https://dev.taxmtd.uk/api/mileage', {
method: 'DELETE',
body: { id: 1 }
})
Python
# Update
res = requests.put(
"https://dev.taxmtd.uk/api/mileage",
json={"id": 1, "miles": 210, "purpose": "Client meeting (return)"},
cookies=session_cookies,
)
data = res.json()["data"]
# Delete
requests.delete(
"https://dev.taxmtd.uk/api/mileage",
json={"id": 1},
cookies=session_cookies,
)
PHP
// Update
$response = Http::withCookies($session)->put(
'https://dev.taxmtd.uk/api/mileage',
['id' => 1, 'miles' => 210, 'purpose' => 'Client meeting (return)']
);
$data = $response->json()['data'];
// Delete
Http::withCookies($session)->delete(
'https://dev.taxmtd.uk/api/mileage',
['id' => 1]
);
Rust
// Update
let res = client.put("https://dev.taxmtd.uk/api/mileage")
.json(&serde_json::json!({
"id": 1,
"miles": 210,
"purpose": "Client meeting (return)"
}))
.send().await?;
// Delete
let res = client.delete("https://dev.taxmtd.uk/api/mileage")
.json(&serde_json::json!({ "id": 1 }))
.send().await?;
cURL
# Update
curl -X PUT https://dev.taxmtd.uk/api/mileage \
-H "Content-Type: application/json" \
-d '{"id":1,"miles":210}'
# Delete
curl -X DELETE https://dev.taxmtd.uk/api/mileage \
-H "Content-Type: application/json" \
-d '{"id":1}'
HMRC Mileage Rates
| Vehicle | First 10,000 miles | Over 10,000 |
|---|---|---|
| Car/van | 45p/mile | 25p/mile |
| Motorcycle | 24p/mile | 24p/mile |
| Bicycle | 20p/mile | 20p/mile |
Receipts
List Receipts
JavaScript
const receipts = await $fetch('https://dev.taxmtd.uk/api/receipts')
Python
res = requests.get(
"https://dev.taxmtd.uk/api/receipts",
cookies=session_cookies,
)
receipts = res.json()["data"]
PHP
$response = Http::withCookies($session)
->get('https://dev.taxmtd.uk/api/receipts');
$receipts = $response->json()['data'];
Rust
#[derive(Deserialize)]
struct Receipt {
id: i64,
merchant: String,
amount: f64,
date: String,
category: Option<String>,
}
let receipts: Vec<Receipt> = client
.get("https://dev.taxmtd.uk/api/receipts")
.send().await?
.json::<serde_json::Value>().await?["data"]
.as_array().unwrap()
.iter()
.map(|v| serde_json::from_value(v.clone()).unwrap())
.collect();
cURL
curl https://dev.taxmtd.uk/api/receipts
Upload Receipt
JavaScript
await $fetch('https://dev.taxmtd.uk/api/receipts', {
method: 'POST',
body: {
image: 'base64-encoded-image...',
merchant: 'Staples',
amount: 45.99,
date: '2026-03-01',
category: 'office-equipment',
transactionId: 42 // optional: link to transaction
}
})
Python
res = requests.post(
"https://dev.taxmtd.uk/api/receipts",
json={
"image": "base64-encoded-image...",
"merchant": "Staples",
"amount": 45.99,
"date": "2026-03-01",
"category": "office-equipment",
"transactionId": 42,
},
cookies=session_cookies,
)
data = res.json()["data"]
PHP
$response = Http::withCookies($session)->post(
'https://dev.taxmtd.uk/api/receipts',
[
'image' => 'base64-encoded-image...',
'merchant' => 'Staples',
'amount' => 45.99,
'date' => '2026-03-01',
'category' => 'office-equipment',
'transactionId' => 42,
]
);
$data = $response->json()['data'];
Rust
let res = client.post("https://dev.taxmtd.uk/api/receipts")
.json(&serde_json::json!({
"image": "base64-encoded-image...",
"merchant": "Staples",
"amount": 45.99,
"date": "2026-03-01",
"category": "office-equipment",
"transactionId": 42
}))
.send().await?;
cURL
curl -X POST https://dev.taxmtd.uk/api/receipts \
-H "Content-Type: application/json" \
-d '{"merchant":"Staples","amount":45.99,"date":"2026-03-01"}'
Projects
CRUD Operations
JavaScript
// List
const projects = await $fetch('https://dev.taxmtd.uk/api/projects')
// Create
await $fetch('https://dev.taxmtd.uk/api/projects', {
method: 'POST',
body: { name: 'Website Redesign', client: 'Acme Ltd', hourlyRate: 75 }
})
// Update
await $fetch('https://dev.taxmtd.uk/api/projects', {
method: 'PUT',
body: { id: 1, status: 'completed' }
})
// Delete
await $fetch('https://dev.taxmtd.uk/api/projects', {
method: 'DELETE',
body: { id: 1 }
})
Python
# List
res = requests.get(
"https://dev.taxmtd.uk/api/projects",
cookies=session_cookies,
)
projects = res.json()["data"]
# Create
res = requests.post(
"https://dev.taxmtd.uk/api/projects",
json={"name": "Website Redesign", "client": "Acme Ltd", "hourlyRate": 75},
cookies=session_cookies,
)
# Update
requests.put(
"https://dev.taxmtd.uk/api/projects",
json={"id": 1, "status": "completed"},
cookies=session_cookies,
)
# Delete
requests.delete(
"https://dev.taxmtd.uk/api/projects",
json={"id": 1},
cookies=session_cookies,
)
PHP
// List
$projects = Http::withCookies($session)
->get('https://dev.taxmtd.uk/api/projects')
->json()['data'];
// Create
Http::withCookies($session)->post(
'https://dev.taxmtd.uk/api/projects',
['name' => 'Website Redesign', 'client' => 'Acme Ltd', 'hourlyRate' => 75]
);
// Update
Http::withCookies($session)->put(
'https://dev.taxmtd.uk/api/projects',
['id' => 1, 'status' => 'completed']
);
// Delete
Http::withCookies($session)->delete(
'https://dev.taxmtd.uk/api/projects',
['id' => 1]
);
Rust
// List
let projects: serde_json::Value = client
.get("https://dev.taxmtd.uk/api/projects")
.send().await?
.json::<serde_json::Value>().await?["data"]
.clone();
// Create
client.post("https://dev.taxmtd.uk/api/projects")
.json(&serde_json::json!({
"name": "Website Redesign",
"client": "Acme Ltd",
"hourlyRate": 75
}))
.send().await?;
// Update
client.put("https://dev.taxmtd.uk/api/projects")
.json(&serde_json::json!({ "id": 1, "status": "completed" }))
.send().await?;
// Delete
client.delete("https://dev.taxmtd.uk/api/projects")
.json(&serde_json::json!({ "id": 1 }))
.send().await?;
cURL
curl https://dev.taxmtd.uk/api/projects
curl -X POST https://dev.taxmtd.uk/api/projects \
-H "Content-Type: application/json" \
-d '{"name":"Website Redesign","client":"Acme Ltd","hourlyRate":75}'
Time Entries
CRUD Operations
JavaScript
// List
const entries = await $fetch('https://dev.taxmtd.uk/api/time-entries')
// Create
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
}
})
// Update
await $fetch('https://dev.taxmtd.uk/api/time-entries', {
method: 'PUT',
body: { id: 1, duration: 4.0 }
})
// Delete
await $fetch('https://dev.taxmtd.uk/api/time-entries', {
method: 'DELETE',
body: { id: 1 }
})
Python
# List
res = requests.get(
"https://dev.taxmtd.uk/api/time-entries",
cookies=session_cookies,
)
entries = res.json()["data"]
# Create
res = 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,
)
# Update
requests.put(
"https://dev.taxmtd.uk/api/time-entries",
json={"id": 1, "duration": 4.0},
cookies=session_cookies,
)
# Delete
requests.delete(
"https://dev.taxmtd.uk/api/time-entries",
json={"id": 1},
cookies=session_cookies,
)
PHP
// List
$entries = Http::withCookies($session)
->get('https://dev.taxmtd.uk/api/time-entries')
->json()['data'];
// Create
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,
]
);
// Update
Http::withCookies($session)->put(
'https://dev.taxmtd.uk/api/time-entries',
['id' => 1, 'duration' => 4.0]
);
// Delete
Http::withCookies($session)->delete(
'https://dev.taxmtd.uk/api/time-entries',
['id' => 1]
);
Rust
// List
let entries: serde_json::Value = client
.get("https://dev.taxmtd.uk/api/time-entries")
.send().await?
.json::<serde_json::Value>().await?["data"]
.clone();
// Create
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?;
// Update
client.put("https://dev.taxmtd.uk/api/time-entries")
.json(&serde_json::json!({ "id": 1, "duration": 4.0 }))
.send().await?;
// Delete
client.delete("https://dev.taxmtd.uk/api/time-entries")
.json(&serde_json::json!({ "id": 1 }))
.send().await?;
cURL
# List time entries
curl https://dev.taxmtd.uk/api/time-entries
# 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}'
Timing App Integration
Import time entries from the macOS Timing app via Web API or CSV file export.
Connect (Web API)
JavaScript
// Connect via API (bearer token from web.timingapp.com → API Keys)
await $fetch('https://dev.taxmtd.uk/api/timing/connect', {
method: 'POST',
body: { apiToken: 'tmng_your_token_here' }
})
cURL
curl -X POST https://dev.taxmtd.uk/api/timing/connect \
-H "Content-Type: application/json" \
-d '{"apiToken":"tmng_your_token_here"}'
Import Entries
JavaScript
// Import all entries
const result = await $fetch('https://dev.taxmtd.uk/api/timing/import', {
method: 'POST'
})
// → { imported: 47, skipped: 0, projectsCreated: 5, projectsMapped: 0 }
// Import with date range
await $fetch('https://dev.taxmtd.uk/api/timing/import', {
method: 'POST',
body: { startDate: '2026-01-01', endDate: '2026-03-31' }
})
Python
# Import all entries
res = requests.post(
"https://dev.taxmtd.uk/api/timing/import",
cookies=session_cookies,
)
result = res.json()["data"]
# → { imported: 47, skipped: 0, projectsCreated: 5, projectsMapped: 0 }
# Import with date range
res = requests.post(
"https://dev.taxmtd.uk/api/timing/import",
json={"startDate": "2026-01-01", "endDate": "2026-03-31"},
cookies=session_cookies,
)
PHP
// Import all entries
$response = Http::withCookies($session)
->post('https://dev.taxmtd.uk/api/timing/import');
$result = $response->json()['data'];
// Import with date range
Http::withCookies($session)->post(
'https://dev.taxmtd.uk/api/timing/import',
['startDate' => '2026-01-01', 'endDate' => '2026-03-31']
);
Rust
// Import all entries
let result: serde_json::Value = client
.post("https://dev.taxmtd.uk/api/timing/import")
.send().await?
.json::<serde_json::Value>().await?["data"]
.clone();
// Import with date range
client.post("https://dev.taxmtd.uk/api/timing/import")
.json(&serde_json::json!({
"startDate": "2026-01-01",
"endDate": "2026-03-31"
}))
.send().await?;
cURL
curl -X POST https://dev.taxmtd.uk/api/timing/import \
-H "Content-Type: application/json" \
-d '{"startDate":"2026-01-01","endDate":"2026-03-31"}'
List Timing Projects
JavaScript
const projects = await $fetch('https://dev.taxmtd.uk/api/timing/projects')
// → [{ id: '42', title: 'Client Work', parentTitle: null, color: '#ff0000' }]
Python
res = requests.get(
"https://dev.taxmtd.uk/api/timing/projects",
cookies=session_cookies,
)
projects = res.json()["data"]
PHP
$response = Http::withCookies($session)
->get('https://dev.taxmtd.uk/api/timing/projects');
$projects = $response->json()['data'];
Rust
let projects: serde_json::Value = client
.get("https://dev.taxmtd.uk/api/timing/projects")
.send().await?
.json::<serde_json::Value>().await?["data"]
.clone();
cURL
curl https://dev.taxmtd.uk/api/timing/projects
Disconnect
JavaScript
await $fetch('https://dev.taxmtd.uk/api/timing/disconnect', { method: 'POST' })
Python
res = requests.post(
"https://dev.taxmtd.uk/api/timing/disconnect",
cookies=session_cookies,
)
PHP
Http::withCookies($session)
->post('https://dev.taxmtd.uk/api/timing/disconnect');
Rust
client.post("https://dev.taxmtd.uk/api/timing/disconnect")
.send().await?;
cURL
curl -X POST https://dev.taxmtd.uk/api/timing/disconnect
Upload CSV
For users who don't sync to Timing's cloud - export from the app (File → Export Report as CSV), then upload.
JavaScript
const csvContent = '...' // Read from file
const result = await $fetch('https://dev.taxmtd.uk/api/timing/upload', {
method: 'POST',
body: { csv: csvContent }
})
// → { imported: 23, skipped: 0, projectsCreated: 3, projectsMapped: 0 }
cURL
curl -X POST https://dev.taxmtd.uk/api/timing/upload \
-H "Content-Type: application/json" \
-d '{"csv":"Project,Title,Start Date,Duration\nClient Work,Design review,2026-03-01,1.5"}'