Common workflows
End-to-end Hoursmith API examples — create a client and project, log time, and read back invoices.
These walkthroughs stitch the endpoints together into real tasks. They assume a $TOKEN
environment variable holding your API token and use the base URL
https://hoursmith.app/api/v1.
Set up a client and project
# 1. Create a client (POST requires an Idempotency-Key)
curl https://hoursmith.app/api/v1/clients \
-H "Authorization: Bearer $TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{ "name": "Globex", "email": "billing@globex.com", "currency": "USD" }'
# Response: { "data": { "id": "cl_...", "name": "Globex", ... } }
# 2. Create an hourly project for that client
curl https://hoursmith.app/api/v1/projects \
-H "Authorization: Bearer $TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{ "clientId": "cl_...", "name": "Website redesign" }'See the exact accepted fields on Create a client and Create a project.
Log time
The canonical way to record time is durationSeconds. You can also send a human duration string
like "1h30m" or "1:30".
curl https://hoursmith.app/api/v1/time-entries \
-H "Authorization: Bearer $TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"projectId": "pr_...",
"entryDate": "2026-06-11",
"durationSeconds": 5400,
"note": "Homepage layout",
"billable": true
}'await fetch('https://hoursmith.app/api/v1/time-entries', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.HOURSMITH_API_TOKEN}`,
'Idempotency-Key': crypto.randomUUID(),
'Content-Type': 'application/json',
},
body: JSON.stringify({
projectId: 'pr_...',
entryDate: '2026-06-11',
duration: '1h30m',
note: 'Homepage layout',
}),
});Check the running timer
curl "https://hoursmith.app/api/v1/time-entries?running=true&limit=1" \
-H "Authorization: Bearer $TOKEN"Pull a month of time for a project
curl "https://hoursmith.app/api/v1/time-entries?projectId=pr_...&entryDateFrom=2026-06-01&entryDateTo=2026-06-30&sort=-entryDate&limit=200" \
-H "Authorization: Bearer $TOKEN"Then page with the nextCursor until it's null.
Find unpaid invoices
Invoices are read-only over the API. List the sent ones and check each invoice's paymentStatus
field (unpaid, partially_paid, paid, refunded):
curl "https://hoursmith.app/api/v1/invoices?status=sent&sort=-issueDate" \
-H "Authorization: Bearer $TOKEN"const res = await fetch('https://hoursmith.app/api/v1/invoices?status=sent', {
headers: { Authorization: `Bearer ${token}` },
});
const { data } = await res.json();
const unpaid = data.filter((inv) => inv.paymentStatus !== 'paid');Creating and sending invoices stays in the app (or happens automatically as you bill tracked time). The API gives you read access to the results so you can sync them into your own reporting.
Tips for robust integrations
- Generate one
Idempotency-Keyper logical write and reuse it on retries. - Handle
429withRetry-After, and409for locked records. - Store ids you create (client, project) so later calls can reference them.