NAV
shell ruby python javascript

Redmine API at Planio

Planio is built on top of Redmine, an awesome open source project management software. Hence, the Planio API is 100% compatible to the Redmine REST API with a few additions and enhancements.

The Planio API is using REST (Representational state transfer) and provides the basic CRUD operations being Create, Read, Update, Delete via HTTPS.

As a representation format, the Redmine API (and hence Planio’s REST API) supports JSON and XML. In the following examples, we’ll sometimes use XML and sometimes JSON. However, all API operations support both formats.

Authentication

To get information about your user record using API authentication you could use this code:

curl 'https://example.plan.io/users/current.json' \
  -H 'X-Redmine-API-Key: 0123456789abcdef'

You would get JSON like this in return:

{
  "user": {
    "id": 123,
    "login": "john.doe@example.com",
    "firstname": "John",
    "lastname": "Doe",
    "name": "John Doe",
    "mail": "john.doe@example.com",
    "created_on": "2007-10-06T13:47:36Z",
    "last_login_on": "2016-06-17T18:34:34Z",
    "api_key": "0123456789abcdef",
    "status": 1,
    "custom_fields": [{
      "id": 1,
      "name": "Work Phone",
      "value": "+1234567890"
    }]
  }
}

While some parts of the API can be used without authentication – depending on how you have configured your Planio account – most actions will require requests to be authenticated. In order for the REST API to work, please navigate to your avatarAdministrationSettingsAuthentication and check the box next to Enable REST API.

With the REST API enabled in your Planio account, please navigate to your avatarMy account, open the sidebar and click on Show below the API Access Key header. After confirming your password, Planio will show your API key.

Now, to authenticate API requests, please add a custom HTTP header called X-Redmine-API-Key and supply your API key as a value.

User Impersonation

The following request would impersonate Jane Schmoe:

curl 'https://example.plan.io/users/current.json' \
  -H 'X-Redmine-API-Key: 0123456789abcdef' \
  -H 'X-Redmine-Switch-User: jane.schmoe@example.com'

As an administrator, you can use the API in order to submit requests assuming the identity of another user. In order to do that, please specify the user’s login as a value for the X-Redmine-Switch-User header.

Deprecated authentication methods

For compatibility with the Redmine API, the Planio REST API also supports the following deprecated ways of authentication:

  1. You can use your Planio/Redmine API key and supply it using either

    • as the username part of HTTP Basic Authentication with a random or empty password, or
    • as the value of a query string parameter called key (not recommended, because it may be stored as part of the URL in all sorts of log files).
  2. You can use your regular Planio login (usually your email address) and your password and supply them using HTTP Basic Authentication.

Content type

To change the subject of issue #1 using JSON you could use this:

curl 'https://example.plan.io/issues/1.json' \
  -X PUT \
  -H 'X-Redmine-API-Key: 0123456789abcdef' \
  -H 'Content-Type: application/json' \
  -d '{ "issue": { "subject": "New subject" } }'

The same request using XML would look like this:

curl 'https://example.plan.io/issues/1.xml' \
  -X PUT \
  -H 'X-Redmine-API-Key: 0123456789abcdef' \
  -H 'Content-Type: application/xml' \
  -d '<issue><subject>New subject</subject></issue>'

When working with resources using the Redmine API at Planio, please specify the content type you are expecting to receive/send by using either the .json or .xml suffix in the URL.

When submitting content via POST or PUT, you will also have to specify the format by setting the Content-Type header.

Collections and Pagination

This will return the first 50 issues:

curl 'https://example.plan.io/projects.json?limit=50' \
  -H 'X-Redmine-API-Key: 0123456789abcdef'

To get 10 users starting at the 21st you’d use:

curl 'https://example.plan.io/users.xml?limit=10&offset=20' \
  -H 'X-Redmine-API-Key: 0123456789abcdef'

By default, when querying collection resources (e.g. /projects.json), you will only receive the first 25 objects in the collection.

To receive more objects you can use the following query parameters:

Parameter Default Description
limit 25 The number of objects to return in the response, maximum is 100
offset 0 The index of the first element to return

Associations

