Two query parameters decide how much of each record you get back. Neither of them lists individual fields.
| Parameter | What it controls | Default |
|---|---|---|
view | Which of the resource's two field sets you get: summary or detail. | summary on a collection; detail on a single read and on the record a write returns. |
include | Which related records and on-demand fields are filled in. | Nothing extra. |
Paths are relative to https://<your-url>/api/v2, where <your-url> is the address you sign in to plnnrly on, such as acme.plnnrly.com, or your organisation's own domain.
There is no fields parameter
You cannot pick single fields. ?fields=… is 400 unsupported-parameter, and errors[0].detail points you to view. Use view for the field set and include for the extras below.
Summary and detail
Each resource has a summary and a detail field set. On many resources they are the same. Where they differ, the detail set adds the larger fields, such as:
- a work item's
descriptionand its location fields (location_name,location_address,location_latitude,location_longitude) - a worklog's
reasonandbillable_change_reason - a Drive document's
content - a user's
working_hoursandwork_locations
The reference marks which fields are detail-only. In the summary view those fields are absent, not null.
curl -G "https://<your-url>/api/v2/work-items" \
-H "Authorization: Bearer <token>" \
--data-urlencode "view=detail"view=detail on a collection costs 3 rate units in place of 1, or 5 together with with_total=1. On a single read and on a write it costs nothing extra. See Rate limits.
Include
include takes up to five names, separated by commas. Each name is a related record or an on-demand field of the resource you are reading:
curl -G "https://<your-url>/api/v2/work-items" \
-H "Authorization: Bearer <token>" \
--data-urlencode "include=sprint,labels"One row of the answer:
{
"id": 812,
"issue_key": "ACM-12",
"title": "Export timesheets as CSV",
"sprint_id": 31,
"sprint": { "id": 31, "name": "Sprint 14", "is_active": true },
"labels": {
"data": [
{ "id": 5, "name": "Backend", "color": "#ef4444" }
],
"meta": { "count": 1, "truncated": false }
}
// 30 more fields: priority, due_date, estimation, remaining_estimate, order, column_order, version, created_at, updated_at, project_id, task_id, workflow_status_id, work_type_id, parent_id, assignee_id, reporter_id, web_url, workflow_status, parent, assignee, reporter, work_type, comments_count, subtasks_count, attachments_count, child_work_items_count, labels_count, drive_items_count, links_count, links
}
The rules:
- Each name is a single relation or field. A dotted path such as
sprint.projectis400invalid-query-parameter with codedepth_exceeded. Read the next record with its own request. - A sixth name is code
count_exceeded. - An unknown name is code
unknown_include_path, anderrors[].detaillists the names this resource accepts. includeis documented as a parameter on collection reads.
Each name costs extra rate units: 1 for a single related record or a field, 3 for a relation that holds several records. include=sprint,labels costs 1 + 1 + 3 = 5 units. See Rate limits.
The operation page lists every name it accepts, what it returns, and any extra grant it needs. All limits are listed together in Limits at a glance.
One record or several
A relation to one record, such as sprint, is a bare {"id": 31} until you include it. Included, it becomes a short summary of that record. It is null when nothing is linked.
A relation to several records, such as labels, is absent until you include it. Included, it is always wrapped as { "data": [...], "meta": {...} }:
meta.truncatedis always present. It istruewhen there were more rows than the cap.meta.countis the full number of related records, on relations that count them.
With such a relation in include, per_page goes up to 25 instead of 100. A larger value is 400 with code out_of_range.
On-demand fields
Some fields are left out unless you name them in include, because they cost extra work to produce:
| Resource | Field | What it gives you |
|---|---|---|
| Files on a work item or Drive item | url | A download URL, which needs your token. This is the only way to get one. See Files: upload and download. |
| Files on a work item or Drive item | url_expires_at | When url stops working. Always null today: the URL does not expire. |
| Drive documents | content_html | The document as sanitised HTML, with the colours, highlights and @mentions that Markdown cannot hold. |
| Projects | logged_minutes | The minutes logged on the project that you may see. |
Includes that need their own grant
Some includes read another area of plnnrly, and need that area's permission and token scope on top of the operation's own. include=assignee on work items reads users, for example.
Without that grant, a related record in include is 400 with code unknown_include_path, and the detail says it is not available to you. It is not a 403. An on-demand field behaves differently: include=logged_minutes without access to time entries returns logged_minutes: null.
Names you cannot include
- A relation that is always filled in. A work item's
workflow_statusand a worklog'sprojectcome with every row. Naming one is400with codeunknown_include_path, telling you to remove it. - A relation with no summary form. A Drive item's
content_recordis always a bare reference. Naming it is400with codeunknown_include_path; read the record by itscontent_record_id. - Anything, on a resource with nothing to include.
includethere is400unsupported-parameter.
A relation that is always filled in can still come back as a bare {"id": …}, when it points at a record you may not read.
Truncation
A relation that holds several records returns at most 25 of them, or up to 50 for tags. When there are more, three things happen:
- The relation's
meta.truncatedistrue. meta.warningson the response gets an entry with codeinclude_truncated. The status code stays200, and the rest ofdatais unchanged.- The row has a link of the same name in
links, such aslinks.commentsorlinks.labelson a work item. Follow it to page through the full list. Without that link, the warning'sdetailsays that only the first 25 are listed.
{
"data": [
{
"id": 812,
"comments": {
"data": [
// 25 comments, each with id, author_type, author_id, author and created_at
],
"meta": { "truncated": true }
},
"links": {
"self": "https://<your-url>/api/v2/work-items/812",
"comments": "https://<your-url>/api/v2/work-items/812/comments"
// 6 more links: subtasks, links, attachments, child_work_items, labels, drive_items
}
// 33 more fields: issue_key, title, priority, due_date, estimation, remaining_estimate, order, column_order, version, created_at, updated_at, project_id, task_id, workflow_status_id, work_type_id, sprint_id, parent_id, assignee_id, reporter_id, web_url, workflow_status, parent, assignee, reporter, work_type, sprint, comments_count, subtasks_count, attachments_count, child_work_items_count, labels_count, drive_items_count, links_count
}
],
"meta": {
"page": {
// 4 page fields: per_page, next_cursor, prev_cursor, total
},
"warnings": [
{
"code": "include_truncated",
"detail": "The `comments` include returned more than 25 rows; follow links.comments for the rest.",
"parameter": "include"
}
]
},
"links": {
// 3 links: self, next, prev
}
}Never treat a truncated relation as the whole set. Check meta.truncated, or the include_truncated warning.
Every relation that can hold more records than its include returns has such a link, with one exception: a work item has links.labels only while your organisation has the Sprints feature, because GET /labels needs it too. tags needs no link: a project, a customer and a Drive item take at most 50 tags each, and include=tags returns up to 50, so it always holds the whole set.
Changing a set you read through include
Some sets are written as a list of ids, such as label_ids on a work item. The list replaces the whole set: an id you leave out is removed. Before you add or remove one entry, read the full set from the row's link, such as links.labels, not from a truncated include. Then send the full list with your change.
Each list takes a limited number of ids, stated on the field in the reference. plnnrly links any number of labels and documents to a work item, so those sets can grow past that number there. Such a set cannot be replaced through the API: change it in plnnrly.
Actions you can call now
On a single-record read, meta=actions adds the actions you may call on that record right now:
curl "https://<your-url>/api/v2/work-items/ACM-12?meta=actions" \
-H "Authorization: Bearer <token>"{
"data": {
// 40 fields in the detail view: id, issue_key, title, description, priority, due_date, estimation, remaining_estimate, location_name, location_address, location_latitude, location_longitude, order, column_order, version, created_at, updated_at, project_id, task_id, workflow_status_id, work_type_id, sprint_id, parent_id, assignee_id, reporter_id, web_url, workflow_status, parent, assignee, reporter, work_type, sprint, comments_count, subtasks_count, attachments_count, child_work_items_count, labels_count, drive_items_count, links_count, links
},
"meta": {
"actions": ["move", "transition"]
}
}
The list takes your token, your permissions and the record's current state into account. When no action applies, for example with a read-only token, meta.actions is left out.
meta=actions works on single-record reads of resources that have actions, such as work items and sprints. On a collection or a write it is 400 unsupported-parameter. See Actions and state changes.
Warnings
meta.warnings is a list of notes about your request. A warning never changes the status code and never changes data. It appears only when there is something to say.
| Field | Meaning |
|---|---|
code | What happened. Switch on this, never on detail. |
detail | An explanation in English. |
pointer | The field in your request body the warning is about, as a JSON pointer such as /is_overtime. |
parameter | The query parameter the warning is about, such as include. |
sunset | For a deprecation: the date it stops working. |
replacement | For a deprecation: what to use instead. |
The codes:
| Code | Meaning |
|---|---|
include_truncated | An included relation hit its cap. See Truncation. |
input_ignored | A field in your write was dropped because your permissions do not cover it. The rest of the write was applied. pointer names the field. |
already_in_target_state | A restore found the record already restored, so nothing changed. |
signed_url_unavailable | A file's download url could not be made, so it is null. See Files: upload and download. |
deprecated_field, deprecated_parameter, deprecated_endpoint | You used something that is deprecated. See Headers and versioning. |
New codes can be added. Treat a code you do not know as a note to log, never as an error. Each operation page lists the codes it can return.
After every write, check meta.warnings for input_ignored. Without that check, a dropped field goes unnoticed.
Related
- Pagination: page through the full list a truncated relation links to.
- Data formats: what absent,
nulland[]mean. - Rate limits: what
viewandincludecost.