Overview

API v2 is a read-only REST-like API which lets you query data in your Targetprocess account.

📘

APIv2 is not a replacement of APIv1

Both versions of API co-exist and serve different purposes.
APIv1 provides CRUD access to data. It has basic support for filtering and querying data.
APIv2 provides read-only access to data. It has advanced support for filtering and querying data.

Url format

/api/v2/{entity}/{id}?
where={where}&select={select}&result={result}&
take={take}&skip={skip}&orderBy={orderby}&
callback={callback}&filter={filter}
  • {entity} - entity type name in single case (Userstory, Bug) - see here for the list of available entity types
  • {id} - optional entity id. If specified, the response will contain only one item in {items} collection
  • {where} - filter expression over collection of entities
  • {select} - select projection.
  • {result} - final expression, used for aggregations' calculation on root entity.
  • {skip}, {take} - paging parameters, how many entities skip and take. If the result contains more entities, the response will have fields "next" or/and "prev" links to another pages.
  • {orderBy} - orderings
  • {callback} - JSONP callback
  • {filter} - a DSL Filter or Simple Filter like on boards. filter and where clauses are combined with and operator.

Also, you can add following flags to query string to modify output:

  • prettify - to prettify response json with spaces and new lines
  • isoDate - to get the dates in ISO 8601 format

Selectors


selector = expression | objectExpression

objectExpression = { namedSelectorList }

namedSelectorList = namedSelector [,namedSelectorList ]

namedSelector = field | name:expression | functionCall

functionCall = A call to Enumerable methods (see below)

expression = field | dlinqExpression

field = Any field of a referenced entity (get from here) or projected object

dlinqExpression = A valid .NET expression with some extensions (learn more)


Every objectExpresssion will be represented as JSON object with given properties calculated from namedSelectors. For instance:

https://md5.tpondemand.com/api/v2/UserStory?select={id,storyName:name,project:{project.id,project.name},tasks.count()}

{
  "next": "http://md5.tpondemand.com/api/v2/UserStory?where=&select={id,storyName:name,project:{project.id,project.name},tasks.count()}&take=25&skip=25",
  "items": [
    {
      "id": 93114,
      "storyName": "Study Projectplace tool",
      "project": {
        "id": 37819,
        "name": "AVM: MKT_Backlog"
      },
      "count": 0
    },
    {
      "id": 93112,
      "storyName": "Briefly describe api v2",
      "project": {
        "id": 49105,
        "name": "TP3"
      },
      "count": 1
    },

If a name of the result field is not defined, api V2 tries to infer the field name using a) field names (id -> id, project.id -> id), b) aggregation names (tasks.count() -> count), otherwise it will use name.

name should be a valid alphanumeric identifier: OK - id, camelCase, name1, name_with_underscore. Not OK - name with space, 1starting_from_number, name!with?symbols.

If you need to get values from inner entities, you need to specify a full path to the property: project.id, feature.epic.name.

For example, I want to get user stories with id, name, effort, project (with id, name and process name), feature (with id, name and epic):

/api/v2/UserStory?select={id,name,project:{project.id,project.name,process:project.process.name},feature:{feature.id,feature.name,feature.epic}}

Let's format selector for convenience:

{
   id,
   name,
   project: { 
     project.id,
     project.name,
     process:project.process.name
   },
   feature: {
      feature.id,
      feature.name,
      feature.epic
   }
}

The result is:

   { // fully filled userstory
    "id": 93108,
    "name": "Add Left/Right arrows to scroll widgets library",
    "project": {
      "id": 49105,
      "name": "TP3",
      "process": "Kanban TP"
    },
    "feature": {
      "id": 49126,
      "name": "Dashboards MVF",
      "epic": { // as far as epic was requested as a field, it contains only "id" and "name"
        "id": 90678,
        "name": "Dashboards"
      }
    },
    {
      "id": 93114,
      "name": "Study Projectplace tool",
      "project": {
        "id": 37819,
        "name": "AVM: MKT_Backlog",
        "process": "Sales: General"
      },
      "feature": { // This UserStory has no feature, so result projection will include the empty "feature" object
        
      }
    }

Selectors for collections

Along with simple fields and related entities, you also can request inner collections. E.g. I want to get projects with: all User Stories.


  • userstories - list of all User Stories in format {id,name}. As far it is just a field, it doesn't require explicit name

Except standard fields that you see when querying inner collection, you might want to retrieve some specific ones. For example, let's get such fields for Bugs inner collection of User Story:

/api/v2/UserStory?select={id,name,bugs:bugs.select({id,name,effort,timespent,timeremain})}

Selectors: Custom Calculations over nested collections

You can request inner collections with filters, projections, and aggregations. E.g. I want to get projects with:

  • all non-closed bugs
  • sum of feature efforts
  • count of opened requests

More information: Selectors: Custom Calculations over nested collections

Final selectors: Custom Calculations over result output

It is also possible to apply aggregation to whole result collection.

More information: Final selectors: Custom Calculations over result output

.NET Expressions

API v2 uses LINQ expression parser that use syntax that is very close to standard .NET syntax. More information: .NET Expressions

Filtering expressions

Filtering expressions should be valid .NET expressions that return true or false. You use these expressions in where conditions.

You can use identifier 'it' to reference the parameter of a filter. For example, I want list of all efforts greater than 5:

/api/v2/Project?select={id,name,efforts:userStories.Select(effort).Where(it>5)}
{
      "id": 35923,
      "name": "Articles",
      "efforts": [
        10.0000,
        21.0000
      ]
    },
    {
      "id": 70163,
      "name": "Astroport",
      "efforts": [
        
      ]
    },
    {
      "id": 53775,
      "name": "AVM: CFO",
      "efforts": [
        9.5000
      ]
    },

Filters

Parameter named filter supports provision of a DSL Filter or Simple Filter like on boards. filter and where clauses are combined with and operator.

/api/v2/request?filter=?AssignedUser.Where(it is Me)

Ordering

A parameter named orderBy sorts results in ascending or descending order. Ascending is the default option.
To specify the order, you should place 'asc' or 'desc' after the selector.
To enable additional sort criteria to sort a sequence, you can enumerate them using commas.

For example, you can sort user stories descending by effort and then ascending by name:

/api/v2/userstory?select={id,name,effort}&orderBy=effort desc,name)
[
	{
		"id": 72903,
		"name": "Defiant",
		"effort": 120
	},
	{
		"id": 86582,
		"name": "Nova",
		"effort": 50
	},
	{
		"id": 71004,
		"name": "Rigel",
		"effort": 20
	},
	{
		"id": 94066,
		"name": "Springfield",
		"effort": 20
	}
]

Collections can also be ordered in ascending or descending order. The default sorting of collection items is descending by Id.
To have custom order, use orderBy() or orderByDescending()

/api/v2/portfolioepic?select={id,name,epics:epics.orderByDescending(name).select(name)}
/api/v2/portfolioepic?select={id,name,epics:epics.orderBy(name).select(name)}

Response format

Response is JSON object with requested collection in items field. For instance:

{
  "next": "/api/v2/UserStory?where=&select={id,name,endDate:(endDate-StartDAte).TotalDays}&take=25&skip=25&type=UserStory",
  "items": [
    {
      "id": 93110,
      "name": "Widgets API documentation"
    }
  ]
}

All fields are in camelCase, all null values are omitted.

Advanced Examples