To get issue #123 including its history (i.e. journals) and repository commits (i.e. changesets):

curl 'https://example.plan.io/issues/123.xml?include=journals,changesets' \
  -H 'X-Redmine-API-Key: 0123456789abcdef'

Would return something like this:

<issue>

  <id>123</id>
  <subject>This is a bug</subject>
  <description>Please fix it</description>

  <!-- ... -->

  <changesets type="array">
    <changeset revision="42">
      <user id="9" name="John Doe"/>
      <comments>This fixes #123 @1h</comments>
      <committed_on>2016-01-09T09:50:31Z</committed_on>
    </changeset>
  </changesets>

  <journals type="array">
    <journal id="123">
      <user id="9" name="John Doe"/>
      <notes>Status applied in changeset r42.</notes>
      <created_on>2016-01-09T09:50:31Z</created_on>
      <details type="array">
        <detail property="attr" name="status_id">
          <old_value>1</old_value>
          <new_value>3</new_value>
        </detail>
      </details>
    </journal>
  </journals>

</issue>

To save requests, you can specify the associated objects you wish to receive included in your response using the include query parameter.

Parameter Default Description
include A comma-separated list of associations to include

Custom fields

Fetching an issue will include its custom fields:

curl 'https://example.plan.io/issues/123.json' \
  -H 'X-Redmine-API-Key: 0123456789abcdef'

You would get JSON like this in return:

{
  "issue": {
    "id": 123,
    "subject": "A sample issue",
    "custom_fields": [{
      "id": 42,
      "name": "Department",
      "value": "Marketing"
    }]
  }
}

To update issue 123 and set Department to Sales:

curl 'https://example.plan.io/issues/123.json' \
  -X PUT \
  -H 'X-Redmine-API-Key: 0123456789abcdef' \
  -H 'Content-Type: application/json' \
  -d@- <<EOF
  {
    "issue": {
      "custom_fields" : [
        { "id": 42, "value": "Sales" }
      ]
    }
  }
EOF

The same request written in XML would look like this:

curl 'https://example.plan.io/issues/123.xml' \
  -X PUT \
  -H 'X-Redmine-API-Key: 0123456789abcdef' \
  -H 'Content-Type: application/xml' \
  -d@- <<EOF
  <issue>
    <custom_fields type="array">
      <custom_field id="42">
        <value>Sales</value>
      </custom_field>
    </custom_fields>
  </issue>
EOF

One of the strengths of Redmine (and thus Planio) is its customizability. You can define custom fields for most objects in Planio and set/get values via the user interface as well as via the REST API.

No additional URL parameters are required to get/set custom fields. The custom fields array will contain a number of constom field objects with the following attributes:

Attribute Required Description
id yes The internal id of this custom field
value yes The value of the custom field for this object, can be an array if multiple is set to true
name no The name of the custom field
multiple no Is true if the custom field allows multiple values to be set

To set custom fields in a POST or PUT request, be sure to include the custom field id with the request.

The custom field name is supplied when fetching objects via GET, but is’s not required when changing custom field values.

File attachments

Fetching an issue including all attachments:

curl 'https://example.plan.io/issues/123.xml?include=attachments' \
  -H 'X-Redmine-API-Key: 0123456789abcdef'

You would get XML like this in return:

<issue>
  <id>123</id>
  <subject>An issue with an attachment</subject>
  <description>This issue has a file attached to it.</description>
  <!-- ... -->
  <attachments type="array">
    <attachment>
      <id>41</id>
      <filename>example.png</filename>
      <filesize>13832</filesize>
      <content_type>image/png</content_type>
      <description>A sample image</description>
      <content_url>https://example.plan.io/attachments/download/41/example.png</content_url>
      <author id="123" name="John Doe"/>
      <created_on>2016-06-20T12:22:10Z</created_on>
    </attachment>
  </attachments>
</issue>

Some objects (e.g. issues, documents, wiki pages,…) support file attachments. They can be fetched like all other associations by setting the include=attachments query parameter. The attachments array will contain a number of attachment objects with the following attributes:

