Log time from your own tools

Time entries record the minutes a person worked on a project, or on one task within it, on one day. With an API key you can log time for anyone in your organization whose time is tracked, then correct or remove it while their week is still open.

The rules in brief
  • Minutes only. Every duration is a whole number of minutes, from 1 to 1440 per entry. A person's entries for one day can add up to 1440 minutes at most. Dates are YYYY-MM-DD in your organization's time zone and cannot be in the future.
  • Submitted weeks are locked. Once a person submits a week, every create, update or delete that touches it answers 409 until the week is unlocked in OnRamp. Entries in a locked week come back with "locked": true.
  • Allotted time lives on tasks. A project's allotted time is the sum of its tasks' allotted minutes; there is no separate project budget to set. Time logged without a task counts toward the project but not toward any task.
  • Creates are retry-safe. If a create times out, send the identical request again within 10 minutes. When the first one landed, you get that entry back with 200 instead of 201, and no duplicate is written. Updates and deletes are not matched this way, so re-read the entry before repeating one.
Log an entry

Send task_uuid to log time on a task (its project is implied), or only project_uuid for general project time.

curl -X POST -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"user_uuid": "USER_UUID", "task_uuid": "TASK_UUID", "entry_date": "2026-09-21", "minutes": 90, "note": "Kickoff call"}' \
  "https://api.onramp.us/v1/time-entries"
import requests

response = requests.post(
    "https://api.onramp.us/v1/time-entries",
    headers={"Authorization": "Bearer YOUR_API_KEY"},
    json={"user_uuid": "USER_UUID", "task_uuid": "TASK_UUID", "entry_date": "2026-09-21", "minutes": 90, "note": "Kickoff call"},
)
created = response.status_code == 201
entry = response.json()["data"]
Correct or remove an entry

PUT /v1/time-entries/{entry_uuid} changes only the fields you send, for example {"minutes": 45}. An entry cannot be moved to another person; delete it and log a new one instead. DELETE /v1/time-entries/{entry_uuid} removes it.

Compare allotted and worked time

GET /v1/time-tracking/reports/allotted-vs-worked returns one row per project, broken down into modules and then tasks. Worked minutes are the time logged against the project's tasks within the window (start and end; by default the 90 days ending today in your organization's time zone). Allotted minutes are the tasks' current allotted time and do not depend on the window. Time logged without a task, and time on a removed task, is not part of this report.

A task is estimated when its allotted_minutes is set. Variance is measured differently at each level:

  • Task. variance_minutes is worked_minutes - allotted_minutes, and is null when the task's allotted_minutes is null.
  • Module and project. allotted_minutes is the sum of the estimated tasks' allotted minutes, and estimated_worked_minutes is the time logged against those same tasks only. variance_minutes is estimated_worked_minutes - allotted_minutes, not worked_minutes - allotted_minutes, and is null when allotted_minutes is 0. consumed and the project's variance_pct divide by allotted_minutes and are null in the same case.
  • Unestimated work. A project's not_estimated counts its tasks with no allotted time (task_count, whether or not anyone logged time on them) and the minutes logged against them (worked_minutes). That time is in worked_minutes but never in estimated_worked_minutes, so it cannot push a project over or under its estimate.

A project's allotted_minutes, worked_minutes and estimated_worked_minutes are always integers, 0 when nothing on it is estimated. Tasks outside any module are grouped under a module named General / no module whose module_uuid is null.

Projects come largest overrun first, by variance_minutes, with projects that have no variance last.