Error Handling

Keito API v2 returns Harvest-compatible error bodies:

{
  "error": "bad request",
  "error_description": "Missing Keito-Account-Id header"
}

HTTP Status Codes

Code Meaning Common Cause
400 Bad Request Missing Keito-Account-Id, missing required field, invalid value
401 Unauthorized Missing or invalid API key
403 Forbidden User lacks permission for the company or resource
404 Not Found Resource does not exist or is outside the company
409 Conflict Conflict such as starting a timer while another timer is running, restarting a timer without replace_running, or deleting an approved time entry
429 Too Many Requests Rate limit exceeded
500 Internal Server Error Server-side error

Retry Strategy

Do not retry validation, authorization, or conflict errors unchanged. For 429 responses, wait before retrying. For 5xx responses, use exponential backoff starting at 1 second.

Running Timer Conflict

Starting or restarting a running timer returns 409 Conflict when another timer is already active and replace_running was not supplied:

{
  "error": "running_timer_conflict",
  "error_description": "A timer is already running.",
  "message": "A timer is already running.",
  "running_entry": {
    "id": "running_time_entry_id"
  },
  "running_entry_count": 1
}

Resolve this by showing the active timer, stopping it, or retrying the start/restart with replace_running: true when the user or integration explicitly wants to switch timers.

The Keito CLI retries transient network and server errors automatically. Client errors are returned immediately with a deterministic exit code.