Attribute Description
id The internal id of this attachment
filename The filename of this attachment
filesize The size of this attachment in bytes
content_type The content type of this attachment, e.g. image/png
description The desription of this attachment
content_url The URL at which the attachment can be downloaded
author The user who has uploaded the attachment, identified by its id and name
created_on The date and time at which the attachment was uploaded

Attaching files to new or existing objects is a two-step process:

  1. Upload the file, receive a token
  2. Create/Update the object, supply the token to attach the file

Uploading a file

To upload the local file example.png, issue a request like this:

curl 'https://example.plan.io/uploads.json' \
  -X POST \
  -H 'X-Redmine-API-Key: 0123456789abcdef' \
  -H 'Content-Type: application/octet-stream' \
  --data-binary @example.png

You will receive an id and a token like this:

{ "upload": { "id": 42, "token": "42.27774ef4d1a1bb92eb305e0b4526767c" } }

POST /uploads.[json|xml]

Simply issue a POST request to while setting the Content-Type header to application/octet-stream and include the file content in the request body.

The response will include the token for your uploaded file.

Attaching a file

To create a new issue and attach the previously uploaded image:

curl 'https://example.plan.io/my-project/issues.json' \
  -X POST \
  -H 'X-Redmine-API-Key: 0123456789abcdef' \
  -H 'Content-Type: application/json' \
  -d@- <<EOF
  {
    "issue": {
      "subject": "A new issue with an image",
      "uploads" : [
        {
          "token": "42.27774ef4d1a1bb92eb305e0b4526767c",
          "filename": "example.png",
          "content_type": "image/png",
          "description": "A sample image"
        }
      ]
    }
  }
EOF

Now, you can create or update an object while supplying the token and file metadata as follows:

Attribute Required Description
token yes The token received in the previous step
filename no The filename for the file attachment
content_type no A content type which should be used to interpret the content, e.g. image/png
description no A short description to be displayed next to the filename

Validation and Errors

Creating a project without supplying a name like this:

curl 'https://example.plan.io/projects.json' \
  -X POST \
  -H 'X-Redmine-API-Key: 0123456789abcdef' \
  -H 'Content-Type: application/json' \
  -d '{ "project": { "description": "This is my project" }}'

Would yield a 422 Unprocessable Entity error response like this:

{
  "errors": [
    "Name can't be blank",
    "Identifier can't be blank"
  ]
}

Most objects in Planio apply constraints to the values being set for its attributes. If an object cannot be created or updated due to any of the constraints not being met, you will receive an HTTP response with status 422 Unprocessable Entity and a body detailing the problem.

Resources

This section provides detailed documentation on all resources available via the Redmine API at Planio.

Issues

A sample issue in XML format:

<issue>
    <id>123</id>
    <project id="1" name="Mission to Mars"/>
    <tracker id="2" name="Support"/>
    <status id="1" name="New"/>
    <priority id="4" name="Normal"/>
    <author id="5" name="John Doe"/>
    <category id="126" name="Maintenance"/>
    <fixed_version id="231" name="Takeoff"/>
    <subject>Rocket booster firmware upgrade</subject>
    <description>
      The current firmware for the rocket boosters
      needs to be updated.
    </description>
    <start_date/>
    <due_date/>
    <done_ratio>0</done_ratio>
    <is_private>false</is_private>
    <estimated_hours>30.0</estimated_hours>
    <spent_hours>0.0</spent_hours>
    <crm_reply_token>abcdef</crm_reply_token>
    <tracking_uri>
      https://example.plan.io/track/123/abcdef
    </tracking_uri>
    <created_on>2016-07-29T10:05:06Z</created_on>
    <updated_on>2016-07-29T10:05:11Z</updated_on>
    <closed_on/>
</issue>

Access issues in your Planio account via this endpoint.

Issue representations can have the following attributes:

