Introduction

Overview

===

The following are REST API cookbook recipes for users and partners creating integrations using The Jama Connect REST API. They intended to answer frequently asked questions from users attempting to create Jama integrations and to encourage best practices in Jama API usage.


THIS IS A LIVING DOCUMENT:

If you or your team have suggestions that should be included in this documentation, Jama is all ears. Talk to us and let us know what pain-points you are experiencing so we can work best practices into the flow.

Cookbook Topics

Jama's Throttling Limits for the API

Jama reserves the right to throttle API usage to ensure a satisfying experience for all our customers. Because REST clients may make unlimited requests, we must protect our systems from slow performance due to these types of calls. We will describe our throttling techniques below.


When will my REST API requests be throttled?

When you exceed 15-requests per seconds and you exceed the 750-request burst limit. Afterwards you will receive 429 response codes.

These throttling rates should be considered temporary as we plan to make changes as our architecture evolves. You may not experience these throttling rates but be prepared to handle them. Stay tuned for more updates.

Efficiently Sync data into and out of Jama through the API

This guide is not intended to provide exact implementation but offer guidance and some best practices for the Jama side of your integration.

Searching for Relevant Data and Detecting the Latest Changes

When integrating with Jama it is important to try to be able to filter on precisely what you are trying to sync without pulling in more data than you need.


Using Abstract Items for Search

Abstract items are the best way to create filters on the fly in our API. You will not be able to create as advanced queries as the filter option, but you do not depend on any filter being set up beforehand. Check out Cookbook section Searching with the Abstract items endpoint for details on how you can select the items you want to be synced from Jama.

Once you have defined the query you want to use, you should be able to page through all the results in an initial import. After that you may use the 'lastActivityDate' query parameter with /abstractitems to find what has changed since your last sync window. You can learn more about the what activities update the last activity date in cookbook section What triggers the Last Activity Date?.


Pros:

· On the fly filter that can be dynamically changed
· Set up requires no interaction in the UI


Cons:

· Paging may not be reliable with real-time data due to the sorting and potential changes in the data between requests.


Using Filters for Search

In Jama's UI you can create advanced filters to query with. This may be a better solution than abstract items if you require more specific items than what abstract items offers. Once you have saved your filter, you may view the results of the filter in the API. Just like with abstract items, you can page through all the results first for your initial sync, and then you can use the lastActivityDate query parameter on the results the same way you would in abstract items. This will allow you to see only what has changed recently so you know what needs to be updated.


Pros:

· Advanced filtering allows for nested AND / OR groupings. You may filter on an items specific location within a project.


Cons:

· You must create the filter in the UI and you cannot update it from the UI.
· Paging may not be reliable with real-time data due to the sorting and potential changes in the data between requests.


Using Activities to Detect Changes

An alternative to using last activity date and filters, you can use the activities endpoint to page through a log of changes made. You will not be able to have the same level of filtering, but you will be able to see events in the order that they happen without missing anything. You will have to use abstract items for your initial sync, but after that you should be able to follow the logs in activities to track changes.


Pros:

· Append only log that is much easier to keep track of changes. No tricky pagination problems with the real-time data
· You can get more detailed information about what has changed.


Cons:

· Only basic filtering, project and item type
· Endpoint lacks documentation and has confusing model.
· Must unwrap batch events


Detecting Comments added to Relevant Items

Last activity date does update when a comment is added directly to an item. For now, you must check for any new comments off the /items/id/comments endpoint.


What is this Realtime Paging Issue?

If you are sort items by its last activity date, you may see items change order when they are updated between your requests. We do not have a good solution for this yet except for using the activities endpoint.


What is the Lagging Index Issue?

An Items last activity date is updated at the time it is committed to the database. There is a small but non-zero amount of time between when then and when you can read the item from the REST API. This means you may not see an item show up in the results when you sort by last activity date. Consider giving yourself a little buffer so that your sync intervals overlap slightly, maybe 5 seconds.


Detecting Changes by Your Integration

You should always consider the modifiedBy attribute on items when reading for changes. If the modifiedBy is from your syncing integration user, that is a strong signal that you do not need to read the item for more changes.


Reading Data From the API

When you have detected that an Item has changed, you will naturally want to download the data and sync it to the other system. Ideally you should be able to the information you need when pulling for changes. If you are using /filters or /abstractitems, you should utilize the includes parameter to download as much as you can without having to make extra calls. You should determine what fields you are interested in so that you can include them on every request. Read more about the includes feature on the Jama developer portal. Basically, it allows you to retrieve all referenced objects on an item, so you do not have to pull for more information in another call.


Downloading Attachments from Rich Text Fields

Jama's rich text editor lets user add images and other attachments to the rich text content. This process is stream lined and does not necessarily work the same way as the attachments widget. When you read the content of a rich text field, you may come across an image or link that looks like this:

https://{jama-base-url}/attachment/65/someImage.png

REST authentication methods don't work for these paths and you must use a work around in order to download the image. You can download the image with our /files endpoint like so:

GET https://{jama-base-url}/rest/v1/files?url=https://{jama-base-url}/attachment/65/someImage.png
* With URL encoding

Writing to Jama with the API

Items can be updated through the API. If the item is locked by someone else, you will have to unlock it or wait for the other user to unlock it. You may also lock an item to prevent others from updating the item while you sync. However, you probably want to make changes as quickly as possible without locking the item for a very long time. We provide two methods for updating an Item, PATCH and PUT.

With PUT, you must provide the entire contents of the item. If a writable field is omitted, the API will assume you want to remove the data from that field. Another problem is that you need to take extra care making sure you have the latest version of the item so that you do not overwrite it with old data that you did not intend to change. To verify that you are updating the item exactly how you expect, it is recommended you follow these steps:

Lock the item

PUT {jama-base-url}/rest/v1/items/{itemId}
{ "locked" : true }

Now get the most recent version of the item.

GET {jama-base-url/rest/v1/items/{itemId}

Copy the "data" object from that response and apply the changes you would like to make using that.

Now use PUT to update the item's content. Note, you cannot update read-only fields. However, if your value matches the existing value on the item, the API will still accept your request. If you supply a read only field value that is different than the existing value, you will get a 400 error.

PUT {jama-base-url}/rest/v1/items{itemId}
{ item payload }

Now unlock the item.

PUT {jama-base-url}/rest/v1/items/{itemId}
{ "locked" : false }

You may choose to not lock the item before using PUT. This is very reasonable because the locking increases the number of requests used to update an Item. However, locking the item does ensure you do not unintentionally overwrite data that has been changes since you retrieved the content of the item.

A better method for updating items is to use PATCH because you do not need to lock the item and get the latest state of the item to make an update without fear of overwriting recent changes. Instead, you will be able to specify exactly which fields you would like to update without affecting anything else in the item. For example, you can update the name and description of an item like this.

PATCH {jama-base-url}/rest/v1/items/{itemId}
[
{
"op": "replace",
"path": "/fields/name",
"value": "Updated Name"
},
{
"op": "replace",
"path": "/fields/description",
"value": "Updated Description"
}
]

Please read more about PATCH here on the Dev channel.


Updatable fields only by API

In your item type configuration, you may specify a field to be read only. When you do this an option will appear to make it editable for the API. This allows you to create fields specifically for your integration and ensures no one in the UI will accidentally edit the value but through the API, you will be able to update the value. If you would like to configure a field like this, edit your item type in the UI Admin screen, and configure the field to be "Read Only" and "Allow API Overwrite".


Updating Test plans, Test Cycles, and Test runs

Test center's API is a little different from your project tree type items. Test Center is built on a work flow that the API is required to follow at the moment. If you need to sync test center items, please refer to cookbook section: '
Executing Tests through the Jama REST API
'


How to update an item

You may use PUT or PATCH. PATCH allows you to update an item without providing the whole context, its more 'atomic'. See Developer Portal


Adding/removing Relationships

Adding and removing relationships should be straight forward with our API. Some project may be configured with relationship rules that you must follow.

To create a relationship, you may make a call like this:

POST {jama-base-url}/rest/v1/relationships
{
"fromItem": 1,
"toItem": 2,
"relationshipType": 12
}

To remove a relationship, you must know the relationship ID. If you know one of the related items, you may find the relationship id with the following methods:

GET {jama-base-url}/rest/v1/abstractitems/{id}/upstreamrelationships
GET {jama-base-url}/rest/v1/abstractitems/{id}/downstreamrelationships


And then to delete the relationship, you may use DELETE:

DELETE {jama-base-url}/rest/v1/relationships/{relationshipId}

You may also call PUT on the relationship if you intend to update the relationship's toItem, fromItem, or relationshipType.


Creating Attachments

Attachments are currently a little more complicated that it should be in the API. Please follow the documentation provided in cookbook sections REST Attachments and Attachments Attachments Attachments!


Creating Comments

If you need to create a comment, use the POST /rest/v1/comments endpoint. You will be able to specify a project or item for the comment location. You may also create a reply to a comment with the inReplyTo field. Just use the ID of the comment you would like to reply to.


Moving an Item

You can move items around in a project with the REST API. You must use the PUT /rest/v1/items/{id}/location endpoint. This endpoint allows you to set the parent of the item, weather it is the project root, or some other item. You will not be able to specify the order the item is placed near its siblings, it will always be placed in the last position. There is no location for test plans, test cycles, or test runs so you cannot update their location.


Links and Tags

Links and Tags may be configured to be added to an item type. There are specific endpoints for each of these item facets. You can GET, PUT, POST, and DELETE tags and links with the /tags and /links endpoints off the item (e.g. /rest/v1/items/{id}/tags or /rest/v1/testplans/{id}/links).

Executing Tests through the Jama REST API

In Jama Connect, there is a flow for executing test cases through the API. This guide will give you an overview of the testing-related objects in Jama Connect and show you the API calls needed to take a test all the way through execution. Some examples will be given from some of our own implementations at Jama.


Getting Familiar with Jama Connect Test Center Objects and Concepts


There are some core objects and concepts to have in mind when working with the Test Center.


Test Case Item


A Test Case Item is like a regular item in Jama, with extra fields (such as steps) and capabilities (it can be executed). Test Cases are created inside Projects just like items, independent of Test Plans. They are also versioned like other items.


Test Run Items


A Test Run Item can be thought of as an execution instance of a Test Case Item. They are created by the system when a Test Cycle is created inside a Test Plan, and they are updated with a status and actual results when executed. A Test Case could have many Test Runs associated with it. These cannot be created directly; this is the reason there is no POST in the /testruns REST endpoint.


Test Plans


A Test Plan is a collection of Test Cases grouped into Groups for organization and Cycles for execution. Test Plans can be created directly.


Test Groups


Test Groups are a grouping of Test Cases inside a Test Plan. They have no direct impact on the way Test Cases are executed; they exist mostly to allow users to group Test Cases into some sort of meaningful sections. For instance, a Test Plan could have groups based on functional breakdowns like "Tree Operations", "Items", etc. Although they are not pertinent to execution, each Test Plan must have at least one Test Group in which to place tests. Test Plans are created with a group called "Default Test Group" which can be used or replaced with custom groups.


Test Cycles


Test Cycles are a collection of Test Run Items that correspond to a particular execution of a Test Plan. For example, you could have a Test Cycle for each release candidate build, or Test Cycles for different browsers, depending on what makes sense for your testing. This terminology may be a bit confusing at first when coming from other test management systems, but the thing to keep in mind is that a "Test Run" is a single item, and a "Test Cycle" is a collection of Test Runs that have been run together at the same time for the same organizational purpose.

When a Test Cycle is created, all Test Case Items in that Test Plan have corresponding Test Run Items created in the system for that Test Cycle. Accordingly, a Test Cycle must be created before any Test Case can be executed. Test Cycles cannot be created independently of a Test Plan (there is no POST in the /testcycles endpoint).

An Example: These concepts as written definitions are a bit tricky, so here is a bit of a rundown on how we test internally:

We have a master regression library with hundreds of
Test Case Items
that we can test. At the time of each release regression, we create a few different
Test Plans
based on different configurations of the product, in our case, "Release 8.20 - Hosted", "Release 8.20 - Clients", "Release 8.20 - Server & Database". Inside those Test Plans, we add all, or a subset, of the Test Cases in the regression library, grouped by hierarchy, which, in our case, corresponds to areas of the product like "Stream" and "Projects". To execute these tests, we create one or more
Test Cycles
in the Test Plan. The "Release 8.20 - Clients" plan, for instance, tests different browsers, so there are cycles like "MacOS Chrome", "Windows Firefox", "Internet Explorer", etc.

Much of our regression library is automated, and our automation tooling executes, and updates results via the API using methods similar (but with much more wrapping) to what will be outlined below.

The Process

This process assumes you already have created Test Case Items that you want to execute. If you are only updating existing executions, you may need to skip further down in the guide.


Creating a Test Plan


First, a Test Plan must be created. If you are planning to use an existing Test Plan that has already been created (using the API or UI), you can skip this section.

POST
/testplans
with a payload like:

{

"project": 43,

"fields": {

"name": "Connect Plan 1"

}

}


project
is the API ID of the project where the Test Plan will be created


name
is the only required field in the payload

If successful, you will get a response like:

{
"meta": {
"status": "Created",
"timestamp": "2018-06-07T18:46:54.094+0000",
"location": "https://yourjama.jamasoftware.net/rest/latest/testplans/20494",
"id": 20494
}
}

You will need the
id
for further operations.


Adding Test Cases to a Test Plan


Test Cases are organized in Test Plans by groups. These groups are only for classification and bear no bearing on the way that Test Cases are executed. However, test cases

must
be added to a Group in the Test Plan; they cannot be added to a Test Plan directly. You can either use the "Default Test Group" present in every Test Plan, or create new groups.


To find the default group:

GET
/testplans/{testPlanId}/testgroups


where {testPlanId} is the API ID of the existing test plan, (from above, 20494)

If successful, you will get a response like:

{
"meta": {
"status": "OK",
"timestamp": "2018-06-07T19:16:01.311+0000",
"pageInfo": {
"startIndex": 0,
"resultCount": 1,
"totalResults": 1
}
},
"links": {},
"data": [
{
"id": 157,
"name": "Default Test Group"
}
]
}

In a brand-new Test Plan, "Default Test Group" will be the only group. You will need its
id
if you plan to add test cases to it, or:


To add your own group:

POST
/testplans/{testPlanId}/testgroups
with a payload like:

where {testPlanId} is the API ID of the existing test plan (from above, 20494)

{
"name": "Stream"
}


name
is the only required field in the payload

If successful, you will get a response like:

{
"meta": {
"status": "Created",
"timestamp": "2018-06-07T19:20:35.340+0000",
"location": "https://yourjama.jamasoftware.net/rest/latest/testplans/20494/testgroups/160",
"id": 160
}
}

You will need the
id
for further operations


To add a Test Case to a Group:


At this time, there is no batch operation for adding Test Cases, so each test case must be added individually using:

POST
/testplans/{testPlanId}/testgroups/{testGroupId}/testcases
with a payload containing a single test case id like:


where {testPlanId} is the API ID of the existing test plan (from above, 20494) and {testGroupId} is the API ID of the Test Group (from above, 157 for the default group, 160 for the custom)

{
"testCase": 20497
}


testCase
is the only item in the payload and should be set to the API ID of the Test Case you want to add

If successful, you will get a response like:

{
"meta": {
"status": "Created",
"timestamp": "2018-06-07T19:36:44.452+0000",
"location": "https://yourjama.jamasoftware.net/rest/latest/testplans/20494/testgroups/160/testcases/20497",
"id": 20497
}
}

The
id
returned in this case should match the id of the Test Case you provided in the payload


Creating a Test Cycle


A Test Cycle must be created to execute tests. Test Cycles are created through an existing Test Plan.

POST
/testplans/{testPlanId}/testcycles
with a payload like:

where {testPlanId} is the API ID of the existing test plan (from above, 20494)

{
"fields": {
"name": "Internet Explorer",
"startDate": "2018-06-06",
"endDate": "2018-06-13"
}
}


name, startDate,
and
endDate
are the only required fields in the payload. Note that there are other payload options for specifying which Test Groups and statuses that are added to the Cycle, but those won't be discussed here. Consult the API documentation for those options.

If successful, you will get a response like:

{
"meta": {
"status": "Created",
"timestamp": "2018-06-07T20:39:05.921+0000",
"location": "https://yourjama.jamasoftware.net/rest/latest/testcycles/20536",
"id": 20536
}
}

You will need the
id
for further operations


Finding an Existing Test Cycle:


If you need to work with an existing Test Cycle, it can be found in this manner.

GET
/testplans/{testPlanId}/testcycles


where {testPlanId} is the API ID of the existing test plan (from above, 20494)

If successful, you will get a response like:

{
"meta": {
"status": "OK",
"timestamp": "2018-06-08T15:57:09.863+0000",
"pageInfo": {
"startIndex": 0,
"resultCount": 2,
"totalResults": 2
}
},
"links": {
... omitted for brevity ...
},
"data": [
{

"id": 20510,

"documentKey": "JEET1-TSTCY-17",

"globalId": "70957",

"itemType": 36,

"project": 43,

"createdDate": "2018-06-07T19:58:19.000+0000",

"modifiedDate": "2018-06-07T19:58:19.000+0000",

"lastActivityDate": "2018-06-07T19:58:19.000+0000",

"createdBy": 5,

"modifiedBy": 5,

"fields": {

"documentKey": "JEET1-TSTCY-17",

"globalId": "70957",

"name": "Build 2018-06-06",

"testPlan": 20494,

"startDate": "2018-06-07",

"endDate": "2018-06-15",

"description": "",

"project": 43

},

"resources": {

"self": {

"allowed": [

"GET",

"PUT",

"PATCH",

"DELETE"

]

}

},

"type": "testcycles"

},

... second object omitted for brevity ...

]

}

You will need the
id
for further operations


Executing a Test


You now have almost all the data needed to record a test execution. Before you can do that, though, you need to find the actual Test Run object created when you created the Test Cycle. You will need the
id
of the Test Case Item, the Test Plan, and the Test Cycle

GET
/rest/latest/testruns?testCycle={testCycleId}&testCase={testCaseId}&testPlan={testPlanId}


where {testPlanId} is the API ID of the existing test plan (from above, 20494), {testCycleId} is the API ID of the Test Cycle (from above, 20536 for the created one, 20510 for the existing), {testCaseId} is the API ID of the Test Case to be executed (from above, 20497)

If successful, you will get a response that looks like:

{

"meta": {

"status": "OK",

"timestamp": "2018-06-07T21:01:36.530+0000",

"pageInfo": {

"startIndex": 0,

"resultCount": 1,

"totalResults": 1

}

},

"links": { ... removed for brevity ...

},

"data": [

{

"id": 20539,

"documentKey": "JEET1-TSTRN-520",

"globalId": "70962",

"itemType": 37,

"project": 43,

"createdDate": "2018-06-07T20:39:02.000+0000",

"modifiedDate": "2018-06-07T20:39:02.000+0000",

"lastActivityDate": "2018-06-07T20:39:02.000+0000",

"createdBy": 5,

"modifiedBy": 5,

"fields": {

"documentKey": "JEET1-TSTRN-520",

"globalId": "70962",

"name": "One",

"testPlan": 20494,

"testCycle": 20536,

"testRunSetName": "Internet Explorer",

"testCase": 20497,

"description": "",

"modifiedDate": "2018-06-07",

"testRunStatus": "NOT_RUN",

"project": 43,

"forcePassed": false

},

"resources": {

"self": {

"allowed": [

"GET",

"PUT",

"PATCH"

]

}

},

"testCaseVersionNumber": 1,

"testCaseCurrentVersionNumber": 1,

"sortOrderFromTestGroup": 1,

"testGroup": [

20536,

160

],

"type": "testruns"

}

]

}

If you have specified the id for Test Case, Test Plan, and Test Cycle, you should get

one

Test Run result in the data. You will need the
id
for further operations.

Next, you will need to either use PUT
or
PATCH to update the status of this test run:


Test Runs

without
Steps:


On test runs without steps, you can simply update the testRunStatus field.

PATCH
/rest/latest/testruns/{testRunId}
with a payload like:

where {testRunId} is the API ID of the Test Run (from above, 20539)

[

{

"op": "REPLACE",

"path": "/fields/testRunStatus",

"value": "PASSED"

}

]

PUT
/rest/latest/testruns/{testRunId}
with a payload like:

where {testRunId} is the API ID of the Test Run (from above, 20539)

{

"fields": {

"testRunStatus": "BLOCKED"

}

}

Valid values for /fields/testRunStatus are PASSED, NOT_RUN, FAILED, INPROGRESS, and BLOCKED.

If successful, you will get a response like:

{

"meta": {

"status": "OK",

"timestamp": "2018-06-07T21:14:14.611+0000"

}

}

Test Runs

with
Steps

On test runs with steps, you must pass the entire array of test steps (in the original order) with new statuses.

Here is an example of a Test Run object with steps. Note that the testRunSteps array is implicitly ordered by the step number as seen in the UI:

{

"id": 20569,

"documentKey": "JEET1-TSTRN-525",

"globalId": "70967",

"itemType": 37,

"project": 43,

"createdDate": "2018-06-11T21:34:09.000+0000",

"modifiedDate": "2018-06-11T21:34:09.000+0000",

"lastActivityDate": "2018-06-11T21:34:09.000+0000",

"createdBy": 5,

"modifiedBy": 5,

"fields": {

"documentKey": "JEET1-TSTRN-525",

"globalId": "70967",

"name": "One",

"testPlan": 20494,

"testCycle": 20536,

"testRunSetName": "Internet Explorer",

"testCase": 20497,

"description": "",

"testRunSteps": [

{

"action": "You do something",

"expectedResult": "Something happens",

"notes": "",

"status": "NOT_RUN"

},

{

"action": "You do something else",

"expectedResult": "Something else happens",

"notes": "",

"status": "NOT_RUN"

}

],

"modifiedDate": "2018-06-11",

"testRunStatus": "NOT_RUN",

"project": 43,

"forcePassed": false

}

Given the two steps above, you can do the following:

PUT
/rest/latest/testRuns/{testRunId}
with a payload like:

{

"fields": {

"testRunSteps": [

{

"status": "PASSED"

},

{

"status": "PASSED"

}

]

}

}

or

{

"fields": {

"testRunSteps": [

{

"status": "FAILED"

},

{

"status": "PASSED"

}

]

}

}

The testRunStatus for the Test Run will then be set automatically according to the status field on the steps.



Congratulations! You've executed a Test Case through the API!

What triggers the Last Activity Date?

Along with create date and modified date, we record the last activity date on every item. While modified date tracks the last time an item was saved, last activity date tracks when the last activity around the item happened. Below we list the types of events that last activity date should be triggered by.

· Item Updates
· Create new Item
· Edit and save Item
----- Note: deleted items cannot be seen so the last activity date is not visible.
· Comments On an Item
· Adding a comment directly to the item
· Deleting a comment that is directly on the item
· Relationships To and From an Item
· Adding a relationship to and from the item
· Removing a relationship to or from the item
· Tags on an Item
· Adding a tag to the item
· Removing a tag to the item
· Attachments on an Item
· Adding attachment to an Item
----- Note: Updating an attachment does not change the last activity date for the items it is a part of.
· Links on an Item
· Adding a link to an Item
· Editing a link on an Item
· Removing a link on an Item
· Reviews and Baseline
----- Sending items and creating baselines does NOT update the last activity date
· Executing Test Run *Only* updates test run's last activity date

Configuration Guidelines for Tasktop and Opshub

br/>Tasktop Recommended Configuration:
Our recommendations are based on the 18.2 Tasktop Settings.
Details: https://docs.tasktop.com/tasktop/user-guide/settings


Change Detection Polling Interval

We recommend setting this to 1 minute.


Full Scan Change Detection Polling Interval

We recommend setting this to at-least 24 hours.

We do not know if it is possible, but we recommend also scheduling these full scans during a time of day that is not busy.

Full scans are very expensive and may slow down Jama during the scan. You may adjust this setting and the next setting if you experience slow performance on your instance.


Integration Maximum Concurrency

This value depends on how many integrations you have enabled. In any case, do not set a value higher than the default of 10 concurrency limit. We recommend having settings this value between 2 and 5. If you have multiple integrations, try using less.


Opshub Recommended Configuration


We recommend using the default settings for OpsHub.

Associate Schedule should be set to the default of 1 minute.
http://docs.myopshub.com/oim/index.php/Integration_Configuration?version=OIMV7.11#Associate_Schedule


Searching with abstract items endpoint

This document will review how you can use the abstract items endpoint to search for items with customized filters. Our abstractitems endpoint offers the best search and filtering capabilities in our API.

Abstract items a generic resource for getting the various types of items in Jama. This resource will return items you can pull from /items, /testplans, /testcycles, /testruns, /attachments. While there are a few endpoints within the abstract items resource, this article will focus on the search capabilities of the GET /abstractitems endpoint.


GET /abstractitems

Response Model

This endpoint returns an array of items. You can review our data model and our paging on our Dev portal. This endpoint also has support for our includes feature. The includes feature lets you get more information out of your results without making more calls and it is recommended to use with this endpoint.



Search Parameters

This endpoint offers many query parameters that you may use to narrow your results to precisely what you are looking for. We will cover these parameters in more detail later, for now let's consider some basic rules so you can correctly set up your query.


Matching Lists

Valid for: project, itemType, release, documentKey, contains

If you would like to provide more than one value for a parameter, you may repeat the parameter. For example, if you want to see all items in either project 15 or 20, the you can make a request like this:

curl -X GET 'https://{baseUrl}/rest/v1/abstractitems?project=15&project=20' -H 'Authorization: Basic dXNlcjpwYXNzd29yZA=='

Remember that when the parameter is repeated, you are grouping the values together with OR expressions. You will get broader results as you add more parameters of the same type.


Matching Date Time Fields

Valid for: createdDate, modifiedDate, lastActivityDate

The date base parameters operate a little differently. You may provide one or two ISO8601 values. When one date time is provided, it will return items which match that field within the range from the date provided to the time of the request. When two values are provided, it will return items which match that field within the range of the two provided date times. The date values should use the ISO8601 date time format: yyyy-MM-dd'T'HH:mm:ss.SSSZ. Note that these date time formats are set using the UTC timezone or zero timezone offset.

In this example, we would get all items with a modifiedDate from 2018-06-19T21:29:15.037Z up to the time the request is made:

curl -X GET 'https://{baseUrl}/rest/v1/abstractitems?modifiedDate=2018-06-19T21:29:15.037Z' -H 'Authorization: Basic dXNlcjpwYXNzd29yZA=='

This example will return all items with a created date between 2018-06-01T00:00:00.000Z and 2018-06-07T00:00:00.000Z:

curl -X GET 'https://{baseUrl}/rest/v1/abstractitems?createdDate=2018-06-01T00:00:00.000Z'&createdDate=2018-06-07T00:00:00.000Z' -H 'Authorization: Basic dXNlcjpwYXNzd29yZA=='


Sorting Results

Parameter: sortBy

After you've chosen your filters, you may want to sort the results you get back. If you do not provide a sortBy value, results will default to sorting by sequence in ascending order and then by documentKey in ascending order. You may provide one or more fields to sort by and they will be used in the order they are sent in.

You must format the sortBy value this way:


{fieldname}.{order}

where fieldname is the fieldname and order are "asc" for ascending, or "desc" for descending.

This example will sort results by project in ascending order first, and then by last activity date descending second:

curl -X GET 'https://{baseUrl}/rest/v1/abstractitems?sortBy=project.asc&sortBy=lastActivityDate.desc' -H 'Authorization: Basic dXNlcjpwYXNzd29yZA=='


Mix and Matching Parameters

Valid for: project, itemType, release, documentKey, contains, createdDate, modifiedDate, lastActivityDate

You may use any combination of query parameters in your query. So, you will be able to find all defects (specific item type id) from 2 different projects, that must contain the word "vegetables". When constructing these types of queries, remember this basic rule:

Duplicated parameters are grouped together with OR expressions.

These sets of parameters are then ANDed with each other.

For example, consider this request:

curl -X GET 'https://{baseUrl}/rest/v1/abstractitems?project=1&project=2&itemType=27&contains=vegetables' -H 'Authorization: Basic dXNlcjpwYXNzd29yZA=='

There are 2 project params, 1 item type param, and 1 contains param. The logical expression for filtering results will look like this:

(project = 1 OR project = 2) AND (itemType = 27) AND (contains = vegetables)

From here it should be possible to create complex filters on the fly, so you can

Parameter Details

Contains

- The contains param lets you find items whose content contains your provided string values. Additionally, you can use some Lucene syntax if you format your string correctly.

In this example, Jama would return all items where the content contains the word "fire".

curl -X GET 'https://{baseUrl}/rest/v1/abstractitems?contains=fire' -H 'Authorization: Basic dXNlcjpwYXNzd29yZA=='

An item will be matched if "fire" shows up in the name, description, any text field, and even the label of a picklist option if that option is set to the item. the case is ignored.

If you are interested in building more complex queries to filter on specific fields,

Simply wrap the same expression with double quotes and use it with the contains query params.

curl -X GET 'https://{baseUrl}/rest/latest/abstractitems?contains="name: "fire" AND name: "water""' -H 'Authorization: Basic dXNlcjpwYXNzd29yZA=='

Please note that this works the same as the search bar in the UI. the main peculiarity is that wild cards may be added to your Lucene query. When specifying fields, remember to use the name of the field and not the display or label. We are considering a different implementation for Lucene queries, so you may have better control.

project

- This simply matches items with the same project id.

itemType

- This simply matches items with the same item type id.

documentKey

- This simply matches items with the same document key.

release

- This simply matches items with the same release id.

createdDate

- See the above section on matching dates. This parameter will match with the created date of an item. Created date is set when it is first created.

modifiedDate

- See the above section on matching dates. This parameter will match with the modified date of an item. Modified date is updated when an items content changes and a new version is made.

lastActivityDate

- See the above section on matching dates. This parameter will match with the last activity date of an item. Last activity date is more sensitive to changes that are not reflected with the modified date. Comments directly on the item, relationships made to the item, changes to the location of the item, attachments added to an item will update the last activity date. More details description of changes to come.

REST Attachments

Attachments can be uploaded through our REST API and associated with an item in three calls. First, you must create an attachment item, then upload the file, and finally associate the attachment to an item. This should be straight forward after you have done it once. This document should help explain the steps clearly.

I will be sharing how to do this with Postman, a Google chrome extension.


Step 1: Create an Attachment Item

Attachment Items are items that contain the meta data for an attachment. You may define the name and description, or any other fields associated with the attachments item type.

This is exactly like filling out the name and description when you create an attachment in the UI:


Attachment Item JSON

{
"fields":{
"name":
"Poppy Flower",
"description":
"A pretty picture"
}
}

Only the name field is required to create an attachment item unless the Item Type has been configured differently.

Post your attachment Item to this path:


POST /rest/v1/projects/{projectID}/attachments

You should get a response back saying the attachment was created. Use the location to determine the id:

{
"meta":{
"status":
"Created",
"timestamp":
"2015-02-09T21:53:06.576+0000",
"location":
"http://localhost:8080/contour/rest/latest/attachments/1133"
}
}

Great, now you have an Attachment item. Next you need to upload the file to this item!


Step 2: Upload the file

You can upload a file using a PUT with form-data. the endpoint is
/rest/v1/attachments/{attachmentID}/file
. The key for the form data should be 'file'. Here is a screenshot of what it looks like in Postman:


Step 3: Associate Attachment Item with Item

To be clear, the attachment item is an item that has the meta data about an attachment. An Item is any old item you are familiar with in Jama, a requirement, test run, or anything else. You must have the Attachment widget enable on the item type before associating attachments to items.

You simply POST the attachment item ID to the attachment endpoint of the item you would like to associate with. Any of these paths are acceptable:

/rest/v1/items/{id}/attachments

/rest/v1/testplans/{id}/attachments

/rest/v1/testruns/{id}/attachments

The JSON is very simple:

{
"attachment":
1133
}

That's it! You can make some other attachment related operations listed below:

URL

Description

GET /rest/v1/attachments{attachmentId}

Gets attachment meta data

PUT /rest/v1/attachment/{attachmentId}/file

Uploads file to attachment

GET /rest/v1/attachment/{attachmentId}/file

Download the attached file

GET /rest/v1/attachments/{attachmentId}/comments

Gets all comments for attachment Item

GET /rest/v1/items/{id}/attachments

Gets attachments on an Item. This also works for test plans and test runs.

POST /rest/v1/items/{id}/attachments

Associates attachment item to the item

DELETE /rest/v1/item/{id}/attachments/{attachmentId}

Removes the association from the item. The attachment item still exists.

Attachments Attachments Attachments!

What are Attachments?

Jama is designed to allow for great flexibility of content, making it the ultimate definition of a system of record. While many of our customers are busy tapping away at the keyboard, they are often associating their content with documents, images, graphs, tables, equations, and so much more. External documents and images are referred to as attachments in Jama.

Uploading Attachments via REST API

There are two main ways to utilize attachments within in Jama:
· Attach a file to an item
· Embed a clickable link to an attachment within an item's text


Attaching a File to a Jama Item

Attachments can be uploaded through our REST API and associated with an item in three quick steps:

Step 1: Create an Attachment Item

Attachment Items are items that contain the meta data for an attachment. A name, description, and any other fields associated with the attachments item type can be defined in the JSON payload.
This is exactly like filling out the name and description when an attachment is created in the UI:


Attachment Item JSON Payload

{
"fields"
: {

"name"
: "Poppy Flower",

"description"
: "A pretty picture"
}
}

Note: By default, Name is the only required field in the Attachment item type.

POST the attachment Item using the following endpoint:

POST /rest/v1/projects/{projectID}/attachments

You should receive a response confirming the attachment was created. Use the location to determine the ID of the newly created attachment item:

{
"meta"
: {
"status"
: "Created",
"timestamp"
:"2015-02-09T21:53:06.576+0000",
"location"
:"http://{base_url}/rest/latest/attachments/1133"
}
}

You have successfully created an attachment item!

Step 2: Upload the attachment file

Files can be uploaded to Jama using a PUT with form-data to the following endpoint:

PUT /rest/v1/attachments/{attachmentID}/file

The attachmentID is the ID retrieved from the response location in step #1.

If you receive a 200/201 response status, you have successfully uploaded a file to the Jama attachment!

Step 3: Associate the attachment with an item

To associate an attachment item with a Jama item, the attachment widget must be enabled on the Jama item's item type prior to establishing an association.

Attachments can be associated with items that contain a POST method for an attachment. The attachment item ID is required in all cases. The following attachment endpoints are available:

POST /rest/v1/items/{itemID}/attachments
POST /rest/v1/testPlans/{testPlanID}/attachments
POST /rest/v1/testRuns/{testRunID}/attachments

The JSON payload should contain the attachment item ID:

{
"attachment"
:1133
}

You should receive a response indicating the status of your POST as shown below:

{
"meta"
: {
"status"
: "Created",
"timestamp"
:"2017-08-25T21:21:49.789+0000",
"location"
:"http://{base_url}/rest/latest/items/2209254/attachments/1133"
}
}

The result should appear in the attachment widget section of the object in Jama like this:

You have successfully associated an attachment with a Jama item using the REST API!

Embedding a Link to an Attachment in a Jama Object

Embedding clickable hyperlinks for attachments within content is also possible through our REST API. These appear in Rich Text fields as clickable links that can be used to download attachments. Once an attachment item is created, and the attachment's file is uploaded (steps #1 and 2 from the approach above), there are three steps to creating a clickable link to the attachment:

Step 1: Get the attachment's attachment value and filename

Once an attachment is created in Jama, and its file has been uploaded, GET the attachment item using the following endpoint:

GET /rest/v1/attachments/{attachmentID}

and retrieve the attachment value from the fields section, as well as the attachment's fileName (highlighted below):

{
"data"
: {
"id":
1133,
"documentKey":
"INF-ATT-31",
"globalId":
"GID-ATT-115929",
"itemType":
89027,
"project":
20319,
"createdDate":
"2017-08-25T21:21:49.789+0000",
"modifiedDate":
"2017-08-25T21:21:49.789+0000",
"lastActivityDate":
"2017-08-25T21:21:49.789+0000",
"createdBy":
18368,
"modifiedBy":
18368,
"fields":
{
"attachment":
78574,
"globalId":
"GID-ATT-115929",
"name"
: Poppy Flower,
"description":
A pretty picture,
}
"resources":
{
"self": {
"allowed": [
"GET"
]
}
},
"fileName":
"poppy.jpeg",
"mimeType":
"image/jpeg",
"fileSize":
7295,
"type":
"attachments"
}
}

Note: the attachment value is

not
the attachment item's ID, rather the attachment value stored in the
fields
section of an attachment object.


Step 2: Create a Hyperlink to your Attachment Item

Create a string with the following form:

<a href="https://{base_url}/attachment/{attachmentValue}/attachmentFileName">Clickable Text</a>


Step 3: Update a Jama Item's Rich Text Field

The string from step #2 now needs to be inserted into a Rich Text field of an Item to be accessible via the UI. Any endpoint that creates or updates a Jama Item's content can be used to update/generate an item with the clickable link embedded in a Rich Text field. Below are a few available endpoints:

POST /rest/v1/items
PUT, PATCH /rest/v1/items/{itemID}
POST /rest/v1/testplans
PUT, PATCH /rest/v1/testplans/{testPlanID}
POST /rest/v1/testruns
PUT, PATCH /rest/v1/testruns/{testRunID}

A clickable link should now appear in the object's Rich Text field as shown below:

Clicking on the hyperlink text should result in the attachment being downloaded:

You have successfully embedded a link to your Jama attachment item!

Downloading Linked Attachments

An attachment's file can be downloaded using the previously created attachment link in three steps:

Step 1: Retrieve the Attachment Link

Retrieve the object containing an embedded attachment link. Below are a few available endpoints:

GET /rest/v1/items/{itemID}
GET /rest/v1/testplans/{testPlanID}
GET /rest/v1/testruns/{testRunID}

Step 2: Parse out the Attachment Link

Parse out the embedded attachment link from the retrieved object's Rich Text field's content. Parsing libraries such as JSOUP for Java and BeautifulSoup for Python are helpful for this step.

Step 3: Download the Attachment File

Download the file using the following endpoint:

GET /rest/v1/files

The request payload should contain the link URL that was parsed out in step #2 and will look like this:

https://{base_url}/attachment/{attachmentValue}/attachmentFileName

If a response status of 200/201 is received, then you've successfully downloaded your attachment's file to your working directory!


Need help getting started?

For help getting started on uploading and downloading attachment files from Jama, check out our starter scripts available on GitHub. (https://github.com/JamaSoftware/UploadAttachments)