stayhomer.png

Treat without the trick!

Be brave and face your Redmine fears Horribly awesome discounts wait for you!

Halloween special offer has begun!

REST API issues timeline

The issues timeline returns the history of status, assignee, sprint, estimates and other Agile fields of issues: the initial state, every change with its time and author, and the final state. Use it to calculate cycle time, lead time, throughput, cumulative flow, sprint scope changes or velocity in your own report. This is a PRO feature. The same data is available to AI clients, see Agile plugin and AI Agent integration.

The request needs the View issues permission. Only visible issues from projects with the Agile module enabled are returned. History is recorded since the Agile plugin 1.7.1 was installed; earlier changes are not restored, and changes made without a journal (direct SQL, imports) are not tracked.

Request

GET /agile/issues_timeline.json?issue_ids[]=45854&fields[status_id]=all&fields[assigned_to_id]=all
GET /agile/issues_timeline.xml?issue_ids[]=45854
Parameter Description
issue_ids[] up to 100 issue ids; invisible ids are skipped
fields[NAME] fields to track: all, or a list of values (see below). Allowed: status_id, assigned_to_id, agile_sprint_id, story_points, estimated_hours, done_ratio, fixed_version_id, tracker_id, priority_id, category_id, parent_id, start_date, due_date. Default: status_id and assigned_to_id
from, to window, dates in UTC; to defaults to today. Events are returned only inside the window, initial is the state at from
mode events (default) or durations
count_only 1: only the total and the number of events per issue
include[] sections of the answer, see below; by default all sections of the mode
limit, offset paging over issues, default 20, maximum 100

Instead of issue_ids you can take every issue that was ever in a sprint: fields[agile_sprint_id][values][]=15. Only the sprint field supports this.

Events mode

Each journal is one event, all fields changed by it are inside. Times are in UTC. Ids are used in events, names are listed once in refs.

GET /agile/issues_timeline.json?issue_ids[]=45854&fields[status_id]=all&fields[assigned_to_id]=all&fields[agile_sprint_id]=all

{
  "issues_timeline": {
    "window": {"from": null, "to": "2026-10-15T09:00:00Z"},
    "total": 1,
    "has_more": false,
    "refs": {
      "statuses": [{"id": 1, "name": "New"}, {"id": 2, "name": "In Progress"}],
      "users": [{"id": 4, "name": "Kirill Bezrukov"}],
      "sprints": [{"id": 1, "name": "Sprint #1 (Oct 13 - Oct 16)"}]
    },
    "issues": [{
      "id": 45854,
      "created_on": "2026-10-14T18:30:11Z",
      "initial": {"status_id": 1, "assigned_to": null, "sprint_id": null},
      "events": [
        {"at": "2026-10-14T20:26:20Z", "journal_id": 278915, "by": 4,
         "sprint_id": {"from": null, "to": 1}},
        {"at": "2026-10-15T06:06:40Z", "journal_id": 278964, "by": 4,
         "status_id": {"from": 1, "to": 2}}
      ],
      "final": {"status_id": 2, "assigned_to": {"id": 4, "type": "User"}, "sprint_id": 1}
    }]
  }
}
  • assigned_to is a user or a group (type is User or Group); a group is never expanded to its members.
  • sprint_id is the sprint of the issue. With fields[agile_sprint_id][values][] you get sprint_member instead, with events entered and left.
  • The creation of an issue is not an event: its state is in initial.
  • null means no value.

Durations mode

mode=durations returns seconds instead of events, in calendar time.

{
  "id": 45854,
  "span": {"from": "2026-10-14T18:30:11Z", "to": "2026-10-15T09:00:00Z", "seconds": 52189},
  "in_status": [{"status_id": 1, "seconds": 41789}, {"status_id": 2, "seconds": 10400}],
  "by_assignee": [{"seconds": 6882}, {"id": 4, "type": "User", "seconds": 45307}],
  "in_status_by_assignee": [
    {"status_id": 1, "seconds": 6882},
    {"status_id": 1, "assignee": {"id": 4, "type": "User"}, "seconds": 34907},
    {"status_id": 2, "assignee": {"id": 4, "type": "User"}, "seconds": 10400}
  ],
  "transitions": [{"status_id": 1, "count": 0}, {"status_id": 2, "count": 1}],
  "sprint_enters": 1
}
  • in_status, by_assignee and in_status_by_assignee each add up to span.seconds. An entry without id and type (or without assignee) is time with nobody assigned.
  • transitions counts entries into each status inside the window.
  • There are no percentiles: take P50 or P85 over the per-issue values in your report.

Choosing sections

include[] trims the answer. Sections of events mode: initial, events, final, refs. Sections of durations mode: initial, span, in_status, by_assignee, in_status_by_assignee, transitions, sprint_enters, final, refs. Issue id, created_on, window, total, has_more and next_offset are always present. A section of the other mode, an unknown section or include together with count_only is an error.

Count only

GET /agile/issues_timeline.json?issue_ids[]=45854&count_only=1

{"issues_timeline": {"total": 1, "issues": [{"id": 45854, "events": 3}]}}

Limits and errors

  • 20 issues per page by default, 100 at most. Use has_more and next_offset for the next page.
  • The number of events in one response is capped; the response stops at an issue boundary and sets has_more. Narrow the window or the selection if you get the error "narrow the window or the selection".
  • A wrong argument gives 422 Unprocessable Entity with {"errors": ["message"]}.

See also REST API Agile Sprint and REST API Agile data.

Was this article helpful? Yes  No