Attribute Required Read-only Description
id no yes Internal identifier of this issue
project yes no Project to which the issue belongs, identified by its id and name; see Projects
subject yes no Issue subject
tracker no no Tracker to which the issue belongs, identified by its id and name; see Trackers
status no no Issue status, identified by its id and name; see Issue statuses
priority no no Priority, identified by its id and name; see Issue priorities
author no yes User who created the issue, identified by their id and name; see Users
category no no Issue category, identified by its id and name; see Issue categories
fixed_version no no Sprint/Milestone to which the issue belongs, identified by its id and name; see Sprints/Milestones
description no no Issue description
start_date no no Date on which the issue starts; formatted as YYYY-MM-DD
due_date no no Date on which the issue is due; formatted as YYYY-MM-DD
done_ratio no no % done percentage; an integer from 0-100
is_private no no Whether or not this issue is marked private; boolean
estimated_hours no no Estimated time in hours; specify as float or HH:MM
spent_hours no yes Total time tracked on this issue
crm_reply_token no yes A secret token required to update this issue via email when using CRM & Helpdesk
tracking_uri no yes A secret URI which can be used to view those parts of the issue that are visible to the customer when using CRM & Helpdesk
created_on no yes Date and time at which the issue was created; formatted as ISO 8601 timestamp
updated_on no yes Date and time at which the issue was last updated; formatted as ISO 8601 timestamp
closed_on no yes Date and time at which the issue was last set to a closed status; formatted as ISO 8601 timestamp

The attributes crm_reply_token and tracking_uri are Planio additions which are not present in the standard Redmine API.

Listing issues

GET /issues.[json|xml]

A GET request will return a paginated list of issues.

Possible parameters:

Parameter Default Description
sort Specify an attribute you’d like to sort by; append :desc for reverse the sort order
project_id Filter by project; use a numeric id here
subproject_id Filter by subproject; if you use project_id=123&subproject_id=!*
tracker_id
status_id
assigned_to_id
created_on
updated_on
closed_on
cf_$FIELD
include Using branches as a value will return the list of branches
limit 25 The number of objects to return in the response, maximum is 100
offset 0 The index of the first element to return

Repositories

A sample repository in JSON format:

{
  "repository": {
    "id": 123,
    "project": { "id": 42, "name": "My project" },
    "identifier": "",
    "is_default": true,
    "scm": "git",
    "ssh_url": "git@example.plan.io:my-project.git",
    "branches": [
      { "name": "master" },
      { "name": "feature/acme-widgets" }
    ],
    "disksize": 62828372,
    "created_on": "2016-07-14T17:43:34Z"
  }
}

A sample repository in XML format:

<repository>
  <id>124</id>
  <project id="42" name="My project"/>
  <identifier>documents</identifier>
  <is_default>false</is_default>
  <scm>subversion</scm>
  <is_mirrored>false</is_mirrored>
  <svn_url>https://example.plan.io/svn/my-project.documents</svn_url>
  <disksize>2168821</disksize>
  <created_on>2016-04-16T11:28:59Z</created_on>
</repository>

Access the hosted Git and Subversion repositories within your Planio account via this endpoint.

Repository representations are composed as follows:

Attribute Required Read-only Description
id no yes Internal identifier of this repository
project no yes Project to which the repository belongs, identified by its id and name
identifier no yes Identifier of the repository; one repository per project can have an empty identifier
is_default no yes Specifies whether the repository is the project’s default repository
scm no yes Source control management system used for this repository, either git or subversion
ssh_url no yes SSH clone URL to access the repository; only if scm is git
svn_url no yes Subversion HTTPS URL to access the repository; only if scm is subversion
is_mirrored no yes If this repository is mirrored from an external host; only if scm is git
mirror_from_url no yes URL of the externally hosted repository from where this repository is mirrored; only if is_mirrored is true
branches no yes Array of available branches for this repository
disksize no yes The size of the repository in bytes
created_on no yes Date and time at which the repository was created

The Repositories endpoint is a Planio addition and is not present in the standard Redmine API.

Listing repositories

This will return a list of repositories you have access to:

curl 'https://example.plan.io/repositories.json' \
  -H 'X-Redmine-API-Key: 0123456789abcdef'

GET /repositories.[json|xml]

A GET request will return a paginated list of repositories.

Possible parameters:

Parameter Default Description
include Using branches as a value will return the list of branches
scm Only list repositories of the specified SCM type; possible values are git or subversion or nothing at all
limit 25 The number of objects to return in the response, maximum is 100
offset 0 The index of the first element to return