Node SDK: Time Entries

Create a Time Entry

const entry = await keito.timeEntries.create({
  project_id: 'prj_abc',
  task_id: 'tsk_001',
  spent_date: '2026-03-06',
  hours: 1.5,
  notes: 'Refactored authentication module',
  source: 'agent',
  metadata: {
    agent_id: 'review-bot-01',
    agent_type: 'claude-code',
    session_id: crypto.randomUUID(),
    model: 'claude-opus-4-6',
  },
});

Start a Running Timer

const timer = await keito.timeEntries.startTimer({
  project_id: 'prj_abc',
  task_id: 'tsk_001',
  spent_date: new Date().toISOString().split('T')[0],
  source: 'agent',
  replace_running: true,
  metadata: {
    agent_id: 'review-bot-01',
    session_id: crypto.randomUUID(),
  },
});

Omit started_time for a current, exact server-side start. started_time and ended_time are HH:mm workspace-time strings, not ISO timestamps. If another timer is already running, the API returns 409 Conflict unless you pass replace_running: true.

Stop a Timer

await keito.timeEntries.stopTimer(timer.id, {
  notes: 'Completed code review',
});

The API calculates elapsed duration server-side from the timer start state.

Restart a Timer

await keito.timeEntries.restartTimer(timer.id, {
  replace_running: true,
});

List Time Entries

// All agent entries for a project this week
const entries = await keito.timeEntries.list({
  source: 'agent',
  project_id: 'prj_abc',
  from: '2026-03-01',
  to: '2026-03-06',
});

for (const entry of entries.data) {
  console.log(`${entry.spent_date}: ${entry.hours}h — ${entry.notes}`);
}

Pagination

let page = await keito.timeEntries.list({
  project_id: 'prj_abc',
  page: 1,
  per_page: 50,
});

while (true) {
  for (const entry of page.data) {
    console.log(entry.id);
  }

  if (!page.hasNextPage()) break;
  page = await page.nextPage();
}

Delete a Time Entry

await keito.timeEntries.delete('te_abc123');