Introduction

The API facilitates integration with external systems and allows direct queries to the Lifecycle data.

We have language bindings in Shell, C#, Javascipt, and Python! You can switch the programming language of the examples with the tabs above.

We highly suggest reading over the terminology section to become familiar with concepts like Assets, Attributes, Filter Tokens and more. Once you have a hande of the basics you'll begin to see how expressive the VersionOne APIs can be! Happy coding!

Base Url

The first step is to find your VersionOne URL. It may look similar to this: https://www7.v1host.com/V1Instance

In this case, www7.v1host.com is your host and V1Instance is your instance. These will be used to build your base URL that all requests to the API will rely on.

Authentication

Every request to the VersionOne API must have the Authorization HTTP Header set. You can do this using your username and password, but it is reccommended that you use an access token. Access tokens are associated with an application and grant the application certain access to resources. The application can act on behalf of the member who created the access token.

Username and Password

You may use your username and password using Basic authentication by setting the Authorization header. You'll have to base64 encode username:password including the : to accomplish this.

curl "https://V1Host/V1Instance/api_endpoint_here"
  -H "Authorization: Basic username:password"

Access Tokens

VersionOne uses access tokens to grant access to the API. You can register a new access token by logging into VersionOne and navigating to the Applications page. This is the suggested way to interact with the VersionOne API.

curl "https://V1Host/V1Instance/api_endpoint_here"
  -H "Authorization: Bearer <access-token>"

Application Page

Validating Your Access Token

To validate that your access token is working prooperly, you can try an HTTP request like below.

HTTP Request

curl 'https://V1Host/V1Instance/rest-1.v1/Data/Member?where=IsSelf="true"&sel=Username'
  -H "Authorization:Bearer <access-token>"
  -H "Accept:application/json"

HTTP Response

You should get back a response similar to this:

{
   "_type":"Assets",
   "total":1,
   "pageSize":2147483647,
   "pageStart":0,
   "Assets":[
      {
         "_type":"Asset",
         "href":"/V1Instance/rest-1.v1/Data/Member/20",
         "id":"Member:20",
         "Attributes":{
            "Username":{
               "_type":"Attribute",
               "name":"Username",
               "value":"admin"
            }
         }
      }
   ]
}

HTTP Headers

curl "https://V1Host/V1Instance/api_endpoint_here"
  -H "Authorization: Bearer <access-token>"
  -H "Content-Type: application/json"
  -H "Accept: application/json"

For this guide we will only show the VersionOne server accepting and responding with JSON.

The Content-Type header tells the server what media type we are sending it in the request body.
The Accept header tells the server what media type to respond to the request with.

HTTP Headers
Ensure that every request has Content-Type: applicaiton/json and Accept: application/json headers.

Errors

The VersionOne API uses the following error codes:

Error Code Message Meaning
400 Bad Request Most common error, resulting from a request that could not be processed by the API. The Error Message will identify the specific problem, and there may be Exception elements that give very detailed information
401 Unauthorized Your access token is invalid
404 Not Found The specified resource could not be found
405 Method Not Allowed The HTTP method used for the request is not valid at the requested URL. This will be returned for any method other than GET and POST, or if POST was sent to a URL that does not support updating.
500 Internal Server Error An unexpected error occurred during the processing of the request. The response payload will contain Exception elements with specific information that will help technical diagnose the cause of the error.

Terminology

Asset

A System Asset is a core business object in the VersionOne® Lifecycle model. Each asset represents the stories/backlog items, defects, sprints/iterations, and the members who use the system. The diagram below illustrates the relationship of these assets to one another and how they work together to help you manage your workflow.


Asset Diagram

Asset Types

Asset types describe the "classes" of data available. Each asset type contains a collection of attribute definitions, a collection of operations, and a number of useful attribute definitions for things like sorting. Asset types form an inheritance hierarchy, such that each asset type inherits attribute definitions, operations, and rules from its parent asset type. Those asset types at the leaves of this hierarchy are concrete, whereas asset types with children asset types are abstract. Assets are all instances of concrete asset types. Asset types are identified by unique names.

By way of example, Story and Defect are concrete asset types. On the other hand, Workitem is an abstract asset type, from which Story and Defect ultimately derive.

Most asset types have the same name as found in the application user interface. A Defect in the user interface is also a Defect as an asset type. However, many of the most common asset types have a different name.

System Name XP Scrum AgileUP DSDM
Scope Project Project Project Project
ScopeLabel Project Project Project Project
Story Story Backlog Item Requirement Requirement
Timebox Iteration Sprint Iteration Iteration
Theme Theme Feature Group Use Case Feature Group

Asset States

Asset states represent system-known life-cycle stage of an asset. The UI typically only show assets that are not "Dead".

State Name Meaning
0 Future
64 Active The asset has been assigned to a user-defined workflow status.
128 Closed The asset has been closed or quick-closed.
200 Template (Dead) The asset is only used to create new copies as part of creating from Templates or Quick Add.
208 Broken Down (Dead) The asset was converted to an Epic for further break-down.
255 Deleted (Dead) The asset has been deleted.

Attribute Definitions

Attribute definitions describe the properties that "make up" each asset type. Each attribute definition describes the type of data it can contain, as well as whether it is required, read only, multi-value, and many other qualities. Attribute definitions are identified by a name that is unique within its asset type. Attribute definitions are defined as either value types or relations to other assets. Furthermore, relation attribute definitions can be either single-value or multi-value.

For example, the Estimate attribute definition on the Workitem asset type is a scalar (specifically, a Number). On the other hand, the Workitem asset type's Scope attribute definition is a single-value relation (to a Scope asset). The reverse relation, Workitems on the Scope asset type, is a multi-value relation (to Workitem assets).

Oid

An Oid is a unique system identifier that is not typically visible in the VersionOne user interface. Oid Tokens are composed of the name of an asset type and an integer ID. For example, Member:20 identifies a Member asset with ID of 20.

This is not the same as the user visible Number attribute available on many (but not all) assets.

Attribute Definitions

An attribute is a single or multi-value property on an asset. For example, a Story has an attribute called Reference which contains text, while the Owners attribute is a multi-value relationship which allows multiple people to own a single Workitem asset. Attributes can be very simple such as the previously mentioned Reference attribute or they may be complex including downcasting, filters, and aggregates.

Projection

It can be useful to follow a relationship from one asset through another to get another piece of information. For example, if you wanted to know the name of a Category attribute on a Story asset you could ask for the attribute Category.Name and it would return the Name attribute of the StoryCategory which the Story asset relates to.

https://V1Host/V1Instance/rest-1.v1/Data/Story/1000/Category.Name

Downcast

A Scope asset has a relation calledWorkitems which points to all the Workitem assets that belong to the given Scope. This includes Story, Defect, Task, and Test asset types. If you wish to only get Story assets you can use downcasting to filter to Workitem assets to a specific type. The following example would return only those Story assets that are in Scope with ID 0.

https://V1Host/V1Instance/rest-1.v1/Data/Scope/0/Workitems:Story

Filter

In another example, you may wish to know all the Workitem assets in a given Scope that are owned by a specific Member. A filtered attribute would help solve this problem. You can use Workitems[Owners='Member:20'] to return only those Workitem assets that are owned by Member with ID 20. An example URL would look like the following.

https://V1Host/V1Instance/rest-1.v1/Data/Scope/0/Workitems[Owners='Member:20']

Aggregation

Let's say you wanted to get the total number of Workitem assets in a particular Scope. You can use the aggregate portion of an attribute to count the number of Workitem assets. The following example would return the total number of Workitem assets that belong to Scope with ID 0.

https://V1Host/V1Instance/rest-1.v1/Data/Scope/0/Workitems.@Count

Combination

To combine all of this into a more complex example, you may also wish to get the total Estimate for all Story assets that have an Owner and are in a given Scope. Rather than getting all Workitem assets and programmatically sorting them into buckets, the API can help you. You can follow a relationship, filter the relationship, and then finally use an aggregate to return the final count all using a single attribute on a Scope asset.

The corresponding attribute would be something like this: Workitems:Story[Owners.@Count!='0'].Estimate.@Sum In this example, the Scope.Workitems attribute will be downcast to only include Story assets, then filtered where the number of Owners is not zero. Once the filtered list is determined, then Estimate for those Story assets will be pulled and finally a single sum will be returned. This attribute will have a URL like the following.

https://V1Host/V1Instance/rest-1.v1/Data/Scope/0/Workitems:Story[Owners.@Count!='0'].Estimate.@Sum

~/meta.v1

Meta.v1 can be used to query for the description of all AssetTypes or a specific AssetType like Story, Defect, or Member. This can be useful if you want to know what Attributes are defined for a given Asset. It also inlcudes details about how Assets are related to one antother, what Attributes are required, and what operations can be executed on any given Asset.

~/meta.v1?xsl=api.xsl has a more human friendly representation of this information!

Query All

This endpoint retrieves a description of all AssetTypes like Story, Defect, Member.

HTTP Request

GET http://V1Host/V1Instance/meta.v1

HTTP Response

{
  "HREF": "/V1Instance/meta.v1/",
  "Version": "18.2.5.14",
  "AssetTypes": {
    "AssetType": {
      "_type": "AssetType",
      "Name": "AssetType",
      "Token": "AssetType",
      "DisplayName": "AssetType'AssetType",
      "Abstract": false,
      "DefaultOrderBy": {
        "href": "/V1Instance/meta.v1/AssetType/Order",
        "tokenref": "AssetType.Order"
      },
      "DefaultDisplayBy": {
        "href": "/V1Instance/meta.v1/AssetType/Name",
        "tokenref": "AssetType.Name"
      },
      "ShortName": {
        "href": "/V1Instance/meta.v1/AssetType/Name",
        "tokenref": "AssetType.Name"
      },
      "Name": {
        "href": "/V1Instance/meta.v1/AssetType/Name",
        "tokenref": "AssetType.Name"
      },
      "Attributes": {
        "AssetType.ID": {
          "_type": "AttributeDefinition",
          "Name": "ID",
          "Token": "AssetType.ID",
          "DisplayName": "AttributeDefinition'ID'AssetType",
          "AttributeType": "Relation",
          "IsReadOnly": true,
          "IsRequired": false,
          "IsMultivalue": false,
          "IsCanned": true,
          "IsCustom": false,
          "ReciprocalRelation": {
            "href": "/V1Instance/meta.v1/AssetType/ID",
            "tokenref": "AssetType.ID"
          },
          ...
        }
        ...
      }
    }
  }
}
curl "https://V1Host/V1Instance/meta.v1/:assetType"
  -H "Authorization: Bearer <access-token>"
  -H "Content-Type: application/json"
  -H "Accept: application/json"

Query

This endpoint retrieves a description of an AssetType like Story, Defect, Member or any Asset in the system.

HTTP Request

GET http://V1Host/V1Instance/meta.v1/:assetType

HTTP Response

{
  "_type": "AssetType",
  "HREF": "/V1Instance/meta.v1/Member",
  "Version": "18.2.5.14",
  "Name": "Member",
  "Token": "Member",
  "DisplayName": "AssetType'Member",
  "Abstract": false,
  "Base": {
    "nameref": "BaseAsset",
    "href": "/V1Instance/meta.v1/BaseAsset"
  },
  "DefaultOrderBy": {
    "href": "/V1Instance/meta.v1/Member/Name",
    "tokenref": "Member.Name"
  },
  "DefaultDisplayBy": {
    "href": "/V1Instance/meta.v1/Member/Name",
    "tokenref": "Member.Name"
  },
  "ShortName": {
    "href": "/V1Instance/meta.v1/Member/Nickname",
    "tokenref": "Member.Nickname"
  },
  "Name": {
    "href": "/V1Instance/meta.v1/Member/Name",
    "tokenref": "Member.Name"
  },
  ...
}
curl "https://V1Host/V1Instance/api/ActivityStream/:OidToken"
  -H "Authorization: Bearer <access-token>"
  -H "Accept: application/json"

~/api/asset

The bulk api can be used to make several operations in a single HTTP request.


Preview

http://V1Host/V1Instance/api/asset?previewonly=true

HTTP Request

The following request will not modify any asset within the system:

Payload:
{
    "from": "Story",
    "where":{
      "Number": "S-01004"
    },
    "update": {
        "Name": "Story Name Change"
    }
}

HTTP Response

Expect a result similar to this:

[
  {
    "@2b9d4588-4e1b-4bcb-b38b-a08ad59539e7": {
      "oid": "Story:1210",
      "update": {
        "Name": {
          "add": [
            "Story Name Change"
          ],
          "remove": []
        }
      }
    }
  }
]

Aliasing

Aliasing will allow you to assign the output of a bulk operation to a reference. One of the advantages of this feature is that it will allow users to make a reference to previously created assets in a later part of the payload. For example, I want to create a brand new scope and use this scope but reference it later on in the payload.

Create a new scope and then create a new story whose scope is the newly created scope.

HTTP Request

POST http://V1Host/V1Instance/api/asset

Payload:
[
  {
    "@newScope": {
      "AssetType":"Scope",
      "Name":"New Scope",
      "Super": "Scope:0"
    }
  },
  {
    "@newStory": {
      "AssetType":"Story",
      "Name":"New Story",
      "Scope": "@newScope"
    }
  }
]

HTTP Response

{
  "requestId": "767f7870-bc12-46d4-a978-e55e6bc405f1",
  "createdDate": "2018-08-24T15:06:53.1347214Z",
  "completedDate": "2018-08-24T15:06:53.2732206Z",
  "duration": "00:00:00.1384992",
  "durationSeconds": 0.1384992,
  "complete": true,
  "processing": false,
  "assetsCreated": {
    "oidTokens": [
        "Story:3604",
        "Scope:3606"
    ],
    "count": 1
  },
  "assetsModified": {
    "oidTokens": [],
    "count": 0
  },
  "assetsOperatedOn": {
    "oidTokens": [],
    "count": 0
  },
  "queryResult": {
    "results": [],
    "count": -1
  }
}
curl "https://V1Host/V1Instance/api/asset"
  -H "Authorization: Bearer <access-token>"
  -H "Content-Type: application/json"
  -H "Accept: application/json"
  --request POST
  --data '[ 
   "@newScope":{  
      "AssetType":"Scope",
      "Name":"New Scope",
      "Super": "Scope:0"
   },
   "@newStory":{  
      "AssetType":"Story",
      "Name":"New Story",
      "Scope": "@newScope"
   },
]'

Create

Create a single asset.

Example: Create a single story

HTTP Request

POST http://V1Host/V1Instance/api/asset

Payload:
{
  "AssetType": "Story",
  "Name": "New Story",
  "Scope": "Scope:0"
}

HTTP Response

{
  "requestId": "767f7870-bc12-46d4-a978-e55e6bc405f1",
  "createdDate": "2018-08-24T15:06:53.1347214Z",
  "completedDate": "2018-08-24T15:06:53.2732206Z",
  "duration": "00:00:00.1384992",
  "durationSeconds": 0.1384992,
  "complete": true,
  "processing": false,
  "assetsCreated": {
    "oidTokens": [
      "Story:3604"
    ],
    "count": 1
  },
  "assetsModified": {
    "oidTokens": [],
    "count": 0
  },
  "assetsOperatedOn": {
    "oidTokens": [],
    "count": 0
  },
  "queryResult": {
    "results": [],
    "count": -1
  }
}
curl "https://V1Host/V1Instance/api/asset"
  -H "Authorization: Bearer <access-token>"
  -H "Content-Type: application/json"
  -H "Accept: application/json"
  --request POST
  --data '{
    "AssetType": "Story",
    "Name": "New Story",
    "Scope": "Scope:0"
}'

Create Many

Create many assets via a single HTTP request.

Example: Create two stories and a new scope

HTTP Request

POST http://V1Host/V1Instance/api/asset

Payload:
[
  {
    "AssetType": "Story",
    "Name": "New Story",
    "Scope": "Scope:0"
  },
  {
    "AssetType": "Story",
    "Name": "Another New Story",
    "Scope": "Scope:0"
  },
  {
    "AssetType": "Scope",
    "Name": "New Scope",
    "Scope": "Scope:0"
  }
]

HTTP Response

{
  "requestId": "767f7870-bc12-46d4-a978-e55e6bc405f1",
  "createdDate": "2018-08-24T15:06:53.1347214Z",
  "completedDate": "2018-08-24T15:06:53.2732206Z",
  "duration": "00:00:00.1384992",
  "durationSeconds": 0.1384992,
  "complete": true,
  "processing": false,
  "assetsCreated": {
  "oidTokens": [
    "Story:3604",
    "Story:3605"
    "Scope:3606"
    ],
    "count": 1
  },
  "assetsModified": {
    "oidTokens": [],
    "count": 0
  },
  "assetsOperatedOn": {
    "oidTokens": [],
    "count": 0
  },
  "queryResult": {
    "results": [],
    "count": -1
  }
}
curl "https://V1Host/V1Instance/api/asset"
  -H "Authorization: Bearer <access-token>"
  -H "Content-Type: application/json"
  -H "Accept: application/json"
  --request POST
    --data '[
    {
      "AssetType": "Story",
      "Name": "New Story",
      "Scope": "Scope:0"
    },
    {
      "AssetType": "Story",
      "Name": "Another New Story",
      "Scope": "Scope:0"
    },
    {
      "AssetType": "Scope",
      "Name": "New Scope",
      "Scope": "Scope:0"
    }
  ]'

Filtering

Filter query results.

Example: Filter for stories that have 1 or more of their children that have not been deleted (or AssetState!=255)

HTTP Request

POST http://V1Host/V1Instance/api/asset

Payload:
{
  "from": "Story",
  "filter": [
    "Children[AssetState!=\"255\"].@Count>\"0\""
  ]
}

HTTP Response

{
  "requestId": "f380237e-e1e8-4310-950f-36ce16381e35",
  "createdDate": "2018-08-29T02:11:00.4022201Z",
  "completedDate": "2018-08-29T02:11:00.6050231Z",
  "duration": "00:00:00.2028030",
  "durationSeconds": 0.20280299999999998,
  "complete": true,
  "processing": false,
  "assetsCreated": {
    "oidTokens": [],
    "count": 0
  },
  "assetsModified": {
    "oidTokens": [],
    "count": 0
  },
  "assetsOperatedOn": {
    "oidTokens": [],
    "count": 0
  },
  "queryResult": {
    "results": [
      [
        {"_oid": "Story:2345"},
        {"_oid": "Story:3456"}
      ]
    ],
    "count": 1
  }
}
curl "https://V1Host/V1Instance/api/asset"
  -H "Authorization: Bearer <access-token>"
  -H "Content-Type: application/json"
  -H "Accept: application/json"
  --request POST
  --data '{
    "from":"Story",
    "filter": [
      Children[AssetState!="255"].@Count>"0"
    ]
}'

Execute Operation

Execute an operation on a single asset.

Example: Delete story Story:1234

HTTP Request

POST http://V1Host/V1Instance/api/asset

Payload:
{
  "from": "Story:1234",
  "execute": "Delete"
}

HTTP Response

{
  "requestId": "340626bb-a623-4029-9eaa-e7441ee7fe3c",
  "createdDate": "2018-08-29T02:00:50.789788Z",
  "completedDate": "2018-08-29T02:00:51.133026Z",
  "duration": "00:00:00.3432380",
  "durationSeconds": 0.343238,
  "complete": true,
  "processing": false,
  "assetsCreated": {
    "oidTokens": [],
    "count": 0
  },
  "assetsModified": {
    "oidTokens": [],
    "count": 0
  },
  "assetsOperatedOn": {
    "oidTokens": [
      "Story:1234"
    ],
    "count": 1
  },
  "queryResult": {
    "results": [],
    "count": -1
  }
}
curl "https://V1Host/V1Instance/api/asset"
  -H "Authorization: Bearer <access-token>"
  -H "Content-Type: application/json"
  -H "Accept: application/json"
  --request POST
  --data '{
    "from": "Story:1234",
    "execute": "Delete"
}'

Update

Update attributes on a single asset.

Example: Update the name of Story:1234 to Updated Story

HTTP Request

POST http://V1Host/V1Instance/api/asset

Payload:
{
  "from": "Story:1234",
  "update": {
    "Name": "Updated Story"
  }
}

HTTP Response

{
  "requestId": "a39afdd9-e471-4ecd-9ff5-73fad2b9ef03",
  "createdDate": "2018-08-29T01:59:12.5584932Z",
  "completedDate": "2018-08-29T01:59:12.5740873Z",
  "duration": "00:00:00.0155941",
  "durationSeconds": 0.0155941,
  "complete": true,
  "processing": false,
  "assetsCreated": {
    "oidTokens": [],
    "count": 0
  },
  "assetsModified": {
    "oidTokens": [
      "Story:1234"
    ],
    "count": 1
  },
  "assetsOperatedOn": {
    "oidTokens": [],
    "count": 0
  },
  "queryResult": {
    "results": [],
    "count": -1
  }
}
curl "https://V1Host/V1Instance/api/asset"
  -H "Authorization: Bearer <access-token>"
  -H "Content-Type: application/json"
  -H "Accept: application/json"
  --request POST
  --data '{
    "from":"Story:1234",
    "update": {
      "Name": "Updated Story"
    }
}'

Update Many

Update attributes on multiple assets via a single HTTP request.

Example: Find all the stories that are in the Epic:1234 Epic and rename them

HTTP Request

POST http://V1Host/V1Instance/api/asset

Payload:
{
  "from": "Story",
  "where": {
    "Super": "Epic:1234"
  },
  "update": {
    "Name": "Updated Story"
  }
}

HTTP Response

{
  "requestId": "a39afdd9-e471-4ecd-9ff5-73fad2b9ef03",
  "createdDate": "2018-08-29T01:59:12.5584932Z",
  "completedDate": "2018-08-29T01:59:12.5740873Z",
  "duration": "00:00:00.0155941",
  "durationSeconds": 0.0155941,
  "complete": true,
  "processing": false,
  "assetsCreated": {
    "oidTokens": [],
    "count": 0
  },
  "assetsModified": {
    "oidTokens": [
      "Story:1234",
      "Story:1235",
      "Story:1242"
    ],
    "count": 3
  },
  "assetsOperatedOn": {
    "oidTokens": [],
    "count": 0
  },
  "queryResult": {
    "results": [],
    "count": -1
  }
}
curl "https://V1Host/V1Instance/api/asset"
  -H "Authorization: Bearer <access-token>"
  -H "Content-Type: application/json"
  -H "Accept: application/json"
  --request POST
  --data '{
    "from":"Story",
    "where": {
      "Super": "Epic:1234"
    },
    "update": {
      "Name": "Updated Story"
    }
}'

Query Assets

Query for assets with a single query specification and retrieve a single result set.

Example: Query for stories associated with Scope:0

HTTP Request

POST http://V1Host/V1Instance/api/asset

Payload:
{
  "from": "Story",
  "where": {
    "Scope": "Scope:0"
  },
  "select": [
    "Name"
  ]
}

HTTP Response:

{
  "requestId": "b71c55f7-8a5a-4465-b87f-73ea428fc92a",
  "createdDate": "2019-08-23T18:56:38.5865376Z",
  "completedDate": "2019-08-23T18:56:38.6835443Z",
  "duration": "00:00:00.0970067",
  "durationSeconds": 0.0970067,
  "complete": true,
  "processing": false,
  "assetsCreated": {
    "oidTokens": [],
    "count": 0
  },
  "assetsModified": {
    "oidTokens": [],
    "count": 0
  },
  "assetsOperatedOn": {
    "oidTokens": [],
    "count": 0
  },
  "queryResult": {
    "results": [
      [
        {
          "_oid": "Story:4014",
          "Name": "API Users can Read Error Details"
        },
        {
          "_oid": "Story:1692",
           "Name": "Product Managers can specfify priority"
        }
      ]
    ],
    "count": 1
  }
}
curl "https://V1Host/V1Instance/api/asset"
  -H "Authorization: Bearer <access-token>"
  -H "Content-Type: application/json"
  -H "Accept: application/json"
  --request POST
  --data '{
    "from": "Story",
    "where": {
      "Scope": "Scope:0"
    },
    "select": [
      "Name"
    ]
}'

Query Assets

Query for assets with multiple query specifications and retrieve multiple result sets.

Example: Query for stories associated with Scope:0 and also query for active members and their OwnedWorkitems.

HTTP Request

POST http://V1Host/V1Instance/api/asset

Payload:
[
  {
    "from": "Story",
    "wwhere": {
      "Scope": "Scope:0"
    },
    "select": [
      "Name"
    ]
  },
  {
    "from": "Member",
    "where": {
      "Inactive": false
    },
    "select": [
      "Name",
      "Username",
      {
        "from": "OwnedWorkitems",
        "select": [
          "Name"
        ]
      }
    ]
  }
]

HTTP Response:

{
  "requestId": "c722e9e3-1ac5-4d2d-93a6-2c2677d9c9e0",
  "createdDate": "2019-08-23T19:57:56.783439Z",
  "completedDate": "2019-08-23T19:57:56.955049Z",
  "duration": "00:00:00.1716100",
  "durationSeconds": 0.17160999999999999,
  "complete": true,
  "processing": false,
  "assetsCreated": {
    "oidTokens": [],
    "count": 0
  },
  "assetsModified": {
    "oidTokens": [],
    "count": 0
  },
  "assetsOperatedOn": {
    "oidTokens": [],
    "count": 0
  },
  "queryResult": {
    "results": [
      [
        {
          "_oid": "Story:4014",
          "Name": "API Users can Read Error Details"
        },
        {
          "_oid": "Story:1692",
           "Name": "Product Managers can specfify priority"
        }
      ],
      [
        {
          "_oid": "Member:20",
          "Name": "Administrator",
          "Username": "admin",
          "OwnedWorkitems": [
            {
              "_oid": "Defect:1758",
              "Name": "Dialog box missing title"
            },
            {
              "_oid": "Epic:4123",
              "Name": "Error Reporting"
            }
          ]
        },
        {
          "_oid": "Member:1024",
          "Name": "Marv Irwin",
          "Username": "MarvIrwin",
          "OwnedWorkitems": [
            {
              "_oid": "Defect:4033",
              "Name": "API Error message lacks summary information"
            },
            {
              "_oid": "Story:4014",
              "Name": "API Users can Read Error Details"
            }
          ]
        },
        {
          "_oid": "Member:1043",
          "Name": "Billy Agilisto",
          "Username": "bagile",
          "OwnedWorkitems": [
            {
              "_oid": "Story:1692",
              "Name": "Product Managers can specfify priority"
            },
            {
              "_oid": "Story:3479",
              "Name": "Testers can rank Defect severity"
            },
            {
              "_oid": "Story:2046",
              "Name": "Release Managers can schedule Workitems into Releases"
            },
      ]
    ],
    "count": 2
  }
}
curl "https://V1Host/V1Instance/api/asset"
  -H "Authorization: Bearer <access-token>"
  -H "Content-Type: application/json"
  -H "Accept: application/json"
  --request POST
  --data '[
    {
      "from": "Story",
      "wwhere": {
        "Scope": "Scope:0"
      },
      "select": [
        "Name"
      ]
    },
    {
      "from": "Member",
      "where": {
        "Inactive": false
      },
      "select": [
        "Name",
        "Username",
        {
          "from": "OwnedWorkitems",
          "select": [
            "Name"
          ]
        }
      ]
    }
  ]'

Execute Scope.AssignMemberWithRole operation for single Member

Demonstrates how to assign a single Member to a Scope along with a Scope-specific role the Member will have for the target Scope.

Setup

For the context of this example, the following request will setup the instance with the needed starting conditions:

HTTP Request

POST http://V1Host/V1Instance/api/asset

Payload:
[
  {
    "from": "Member",
    "where": {
      "Name": "scopeMember1"
    },
    "execute": "Delete"
  },
  {
    "AssetType": "Scope",
    "Name": "Project for Members",
    "Parent": "Scope:0",
    "BeginDate": "2019-11-20T20:49:37.733Z"
  },
  {
    "AssetType": "Member",
    "Name": "scopeMember1",
    "Password": "scopeMember1",
    "Nickname": "scopeMember1",
    "Username": "scopeMember1",
    "DefaultRole": "Role.Name'Observer"
  }
]

HTTP Request

The following request invokes the behavior:

POST http://V1Host/V1Instance/api/asset

Payload:
{
  "from": "Scope:1065",
  "execute": {
    "op": "AssignMemberWithRole",
    "args": {
      "Member": "Member:1066",
      "Role": "Role:3",
      "IsOwner": true
    }
  }
}

HTTP Response

Expect a result similar to this:

{
  "requestId": "fd835822-54f2-475b-91ee-28826be351a9",
  "createdDate": "2019-11-20T20:49:37.8654392Z",
  "completedDate": "2019-11-20T20:49:37.8784385Z",
  "duration": "00:00:00.0129993",
  "durationSeconds": 0.0129993,
  "complete": true,
  "processing": false,
  "assetsCreated": {
    "oidTokens": [],
    "count": 0
  },
  "assetsModified": {
    "oidTokens": [],
    "count": 0
  },
  "assetsOperatedOn": {
    "oidTokens": [
      "Scope:1065"
    ],
    "count": 1
  },
  "commandFailures": {
    "commands": [],
    "count": 0
  },
  "queryResult": {
    "results": [],
    "count": -1
  }
}
  • Notice that the assetsOperatedOn.oidTokens array property contains a single scope token. This is because in this example we invoked the Scope.AssignMemberWithRole operation once on the scope for a single member.

Execute Scope.AssignMemberWithRole operation for list of Members

Demonstrates how to use a single command to assign multiple Members to a Scope along with Scope-specific roles each Member will have for the target Scope.

Setup

For the context of this example, the following request will setup the instance with the needed starting conditions:

HTTP Request

POST http://V1Host/V1Instance/api/asset

Payload:
[
  {
    "from": "Member",
    "filter": [
      "Name='scopeListMember1','scopeListMember2'"
    ],
    "execute": "Delete"
  },
  {
    "AssetType": "Scope",
    "Name": "Project for List of Members",
    "Parent": "Scope:0",
    "BeginDate": "2019-11-20T20:50:16.907Z"
  },
  {
    "AssetType": "Member",
    "Name": "scopeListMember1",
    "Password": "scopeListMember1",
    "Nickname": "scopeListMember1",
    "Username": "scopeListMember1",
    "DefaultRole": "Role.Name'Observer"
  },
  {
    "AssetType": "Member",
    "Name": "scopeListMember2",
    "Password": "scopeListMember2",
    "Nickname": "scopeListMember2",
    "Username": "scopeListMember2",
    "DefaultRole": "Role.Name'Observer"
  }
]

HTTP Request

The following request invokes the behavior:

POST http://V1Host/V1Instance/api/asset

Payload:
{
  "from": "Scope:1070",
  "execute": {
    "op": "AssignMemberWithRole",
    "list": [
      {
        "Member": "Member:1071",
        "Role": "Role:3",
        "IsOwner": true
      },
      {
        "Member": "Member:1072",
        "Role": "Role:7",
        "IsOwner": false
      }
    ]
  }
}

HTTP Response

Expect a result similar to this:

{
  "requestId": "fee67e0a-5bc8-4997-a531-c78c875b3029",
  "createdDate": "2019-11-20T20:50:17.1563425Z",
  "completedDate": "2019-11-20T20:50:17.188342Z",
  "duration": "00:00:00.0319995",
  "durationSeconds": 0.0319995,
  "complete": true,
  "processing": false,
  "assetsCreated": {
    "oidTokens": [],
    "count": 0
  },
  "assetsModified": {
    "oidTokens": [],
    "count": 0
  },
  "assetsOperatedOn": {
    "oidTokens": [
      "Scope:1070",
      "Scope:1070"
    ],
    "count": 2
  },
  "commandFailures": {
    "commands": [],
    "count": 0
  },
  "queryResult": {
    "results": [],
    "count": -1
  }
}
  • Notice that the assetsOperatedOn.oidTokens array property contains the same token twice. This is because in this example we invoked the Scope.AssignMemberWithRole operation on the same scope, passing different member oids each time.

Execute Scope.AssignMemberWithRole operation using a subquery

Demonstrates how to use a subquery to assign a single Member to a Scope along with a Scope-specific role the Member will have for the target Scope.

Setup

For the context of this example, the following request will setup the instance with the needed starting conditions:

HTTP Request

POST http://V1Host/V1Instance/api/asset

Payload:
[
  {
    "from": "Member",
    "where": {
      "Name": "scopeMember1"
    },
    "execute": "Delete"
  },
  {
    "AssetType": "Scope",
    "Name": "Project for Members",
    "Parent": "Scope:0",
    "BeginDate": "2019-11-21T16:56:22.438Z"
  },
  {
    "AssetType": "Member",
    "Name": "scopeMember1",
    "Password": "scopeMember1",
    "Nickname": "scopeMember1",
    "Username": "scopeMember1",
    "DefaultRole": "Role.Name'Observer"
  }
]

HTTP Request

The following request invokes the behavior:

POST http://V1Host/V1Instance/api/asset

Payload:
{
  "from": "Scope:1117",
  "execute": {
    "op": "AssignMemberWithRole",
    "args": {
      "Member": {
        "from": "Member",
        "where": {
          "Username": "scopeMember1"
        }
      },
      "Role": {
        "from": "Role",
        "where": {
          "Name": "Role.Name'Project Lead"
        }
      },
      "IsOwner": true
    }
  }
}
  • Notice that in the args property, the values for the Member and the Role properties are specified as subqueries. This makes it easier to create scripts which manipulate members and their project roles in the system using commonly shared values instead of having to separately query for oids first and then construct an HTTP request.
  • Note that when using subqueries, only the very first query result will be used as the property value. This means you may need to use sorting to get the correct value if your subquery has a chance of returning more than one asset.

    HTTP Response

Expect a result similar to this:

{
  "requestId": "2d1ac0a5-918d-4332-8d01-ba6607b8b8cd",
  "createdDate": "2019-11-21T16:56:22.5630306Z",
  "completedDate": "2019-11-21T16:56:22.589028Z",
  "duration": "00:00:00.0259974",
  "durationSeconds": 0.0259974,
  "complete": true,
  "processing": false,
  "assetsCreated": {
    "oidTokens": [],
    "count": 0
  },
  "assetsModified": {
    "oidTokens": [],
    "count": 0
  },
  "assetsOperatedOn": {
    "oidTokens": [
      "Scope:1117"
    ],
    "count": 1
  },
  "commandFailures": {
    "commands": [],
    "count": 0
  },
  "queryResult": {
    "results": [],
    "count": -1
  }
}
  • Notice that the assetsOperatedOn.oidTokens array property contains a single scope token. This is because in this example we invoked the Scope.AssignMemberWithRole operation once on the scope for a single member.

Execute Member.AssignToScopeWithRole operation for single scope

Demonstrates how to assign a single scope to a member along with a scope-specific role the member will have for assigned scope.

Setup

For the context of this example, the following request will setup the instance with the needed starting conditions:

HTTP Request

POST http://V1Host/V1Instance/api/asset

Payload:
[
  {
    "from": "Member",
    "filter": [
      "Name='memberForSoloScope'"
    ],
    "execute": "Delete"
  },
  {
    "from": "Scope",
    "filter": [
      "Name='Solo project for Member.AssignToScopeWithRole'"
    ],
    "execute": "Delete"
  },
  {
    "AssetType": "Scope",
    "Name": "Solo project for Member.AssignToScopeWithRole",
    "Parent": "Scope:0",
    "BeginDate": "2019-11-21T16:25:00.131Z"
  },
  {
    "AssetType": "Member",
    "Name": "memberForSoloScope",
    "Password": "memberForSoloScope",
    "Nickname": "memberForSoloScope",
    "Username": "memberForSoloScope",
    "DefaultRole": "Role.Name'Observer"
  }
]

HTTP Request

The following request invokes the behavior:

POST http://V1Host/V1Instance/api/asset

Payload:
{
  "from": "Member:1102",
  "execute": {
    "op": "AssignToScopeWithRole",
    "args": {
      "Scope": "Scope:1101",
      "Role": "Role:3",
      "IsOwner": true
    }
  }
}

HTTP Response

Expect a result similar to this:

{
  "requestId": "2a85553c-06ac-4832-a93b-5f65045a416f",
  "createdDate": "2019-11-21T16:25:00.5825599Z",
  "completedDate": "2019-11-21T16:25:00.67756Z",
  "duration": "00:00:00.0950001",
  "durationSeconds": 0.09500009999999999,
  "complete": true,
  "processing": false,
  "assetsCreated": {
    "oidTokens": [],
    "count": 0
  },
  "assetsModified": {
    "oidTokens": [],
    "count": 0
  },
  "assetsOperatedOn": {
    "oidTokens": [
      "Member:1102"
    ],
    "count": 1
  },
  "commandFailures": {
    "commands": [],
    "count": 0
  },
  "queryResult": {
    "results": [],
    "count": -1
  }
}
  • Notice that the assetsOperatedOn.oidTokens array property contains a single member token. This is because in this example we invoked the Member.AssignToScopeWithRole operation once on the member for a single scope.

Execute Member.AssignToScopeWithRole operation for list of scopes

Demonstrates how to assign multiple scopes to a member along with scope-specific roles the member will have for each of the assigned scopes.

Setup

For the context of this example, the following request will setup the instance with the needed starting conditions:

HTTP Request

POST http://V1Host/V1Instance/api/asset

Payload:
[
  {
    "from": "Member",
    "filter": [
      "Name='memberForScope1'"
    ],
    "execute": "Delete"
  },
  {
    "from": "Scope",
    "filter": [
      "Name='Project 1 for Member.AssignToScopeWithRole','Project 2 for Member.AssignToScopeWithRole'"
    ],
    "execute": "Delete"
  },
  {
    "AssetType": "Scope",
    "Name": "Project 1 for Member.AssignToScopeWithRole",
    "Parent": "Scope:0",
    "BeginDate": "2019-11-20T20:56:06.561Z"
  },
  {
    "AssetType": "Scope",
    "Name": "Project 2 for Member.AssignToScopeWithRole",
    "Parent": "Scope:0",
    "BeginDate": "2019-11-20T20:56:06.561Z"
  },
  {
    "AssetType": "Member",
    "Name": "memberForScope1",
    "Password": "memberForScope1",
    "Nickname": "memberForScope1",
    "Username": "memberForScope1",
    "DefaultRole": "Role.Name'Observer"
  }
]

HTTP Request

The following request invokes the behavior:

POST http://V1Host/V1Instance/api/asset

Payload:
{
  "from": "Member:1088",
  "execute": {
    "op": "AssignToScopeWithRole",
    "list": [
      {
        "Scope": "Scope:1086",
        "Role": "Role:3",
        "IsOwner": true
      },
      {
        "Scope": "Scope:1087",
        "Role": "Role:7",
        "IsOwner": false
      }
    ]
  }
}

HTTP Response

Expect a result similar to this:

{
  "requestId": "e08066c8-31fd-43f0-a313-523252793ff9",
  "createdDate": "2019-11-20T20:56:06.8228258Z",
  "completedDate": "2019-11-20T20:56:06.8408256Z",
  "duration": "00:00:00.0179998",
  "durationSeconds": 0.0179998,
  "complete": true,
  "processing": false,
  "assetsCreated": {
    "oidTokens": [],
    "count": 0
  },
  "assetsModified": {
    "oidTokens": [],
    "count": 0
  },
  "assetsOperatedOn": {
    "oidTokens": [
      "Member:1088",
      "Member:1088"
    ],
    "count": 2
  },
  "commandFailures": {
    "commands": [],
    "count": 0
  },
  "queryResult": {
    "results": [],
    "count": -1
  }
}
  • Notice that the assetsOperatedOn.oidTokens array property contains the same token twice. This is because in this example we invoked the Member.AssignToScopeWithRole operation on the same member, passing different scope oids each time.

Execute Member.AssignToScopeWithRole operation using a subquery

Demonstrates how to use a subquery to assign a single scope to a member along with a scope-specific role the member will have for assigned scope.

Setup

For the context of this example, the following request will setup the instance with the needed starting conditions:

HTTP Request

POST http://V1Host/V1Instance/api/asset

Payload:
[
  {
    "from": "Member",
    "filter": [
      "Name='memberForSubqueryScope'"
    ],
    "execute": "Delete"
  },
  {
    "from": "Scope",
    "filter": [
      "Name='Subquery project for Member.AssignToScopeWithRole'"
    ],
    "execute": "Delete"
  },
  {
    "AssetType": "Scope",
    "Name": "Subquery project for Member.AssignToScopeWithRole",
    "Parent": "Scope:0",
    "BeginDate": "2019-11-21T16:45:34.822Z"
  },
  {
    "AssetType": "Member",
    "Name": "memberForSubqueryScope",
    "Password": "memberForSubqueryScope",
    "Nickname": "memberForSubqueryScope",
    "Username": "memberForSubqueryScope",
    "DefaultRole": "Role.Name'Observer"
  }
]

HTTP Request

The following request invokes the behavior:

POST http://V1Host/V1Instance/api/asset

Payload:
{
  "from": "Member:1114",
  "execute": {
    "op": "AssignToScopeWithRole",
    "args": {
      "Scope": {
        "from": "Scope",
        "where": {
          "Name": "Subquery project for Member.AssignToScopeWithRole"
        }
      },
      "Role": {
        "from": "Role",
        "where": {
          "Name": "Role.Name'Project Lead"
        }
      },
      "IsOwner": true
    }
  }
}
  • Notice that in the args property, the values for the Scope and the Role properties are specified as subqueries. This makes it easier to create scripts which manipulate members and their project roles in the system using commonly shared values instead of having to separately query for oids first and then construct an HTTP request.
  • Note that when using subqueries, only the very first query result will be used as the property value. This means you may need to use sorting to get the correct value if your subquery has a chance of returning more than one asset.

    HTTP Response

Expect a result similar to this:

{
  "requestId": "3829e378-db9d-4bd7-b656-3edb195da6c5",
  "createdDate": "2019-11-21T16:45:35.0078639Z",
  "completedDate": "2019-11-21T16:45:35.0258636Z",
  "duration": "00:00:00.0179997",
  "durationSeconds": 0.0179997,
  "complete": true,
  "processing": false,
  "assetsCreated": {
    "oidTokens": [],
    "count": 0
  },
  "assetsModified": {
    "oidTokens": [],
    "count": 0
  },
  "assetsOperatedOn": {
    "oidTokens": [
      "Member:1114"
    ],
    "count": 1
  },
  "commandFailures": {
    "commands": [],
    "count": 0
  },
  "queryResult": {
    "results": [],
    "count": -1
  }
}
  • Notice that the assetsOperatedOn.oidTokens array property contains a single member token. This is because in this example we invoked the Member.AssignToScopeWithRole operation once on the member for a single scope.

Error: Create Epic and Subs where Scope is invalid causes cascade of four failures

Demonstrates how the API will return a cascade of failures when an invalid Scope is specified for a top-level Epic that has a collection of Subs. The failure messages can be modified and resubmitted to the API to create the original request's Assets.

HTTP Request

The following request invokes the behavior:

POST http://V1Host/V1Instance/api/asset

Payload:
{
  "AssetType": "Epic",
  "Scope": "Scope:9999",
  "Name": "My Epic on a Scope that DOES NOT EXIST which will produce a cascade of four failures!",
  "Subs": [
    {
      "AssetType": "Story",
      "Name": "My Story",
      "Children": [
        {
          "AssetType": "Test",
          "Name": "My Test"
        },
        {
          "AssetType": "Task",
          "Name": "My Task"
        }
      ]
    }
  ]
}

HTTP Response

Expect a result similar to this:

{
  "requestId": "adffb44e-f026-4fd2-94e3-d3e6cc8a0f52",
  "createdDate": "2019-11-06T20:01:08.0040847Z",
  "completedDate": "2019-11-06T20:01:08.0525809Z",
  "duration": "00:00:00.0484962",
  "durationSeconds": 0.048496199999999996,
  "complete": true,
  "processing": false,
  "assetsCreated": {
    "oidTokens": [],
    "count": 0
  },
  "assetsModified": {
    "oidTokens": [],
    "count": 0
  },
  "assetsOperatedOn": {
    "oidTokens": [],
    "count": 0
  },
  "commandFailures": {
    "commands": [
      {
        "@839e420a-f395-48ff-a522-4d7c9c8ce37e": {
          "AssetType": "Epic",
          "Scope": "Scope:9999",
          "Name": "My Epic on a Scope that DOES NOT EXIST which will produce a cascade of four failures!"
        },
        "error": {
          "message": "Violation'Invalid'Epic.Scope",
          "sourceCommandIndex": 0
        }
      },
      {
        "@bf084e75-1263-476f-af99-fa8153bf7ebd": {
          "AssetType": "Story",
          "Name": "My Story",
          "#ContextOid": "@839e420a-f395-48ff-a522-4d7c9c8ce37e"
        },
        "error": {
          "message": "Invalid OID token: @839e420a-f395-48ff-a522-4d7c9c8ce37e",
          "sourceCommandIndex": 0
        }
      },
      {
        "@4622a696-c001-414d-8749-fd620fd6a284": {
          "AssetType": "Test",
          "Name": "My Test",
          "#ContextOid": "@bf084e75-1263-476f-af99-fa8153bf7ebd"
        },
        "error": {
          "message": "Invalid OID token: @bf084e75-1263-476f-af99-fa8153bf7ebd",
          "sourceCommandIndex": 0
        }
      },
      {
        "@b92be85b-5039-4a84-93b7-e602bee7ab4b": {
          "AssetType": "Task",
          "Name": "My Task",
          "#ContextOid": "@bf084e75-1263-476f-af99-fa8153bf7ebd"
        },
        "error": {
          "message": "Invalid OID token: @bf084e75-1263-476f-af99-fa8153bf7ebd",
          "sourceCommandIndex": 0
        }
      }
    ],
    "count": 4
  },
  "queryResult": {
    "results": [],
    "count": -1
  }
}
  • Notice that objects returned in the commandFailures.commands property are in the form of complete commands. In this particular example, you would be able to edit the Scope value to point to an actual scope and resubmit either the original payload that had the nested assets, or simply submit the array of four commands in the failure details. Since the descendant nodes have been auto-aliased by the server and linearized, they will get processed properly by reference when resubmitted. The special #ContextOid keys that the server generated tell the server how to relate the descendant assets back to original hierarchy from the source command.
  • Also notice that each failure has a sourceCommandIndex property that identifies a zero-based index of the command that generated this error from your original payload. Because our original payload contained nested assets, each of these commands has 0 for this value.

Error: Query select unknown attribute

Demonstrates how the API will return a failure when you attempt to invoke an unknown attribute definition on an asset.

HTTP Request

The following request invokes the behavior:

POST http://V1Host/V1Instance/api/asset

Payload:
{
  "@user-alias": {
    "from": "Scope",
    "select": [
      "MuddleBubble"
    ]
  }
}

HTTP Response

Expect a result similar to this:

{
  "requestId": "9a4b517a-06a3-407f-9ff1-551e0343e382",
  "createdDate": "2019-11-21T15:26:14.0465326Z",
  "completedDate": "2019-11-21T15:26:14.0495334Z",
  "duration": "00:00:00.0030008",
  "durationSeconds": 0.0030007999999999996,
  "complete": true,
  "processing": false,
  "assetsCreated": {
    "oidTokens": [],
    "count": 0
  },
  "assetsModified": {
    "oidTokens": [],
    "count": 0
  },
  "assetsOperatedOn": {
    "oidTokens": [],
    "count": 0
  },
  "commandFailures": {
    "commands": [
      {
        "@user-alias": {
          "from": "Scope",
          "select": [
            "MuddleBubble"
          ]
        },
        "error": {
          "message": "Unknown AttributeDefinition: Scope.MuddleBubble",
          "sourceCommandIndex": 0
        }
      }
    ],
    "count": 1
  },
  "queryResult": {
    "results": [],
    "count": -1
  }
}
  • Notice that object returned in the commandFailures.commands property is in the form of a complete command. In this example, you could correct the selected attribute name to reference a legitimate attribute that exists on the Scope asset type.

Error: Invoking an unknown Operation

Demonstrates how the API will return a failure when you attempt to invoke an unknown operation on an asset.

HTTP Request

The following request invokes the behavior:

POST http://V1Host/V1Instance/api/asset

Payload:
{
  "from": "Scope:0",
  "execute": "NonexistentOperation"
}

HTTP Response

Expect a result similar to this:

{
  "requestId": "4b982452-b716-44ba-9445-a249b8adfb6c",
  "createdDate": "2019-11-19T20:17:57.9370732Z",
  "completedDate": "2019-11-19T20:17:57.9430751Z",
  "duration": "00:00:00.0060019",
  "durationSeconds": 0.0060019,
  "complete": true,
  "processing": false,
  "assetsCreated": {
    "oidTokens": [],
    "count": 0
  },
  "assetsModified": {
    "oidTokens": [],
    "count": 0
  },
  "assetsOperatedOn": {
    "oidTokens": [],
    "count": 0
  },
  "commandFailures": {
    "commands": [
      {
        "@a2811f5b-aa87-4ffc-8959-e9d343adfef9": {
          "oid": "Scope:0",
          "execute": {
            "op": "NonexistentOperation",
            "args": {}
          }
        },
        "error": {
          "message": "Unknown Operation 'Scope.NonexistentOperation'",
          "sourceCommandIndex": 0
        }
      }
    ],
    "count": 1
  },
  "queryResult": {
    "results": [],
    "count": -1
  }
}
  • Notice that objects returned in the commandFailures.commands property are in the form of complete commands. In this example, you could correct the operation name to reference a legitimate operation that exists on the Scope asset type.

Error: Query unknown asset type

Demonstrates how the API will return a failure when you attempt to query for an unknown asset type.

HTTP Request

The following request invokes the behavior:

POST http://V1Host/V1Instance/api/asset

Payload:
{
  "@user-alias": {
    "from": "Animal"
  }
}

HTTP Response

Expect a result similar to this:

{
  "requestId": "82a33f29-2a19-496c-979f-8009e3c82983",
  "createdDate": "2019-11-19T22:11:31.0308504Z",
  "completedDate": "2019-11-19T22:11:31.0318466Z",
  "duration": "00:00:00.0009962",
  "durationSeconds": 0.0009962,
  "complete": true,
  "processing": false,
  "assetsCreated": {
    "oidTokens": [],
    "count": 0
  },
  "assetsModified": {
    "oidTokens": [],
    "count": 0
  },
  "assetsOperatedOn": {
    "oidTokens": [],
    "count": 0
  },
  "commandFailures": {
    "commands": [
      {
        "@user-alias": {
          "from": "Animal"
        },
        "error": {
          "message": "Unknown AssetType: Animal",
          "sourceCommandIndex": 0
        }
      }
    ],
    "count": 1
  },
  "queryResult": {
    "results": [],
    "count": -1
  }
}
  • Notice that object returned in the commandFailures.commands property is in the form of a complete command. In this example, you could correct the asset type in the from clause to referebce a legitimate asset type.

Error: Query where with unknown attribute

Demonstrates how the API will return a failure when you attempt to query using a where clause referencing an attribute that is unknown on the target asset type.

HTTP Request

The following request invokes the behavior:

POST http://V1Host/V1Instance/api/asset

Payload:
{
  "@user-alias": {
    "from": "Scope",
    "where": {
      "MuddleBubble": "BubbleMuddle"
    },
    "select": [
      "Name"
    ]
  }
}

HTTP Response

Expect a result similar to this:

{
  "requestId": "2cc1e623-9dbe-474e-ac49-9774c8ba2c94",
  "createdDate": "2019-11-19T22:29:09.2679473Z",
  "completedDate": "2019-11-19T22:29:09.2689476Z",
  "duration": "00:00:00.0010003",
  "durationSeconds": 0.0010003,
  "complete": true,
  "processing": false,
  "assetsCreated": {
    "oidTokens": [],
    "count": 0
  },
  "assetsModified": {
    "oidTokens": [],
    "count": 0
  },
  "assetsOperatedOn": {
    "oidTokens": [],
    "count": 0
  },
  "commandFailures": {
    "commands": [
      {
        "@user-alias": {
          "from": "Scope",
          "where": {
            "MuddleBubble": "BubbleMuddle"
          },
          "select": [
            "Name"
          ]
        },
        "error": {
          "message": "Invalid QueryFilter2 token MuddleBubble='BubbleMuddle'",
          "sourceCommandIndex": 0
        }
      }
    ],
    "count": 1
  },
  "queryResult": {
    "results": [],
    "count": -1
  }
}
  • Notice that object returned in the commandFailures.commands property is in the form of a complete command. In this example, you could correct the where clause to refer to a legitimate attriute definition for the target asset type.

~/api/webhook

Webhook subscriptions allow you to define which events in VersionOne can fire webhooks.

By supplying a URL to an external system and a list of events that should trigger a webhook, you can inform that external system any time the event occurs in VersionOne.

You are able to create and edit webhooks to be as broad or specific as you'd like. For example, you can use webhooks to receive an HTTP request to the external system any time any Story Status changes, or any time a Story in Project A that is owned by Susan has a Status change.

By configuring the event with from, filter, with, and select, you can get very specific about which changes you want to be notified about in VersionOne.

External System

The external system can be configured by adding a url to the webhook subscription. If the external system requires an authorization token, you can add it as an authorizationHeader. This field will be sent as the HTTP Authorization Header each time an event triggers the webhook to be sent.

The webhookId will be helpful for you to query or update this webhook later, so make it meaningful and unique, if possible.

Add a short description to keep track of what this webhook is used for, such as where this webhook will be sent and why.

Event Types

VersionOne keeps track of any time an Asset is created, or updated. This allows us to create powerful webhook events modeled around Assets and their Attributes. Each event has a type from one of the following:

  • AssetCreated
  • AssetChanged

If I want a webhook triggered any time a Story changes, my event would look like:

{
  "type": "AssetChanged",
  "from": "Story"
}

You can also include an array of attributes that will allow you to specify which attributes of the asset you'd like to trigger webhooks. Omitting the attributes field will notify you of any changes to the asset.

If I want a webhook triggered any time a Story Status changes, my event would look like:

{
  "type": "AssetChanged",
  "from": "Story",
  "attributes": ["Status"]
}

We can enhance our event even more by filtering out Stories that don't meet a specified criteria using the filter and with fields. If I only want to know about Story Status changes for Stories in my Project, the event would look like:

{
  "type": "AssetChanged",
  "from": "Story",
  "attributes": ["Status"],
  "filter": ["Scope=$Scope"],
  "with": {
    "$Scope": "Scope:0"
  },
  "userContext": "Memeber:1002"
}

Many assets in VersionOne are secured by their relationship to a Scope (Project) limiting a member's ability to access a resource. We can configure the webhook to query on behalf of a sepcific user using the userContext field. Without this field, all assets independent of their relationship to Scope can produce webhooks. In the following case, only Status changes to Stories visible to Member 1002 will produce webhook events.

{
  "type": "AssetChanged",
  "from": "Story",
  "attributes": ["Status"],
  "userContext": "Memeber:1002"
}

When the webhook is fired, we might want details about the Story whose Status changed. You can use the select field to pick which of the Story's Attributes will be included in addition to the Asset's Oid. For example, if you want to know the Name of the Story and the Name of each of Owner of the Story, your event would look like:

{
  "type": "AssetChanged",
  "from": "Story",
  "attribute": ["Status"],
  "filter": ["Scope=$Scope"],
  "with": {
    "$Scope": "Scope:0"
  },
  "select": ["Name", "Owners.Name"]
}

Webhook

The webhook itself will include many details about the event that has occurred within VersionOne.

In each event object, the webhook will include the webhookId, which will allow the external system to identify which webhook subscription the response is associated with. It will also include a sequenceId, which will allow the system to determine the order in which the events occurred, along with the timestamp. This means your external system may receive the events out of order, but you can used the sequence id to guarantee that the order is accurate!

The webhook will also include information about the instigator, or the user who enacted the change in VersionOne that triggered the webhook, such as their name, role, email, and more.

Next, the webhook contains the target asset and changes, which will specify the asset on which the changes were made, as well as what those changes were.

The final section is the snapshot, which includes the information requested in the select field of the event type definition in your webhook subscription. Say you want webhooks fired when a Story Status changes, but when you receive the webhook you want to know specific details about the Story whose Status changed. By including attributes of the Story in your select, you can receive that projection of the Story in the webhook snapshot in the same shape as the results of the ~/api/query.v1 request.

{
  "events": [
    {
      "webhookId": "YYY",
      "sequenceId": 1,
      "eventType": "AssetChanged",
      "timestamp": "UTC timestamp",
      "instigator": {
        "_oid": "Member:20",
        "href": "https://V1Host/V1Instance/assetdetail.v1?oid=Member:20",
        "name": "Administrator",
        "nickName": "Admin",
        "email": "admin@admin.com",
        "role": "Role:2",
        "avatar": "https://V1Host/V1Instance/Image.mvc/Show?imageOid=Image:192923"
      },
      "targetAsset": {
        "_oid": "Story:123:456",
        "assetType": "Story",
        "href": "https://V1Host/V1Instance/assetdetail.v1?oid=Story:123"
      },
      "changes": [
        {
          "name": "Name",
          "old": "Original Name",
          "new": "New Name",
          "act": "Set"
        },
        {
          "name": "Owners",
          "new": "Member:20",
          "act": "Added"
        }
      ],
      "snapshot": [
        {
          "_oid": "Story:123",
          "Owners.Name": [
            "Administrator"
          ],
          "Owners.ID": [
            { "_oid": "Member:20" }
          ],
          "SubsAndMe.Owners.Name": [
            "Administrator"
          ]
        }
      ]
    }
  ]
}

Create

Create a webhook subscription.

HTTP Request

POST http://V1Host/V1Instance/api/webhook

Payload:
{
  "url": "https://externalsystem.com",
  "authroizationHeader": "Optional HTTP Authorization Header to send with each webhook", 
  "webhookId": "Webhook identifier",
  "enabled": true,
  "description": "Short description of the webhook subscription",
  "eventTypes": [],
}

HTTP Response

{
  "id": "336d997f-d9fa-4612-80e8-9f41a4b41352",
  "webhookId": "Webhook indentifier",
  "url": "https://externalsystem.com",
  "description": "Short description of the webhook subscription",
  "enabled": true,
  "eventTypes": [],
  "lastResponseAt": "0001-01-01T00:00:00Z",
  "retryCount": 0,
  "createdAt": "2018-09-27T20:28:41.3829451Z",
  "updatedAt": "2018-09-27T20:28:41.3829451Z",
  "createdBy": "Member:20"
}
Sorry we don't have an example yet! Fork our repo and help us document

Update

Update a webhook subscription by id.

HTTP Request

POST http://V1Host/V1Instance/api/webhook/:id

Payload:
{
  "url": "https://newurl.com", 
  "enabled": false,
  "description": "Updated description of the webhook subscription",
  "eventTypes": [],
}

HTTP Response

{
  "id": "336d997f-d9fa-4612-80e8-9f41a4b41352",
  "webhookId": "Webhook indentifier",
  "url": "https://newurl.com",
  "description": "Updated description of the webhook subscription",
  "enabled": false,
  "eventTypes": [],
  "lastResponseAt": "0001-01-01T00:00:00Z",
  "retryCount": 0,
  "createdAt": "2018-09-27T20:28:41.3829451Z",
  "updatedAt": "2018-09-27T20:28:41.3829451Z",
  "createdBy": "Member:20"
}
Sorry we don't have an example yet! Fork our repo and help us document

Query

Retrieve a paged list of existing webhook subscriptions. By default, a query of existing webhook subscriptions will start with the first subscription and show 25 per page, but that can be changed in the request.

HTTP Request

GET http://V1Host/V1Instance/api/webhook?page=pageSize,pageStart

HTTP Response

{
    "total": 1,
    "pageSize": 25,
    "pageStart": 0,
    "_type": "WebhookSubscription",
    "results": [
    {
      "id": "336d997f-d9fa-4612-80e8-9f41a4b41352",
      "webhookId": "Webhook indentifier",
      "url": "https://matchedUrl.com",
      "description": "Short description of the webhook subscription",
      "enabled": true,
      "eventTypes": [],
      "lastResponseAt": "0001-01-01T00:00:00Z",
      "retryCount": 0,
      "createdAt": "2018-09-27T20:28:41.3829451Z",
      "updatedAt": "2018-09-27T20:28:41.3829451Z",
      "createdBy": "Member:20"
    }
  ]
}
Sorry we don't have an example yet! Fork our repo and help us document

Delete

Delete a webhook subscription by id.

HTTP Request

POST http://V1Host/V1Instance/api/webhook/delete/:id

HTTP Response

{
  "id": "336d997f-d9fa-4612-80e8-9f41a4b41352",
  "webhookId": "Webhook indentifier",
  "url": "https://externalsystem.com",
  "description": "Short description of the webhook subscription",
  "enabled": true,
  "eventTypes": [],
  "lastResponseAt": "0001-01-01T00:00:00Z",
  "retryCount": 0,
  "createdAt": "2018-09-27T20:28:41.3829451Z",
  "updatedAt": "2018-09-27T20:28:41.3829451Z",
  "createdBy": "Member:20"
}
Sorry we don't have an example yet! Fork our repo and help us document

Status

Retrieve a list of the 20 most recent webhook receipts by id.

This is feature is useful for troubleshooting webhooks that don't seem to be working. The receipts will contain useful information to allow you to determine if your webhooks are being sent, if they are received, how the external system is responding, and additional information about the webhook, such as the timestamp, retry count, or if it included an Authorization Header.

HTTP Request

GET http://V1Host/V1Instance/api/webhook/status/:id

HTTP Response

[
  {
    "subscriptionId": "b3ff4f99-1436-4989-96a5-cb43341fc9e4",
    "hasAuthorizationHeader": true,
    "url": "https://externalsystem.com",
    "response": "Optional Response Information",
    "headers": {
      "transfer-Encoding": "chunked",
      "connection": "keep-alive",
      "x-Request-Id": "837ea952-2c56-4470-aa89-3f996ad1b65c",
      "x-Token-Id": "46054f26-412f-4772-a1d6-48648421fbc3",
      "x-RateLimit-Limit": "30",
      "x-RateLimit-Remaining": "26",
      "cache-Control": "no-cache",
      "content-Type": "text/plain; charset=UTF-8",
      "date": "Fri, 07 Dec 2018 19:54:53 GMT",
      "server": "nginx/1.10.3"
    },
    "status": 500,
    "timeStamp": "2018-12-07T19:54:09.59Z",
    "retryCount": 3,
    "wasReceived": false
  }
]
Sorry we don't have an example yet! Fork our repo and help us document

~/api/tags

First and foremost Tags are values that exist on most BaseAssets. Tags exist only in the context of the Assets they are added to. This means adding (and removing) tags for an Asset should be done via rest-1.v1/Data.

As of now Tags have been exposed on the following Assets via the AttributeDefinition TaggedWith

  • Story
  • Defect
  • Test Set
  • Task
  • Test
  • Portfolio Item
  • Regression Test

Query

The following example returns usage information for the specified <tag>. It will let you know based on your scope visibility the total # of usages of the tag count vs the usage that are visible to your member visibleCount.

HTTP Request

GET http://V1Host/V1Instance/api/tags?tag=<tag>

HTTP Response

{
  "tag": "UX",
  "count": 1,
  "visibleCount": 1
}
curl "https://V1Host/V1Instance/api/tags?tag='UX'"
  -H "Authorization: Bearer <access-token>"
  -H "Accept: application/json"

Query All

The following example returns every tag in use in the system with usage information broken down the same as the Single Tag above.

HTTP Request

GET http://V1Host/V1Instance/api/tags/all

HTTP Response

{
  "acceptanceTestDetails": {
    "tag": "AcceptanceTestDetails",
    "count": 1,
    "visibleCount": 1
  },
  "acceptanceTestDetails 2": {
    "tag": "AcceptanceTestDetails 2",
    "count": 1,
    "visibleCount": 1
  },
  "acceptanceTestDetails 3": {
    "tag": "AcceptanceTestDetails 3",
    "count": 1,
    "visibleCount": 1
  }
}
curl "https://V1Host/V1Instance/api/tags/all"
  -H "Authorization: Bearer <access-token>"
  -H "Accept: application/json"

Remove Tags

The following example will allow you to remove tags from every asset they exist on.

Remove command is restricted to users that have Project Admin access and will only work for projects they have scope visibility to. A user cannot remove tags on assets they cannot see or edit in the system.

HTTP Request

POST http://V1Host/V1Instance/api/tags/command/remove

{
  "MergeTo" : "Regression Tests",
  "MergeFrom" : ["RegressionTests", "RegTests"]
}
curl "https://V1Host/V1Instance/api/tags/command/remove"
  -H "Authorization: Bearer <access-token>"
  -H "Content-Type: application/json"
  -H "Accept: application/json"
  --request POST
  --data '{
    "removeFrom": [
      "RegressionTestDetails",
      "RegressionTests"
    ]
}'

Merge Tags

The following example will merge multiple tags into a single tag. It is possible to merge into an existing tag, or into a new tag. This will remove all of the tags listed in the MergeFrom array in the Post Data and will add the MergeTo tag to the assets the other tags were removed from.

HTTP Request

POST http://V1Host/V1Instance/api/tags/command/merge

{
  "MergeTo" : "Regression Tests",
  "MergeFrom" : ["RegressionTests", "RegTests"]
}
curl "https://V1Host/V1Instance/api/tags/command/merge"
  -H "Authorization: Bearer <access-token>"
  -H "Content-Type: application/json"
  -H "Accept: application/json"
  --request POST
  --data '{
    "MergeTo": "Regression Tests",
    "MergeFrom": [
      "RegressionTests",
      "RegTests"
    ]
}'

~/api/activityStream

This endpoint provides read-only access to the activity streams for assets and entities within VersionOne.

Query Params Meaning
anchorDate Datetime to use in selecting the returned activity. Defaults to 'now'.
direction 'Forward' or 'Back'. Controls whether activity earlier or later than the anchor date will be returned. Defaults to 'Back'.
maxCount Number of activities to return. Defaults to 25.
verbs A comma-separated list of verbs to act as a filter on the activity returned. By default, no filter is applied.

Valid verbs are:

  • Added
  • Blocked
  • Deleted
  • Deprecated
  • Closed
  • Created
  • Moved
  • Reopened
  • Removed
  • UnBlocked
  • Updated
  • Undeleted
  • Activated
  • Deactivated

Query Activity

View the activities for asset with the given OidToken

HTTP Request

GET http://V1Host/V1Instance/api/ActivityStream/:OidToken

HTTP Response

[
  {
    "body": {
      "actor": {
          "id": "Member:1065",
          "assetType": "Member",
          "displayName": "Tammy Coder",
          "username": "tammy",
          "email": "tammy.coder@company.com",
          "avatar": "Image:1936"
      },
      "verb": "Updated",
      "object": {
        "id": "Story:1220",
        "assetType": "Story",
        "displayName": "Delete RMA",
        "number": "S-01047",
        "assetState": "Active",
        "scope": "Scope:1258"
      },
      "time": "2014-04-22T14:11:01.1175003Z",
      "summary": "Tammy Coder Updated Story 'Delete RMA'",
      "provider": {
        "stream": "MetaStream",
        "commitSeq": "237",
        "commitId": "01a7b036-01f9-47a1-86b0-17a9c4c25544"
      },
      "target": [
        {
          "name": "Timebox",
          "newValue": {
            "id": "Timebox:1785",
            "assetType": "Timebox",
            "displayName": "Sprint 6",
            "assetState": "Future"
          },
          "oldValue": "",
          "verb": "Set",
          "summary": "Timebox was Set to 'Sprint 6'"
        },
        {
          "name": "Estimate",
          "newValue": "3.00",
          "oldValue": "2.00",
          "verb": "Set",
          "summary": "Estimate was Set to '3.00'"
        },
        {
          "name": "Priority",
          "newValue": "Medium",
          "oldValue": "High",
          "verb": "Set",
          "summary": "Priority was Set to 'Medium'"
        },
        {
          "name": "Risk",
          "newValue": "Low",
          "oldValue": "High",
          "verb": "Set",
          "summary": "Risk was Set to 'Low'"
        }
      ]
    }
  }
]
curl "https://V1Host/V1Instance/api/ActivityStream/<OidToken>"
  -H "Authorization: Bearer <access-token>"
  -H "Accept: application/json"

~/query.v1

USE: ~/api/asset

Read only api that allows retrieval of arbitrarily nested master/detail and hierarchical relationships. (For example, you can retrieve all the Schedules in a Scope, all the Iterations in the Schedules, and all the Workitems in the iterations, all in one go.)

An arbitrary number of independent queries can be executed in one HTTP round-trip.

Components of the HTTP POST request body:

Key Meaning
from Every query must have a "from" key with a string value naming the Asset Type to query. All other keys are optional.
select In order to retrieve any data, a selection list of the desired attributes is required. These attributes are in the VersionOne Selection Token syntax. Scalar attributes, relations, multivalued attributes, and traversal through a relation to all of the above are suppported.
filter the filter key is a sequence of VersionOne filter tokens as strings. Filter tokens name an attribute (possible traversing relations) and give a comparison operator and either a comparison value or a context variable that will be defined in the with clause.
with You may define variables in your filter tokens that will be filled via the with mapping. This can allow parameterization and alleviate quoting issues. with is a mapping of variable names to their values, and is applied over the entire query.
where the where key takes a value that is also a mapping. The keys of the mapping are taken as selection tokens, and the values of the mapping are taken as the value to compare against in an "equal" comparison.
sorting Any selection token can be used to sort the results. include a "sort" key with a value that is a list of selection tokens to sort by. Tokens can be preceded by + or - to indicate ascending or descending sort.
grouping You may group a set of assets by a related-to value. For example, stories can be grouped by status. The queried assets are returned in the _children element of the grouped-on asset.
find provides basic substring matching
findin list of selected attributes to search in
page You may limit the number of returned results, or start retrieving results starting from a particular index. Results are returned in ID order if no other sorting is applied, so paging will always be deterministic
asof Historical data is kept for all assets, and you may query for the state of assets "as of" a particular point in time. The asof value is a string with a timestamp in ISO format.

Response

Data is returned as a sequence of result sets. Each result set is a sequence that contains the results from one query mapping. Each result is a JSON object with fields for the selections you defined in the query mapping.

Asof

Historical data is kept for all assets, and you may query for the state of assets "as of" a particular point in time. The asof value is a string with a timestamp in ISO format.

HTTP Request

POST http://V1Host/V1Instance/query.v1

{
  "from": "Story",
  "select": [
    "Name",
    "ChangeDateUTC"
  ],
  "asof": "2016-01-01"
}

HTTP Response

[
  [
    {
      "_oid": "Story:1234:1265",
      "Name": "Name",
      "ChangeDateUTC": "2017-09-06T15:06:26.7530000Z",
    },
    {
      "_oid": "Story:1234:1266",
      "Name": "Updated Name",
      "ChangeDateUTC": "2017-09-06T17:06:26.7530000Z",
    }
  ]
]
curl "https://V1Host/V1Instance/query.v1"
  -H "Authorization: Bearer <access-token>"
  -H "Content-Type: application/json"
  -H "Accept: application/json"
  --request POST
  --data '{
    "from": "Story",
    "select": [ 
        "Name",
        "ChangeDateUTC"
    ],
    "asof": "2016-01-01"
}'

Filter

Filter on a collection of filter tokens which apply comparison operators to attributes and values.

HTTP Request

POST http://V1Host/V1Instance/query.v1

{
  "from": "Story",
  "select": [
    "Name",
    "Owners.@Count"
  ],
  "filter": [
    "Owners.@Count>'2'"
  ]
}

HTTP Response

[
  [
    {
      "_oid": "Story:1234",
      "Name": "Story Two",
      "Owners.@Count": "3"
    },
    {
      "_oid": "Story:4567",
      "Name": "Story Two",
      "Owners.@Count": "1"
    }
  ]
]
curl "https://V1Host/V1Instance/query.v1"
  -H "Authorization: Bearer <access-token>"
  -H "Content-Type: application/json"
  -H "Accept: application/json"
  --request POST
  --data '{
    "from": "Story",
    "select": [ 
        "Name",
        "Owners.@Count"
    ],
    "filter": [
      "Owners.@Count>'2'"
    ]
}'

Find and Findin

find contains a search term and findin specifies which attributes to locate the term within.

HTTP Request

POST http://V1Host/V1Instance/query.v1

{
  "from": "Story",
  "select": [
    "Name"
  ],
  "find": "As a user",
  "findin": [
    "Name"
  ]
}

HTTP Response

[
  [
    {
      "_oid": "Story:1234",
      "Name": "As a user I can do X"
    },
    {
      "_oid": "Story:4567",
      "Name": "As a user I can do Y"
    }
  ]
]
curl "https://V1Host/V1Instance/query.v1"
  -H "Authorization: Bearer <access-token>"
  -H "Content-Type: application/json"
  -H "Accept: application/json"
  --request POST
  --data '{
    "from": "Story",
    "select": [ 
        "Name"
    ],
    "find": "As a user",
    "findin": [
      "Name"
    ]
}'

Group

You may group a set of assets by a related-to value. For example, stories can be grouped by status. The queried assets are returned in the _children element of the grouped-on asset.

HTTP Request

POST http://V1Host/V1Instance/query.v1

{
  "from": "Story",
  "select": [
    "Name",
    "Number"
  ],
  "group": [
    {
      "from": "Status",
      "select": [
        "Name"
      ]
    }
  ]
}

HTTP Response

[
  [
    {
      "_oid": "NULL",
      "Name": null,
      "_children": [
        {
          "_oid": "Story:1215",
          "Name": "User Interface Story",
          "Number": "S-01054"
        }
      ]
    },
    {
      "_oid": "StoryStatus:133",
      "Name": "Future",
      "_children": [
        {
          "_oid": "Story:1153",
          "Name": "Partnerships",
          "Number": "S-01009"
        }
      ]
    },
    {
      "_oid": "StoryStatus:134",
      "Name": "In Progress",
      "_children": [
        {
          "_oid": "Story:1194",
          "Name": "Enter RMA",
          "Number": "S-01038"
        },
        {
          "_oid": "Story:1196",
          "Name": "Add Shipping Notes",
          "Number": "S-01039"
        }
      ]
    }
  ]
]
curl "https://V1Host/V1Instance/query.v1"
  -H "Authorization: Bearer <access-token>"
  -H "Content-Type: application/json"
  -H "Accept: application/json"
  --request POST
  --data '{
    "from": "Story",
    "select": [ 
        "Name",
        "Number"
    ],
    "group": [
      {
        "from": "Status",
        "select": [
          "Name"
        ]
      }
    ]
}'

Page

You may limit the number of returned results, or start retrieving results starting from a particular index.

Results are returned in ID order if no other sorting is applied, so paging will always be deterministic.

Paging only works for the topmost query. You cannot limit/page the results of subselections.

HTTP Request

POST http://V1Host/V1Instance/query.v1

{
  "from": "Story",
  "select": [
    "Name"
  ],
  "page": {
    "start": "0",
    "size": "5"
  }
}

HTTP Response

[
  [
    {
      "_oid": "Story:1234",
      "Name": "Story One"
    },
    {
      "_oid": "Story:2345",
      "Name": "Story Two"
    },
    {
      "_oid": "Story:3456",
      "Name": "Story Three"
    },
    {
      "_oid": "Story:4567",
      "Name": "Story Four"
    },
    {
      "_oid": "Story:5678",
      "Name": "No more than page size of 5!"
    }
  ]
]
curl "https://V1Host/V1Instance/query.v1"
  -H "Authorization: Bearer <access-token>"
  -H "Content-Type: application/json"
  -H "Accept: application/json"
  --request POST
  --data '{
    "from": "Story",
    "select": [ 
        "Name"
    ],
    "page" {
        "start": "0",
        "size": "5"
    }
}'

Query

Retrieve only the attributes you need from an asset.

HTTP Request

POST http://V1Host/V1Instance/query.v1

{
  "from": "Story",
  "select": [
    "Name",
    "Scope.Name"
  ]
}

HTTP Response

[
  [
    {
      "_oid": "Story:1234",
      "Name": "Their Story",
      "Scope.Name": "Project A"
    },
    {
      "_oid": "Story:5678",
      "Name": "My Story",
      "Scope.Name": "Project B"
    }
  ]
]
curl "https://V1Host/V1Instance/query.v1"
  -H "Authorization: Bearer <access-token>"
  -H "Content-Type: application/json"
  -H "Accept: application/json"
  --request POST
  --data '{
    "from": "Story",
    "select": [ 
        "Name",
        {
          "from": "Owners",
          "select": [
            "Name",
            "Avatar.Content"
          ]
        }
    ]
}'

Sort

Sort by selection tokens with ascending + or descending - order.

HTTP Request

POST http://V1Host/V1Instance/query.v1

{
  "from": "Story",
  "select": [
    "Name",
    "Estimate"
  ],
  "sort": [
    "+Name",
    "-Estimate"
  ]
}

HTTP Response

[
  [
    {
      "_oid": "Story:1234",
      "Name": "Story A",
      "Estimate": "3"
    },
    {
      "_oid": "Story:1234",
      "Name": "Story A",
      "Estimate": "1"
    },
    {
      "_oid": "Story:4567",
      "Name": "Story B",
      "Estimate": "5"
    }
  ]
]
curl "https://V1Host/V1Instance/query.v1"
  -H "Authorization: Bearer <access-token>"
  -H "Content-Type: application/json"
  -H "Accept: application/json"
  --request POST
  --data '{
    "from": "Story",
    "select": [ 
        "Name",
        "Estimate"
    ],
    "sort": [
      "+Name",
      "-Estimate"
    ]
}'

Subselect

Sub select a relation.

HTTP Request

POST http://V1Host/V1Instance/query.v1

{
  "from": "Story",
  "select": [
    "Name",
    "Owners.@Count",
    {
      "from": "Owners",
      "select": [
        "Name",
        "Avatar.Content"
      ]
    }
  ]
}

HTTP Response

[
  [
    {
      "_oid": "Story:1234",
      "Name": "Story Name",
      "Owners.@Count": "2",
      "Owners": [
        {
          "_oid": "Member:1234",
          "Name": "Andre Agile",
          "Avatar.Content": "iVBORw0KGgoAAAANSUh/ORK5CYII="
        },
        {
          "_oid": "Member:2345",
          "Name": "Alice Agility",
          "Avatar.Content": "/9j/4AAQSkZJRgABAQEAYAjlr2P/2Q=="
        }
      ]
    }
  ]
]
curl "https://V1Host/V1Instance/api/asset"
  -H "Authorization: Bearer <access-token>"
  -H "Content-Type: application/json"
  -H "Accept: application/json"
  --request POST
  --data '{
    "from": "Story",
    "select": [ 
        "Name",
        "Owners.@Count",
        {
          "from": "Owners",
          "select": [
            "Name",
            "Avatar.Content"
          ]
        }
    ]
}'

Where

the where key takes a value that is also a mapping. The keys of the mapping are taken as selection tokens, and the values of the mapping are taken as the value to compare against in an "equal" comparison.

HTTP Request

POST http://V1Host/V1Instance/query.v1

{
  "from": "Story",
  "select": [
    "Name"
  ],
  "where": {
    "Scope": "Scope:1234"
  }
}

HTTP Response

[
  [
    {
      "_oid": "Story:1234",
      "Name": "Story Name"
    }
  ]
]
curl "https://V1Host/V1Instance/query.v1"
  -H "Authorization: Bearer <access-token>"
  -H "Content-Type: application/json"
  -H "Accept: application/json"
  --request POST
  --data '{
    "from": "Story",
    "select": [ 
        "Name"
    ],
    "where": {
      "Scope": "Scope:1234"
    }
}'

With

Provide context to where clauses or filter with variables.

HTTP Request

POST http://V1Host/V1Instance/query.v1

{
  "from": "Story",
  "select": [
      "Name"
  ],
  "filter": [
    "Name=$myName"
  ],
  "where": {
    "Scope": "$myScope"
  },
  "with": {
    "$myScope": "Scope:1234",
    "$myName": "Alice Agility"
  }
}

HTTP Response

[
  [
    {
      "_oid": "Story:1234",
      "Name": "Story Name"
    }
  ]
]
curl "https://V1Host/V1Instance/query.v1"
  -H "Authorization: Bearer <access-token>"
  -H "Content-Type: application/json"
  -H "Accept: application/json"
  --request POST
  --data '{
    "from": "Story",
    "select": [ 
        "Name"
    ],
    "filter": [
      "Name=$myName"
    ],
    "where": {
      "Scope": "$myScope"
    },
    "with": {
      "$myScope": "Scope:1234",
      "$myName": "Alice Agility"
    }
}'

~/rest-1.v1

USE: ~/api/asset

This endpoint provides read, write, and update access to assets. This endpoint queries for simple or complex sets of information, updates information, and executes system-defined operations.

Query Params Meaning
asOf Use the asof query parameter to retrieve data as it existed at some point in time.
filter The filter parameter filters results to a subset that meet specific criteria. Whenever possible, use where or filter to explicitly choose specific assets, thereby reducing the load put on the application
findin Used in conjunction with the find parameter, findin specifies the attributes to check for the find substring. The findin parameter is optional. If omitted, a base set of attributes will be searched. This free text search is relatively expensive for VersionOne, so when the exact contents of a field should be matched, use the where parameter instead.
from Used in conjunction with the find parameter, findin specifies the attributes to check for the find substring. The findin parameter is optional. If omitted, a base set of attributes will be searched. This free text search is relatively expensive for VersionOne, so when the exact contents of a field should be matched, use the where parameter instead.
group The group parameter organizes results by value within an attribute. For example, stories can be grouped by status.
op The Operation op parameter calls an action for a single asset. For example, to delete an asset you must execute the Delete operation on the target asset. When executing an operation, a request must be an HTTP POST.
page Since some results from a query may be very large, you may limit the number of returned results or start retrieving results starting from a particular index. Results are returned in ID order if no other sorting is applied, so paging will always be deterministic. The page parameter specifies how many assets you want to retrieve and where to start in the list of assets. The page start represents the number of items from which to start and is zero indexed. It is an item count, not a page count. The page size is the maximum number of items to return on a page. For example if you have 100 assets and want to see the first 10, you would use a page start of 0, and a page size of 10. To retrieve the second page simply ask for a page start of 10 with a page size of 10, and so on.
select Without the select parameter, queries return a default set of attributes. The select parameter specifies which attributes to provide in the response. Whenever possible, use select to explicitly choose specific attributes, thereby reducing the load put on the application.
sort Any attribute definition can be used to sort the results of a query. Tokens can be preceded by + or - to indicate ascending or descending sort respectively.
where Without the where parameter, queries return the entire set of from assets. The where parameter filters the results to a subset that meet specific criteria. Whenever possible, use where or filter to explicitly choose specific assets, thereby reducing the load put on the application.
with Without the where parameter, queries return the entire set of from assets. The where parameter filters the results to a subset that meet specific criteria. Whenever possible, use where or filter to explicitly choose specific assets, thereby reducing the load put on the application.

Dichotomy of the Response

Assets

When requesting more than a single asset, the assets node helps navigate over the set of assets. The attributes total, pageSize, and pageStart can be used to navigate through a large set.

Asset

The Asset node has an href attribute containing the URL path used to retrieve this asset. The asset node has an id attribute with the OID Token for this asset.

Attribute

Name refers to an Attribute Definition.

Relation

Name refers to an Attribute Definition. Contains another asset node with an idref to the OID Token of the referenced asset.

Request Body

Both creating and updating assets via rest-1.v1 has a POST body structured with a collection of attributes. When creating, it can contain Attributes that will exist on the new asset, and when updating it can contain Attributes that will modify an existing Asset.

The keys are valid Attribute names for a given Asset. The value of each key is valid based on the following:

  • Scalars: like Name:
{
  "value": "New Name",
  "act": "set"
}
  • Single-value relation: like Scope:
{
  "value": "Scope:0",
  "act": "set"
}
  • Multi-value relations: like ChangeSets take an array. Each element of the array specifies an asset to add or remove from the relation and have the shape:
[
  { "idref": "<OidToken>", "act": "add" }
  { "idref": "<OidToken>", "act": "remove" }
]

Create

Update attributes a specific asset

HTTP Request

POST http://V1Host/V1Instance/rest-1.v1/Data/:AssetType

{  
  "Attributes":{  
    "Name":{  
      "value":"New Name",
      "act":"set"
    },
    "Scope":{  
      "value":"Scope:123",
      "act":"set"
    },
    "ChangeSets": {
    "value": [  
    {  
      "idref":"ChangeSet:123",
      "act":"add"
    },
    {  
      "idref":"ChangeSet:789",
      "act":"remove"
    }
      ]
  }
  }
}

HTTP Response

{
  "_type": "Asset",
  "href": "/V1Instance/rest-1.v1/Data/Story/4462/4631",
  "id": "Story:4462:4631",
  "Attributes": {
    "Name": {
      "_type": "Attribute",
      "name": "Name",
      "value": "New Name"
    },
    "Scope": {
      "_type": "Relation",
      "name": "Scope",
      "value": {
        "_type": "Asset",
        "href": "/V1Instance/rest-1.v1/Data/Scope/0",
        "idref": "Scope:0"
      }
    },
    "ChangeSets": {
      "_type": "Relation",
      "name": "ChangeSets",
      "value": [
        {
          "_type": "Asset",
          "href": "/V1Instance/rest-1.v1/Data/ChangeSet/123",
          "idref": "ChangeSet:123"
        }
      ]
    }
  }
}
curl "http://V1Host/V1Instance/rest-1.v1/Data/Story"
  -H "Authorization: Bearer <access-token>"
  -H "Accept: application/json"
  -H "Content-type: application/json"
  --request POST
  --data '{  
   "Attributes":{  
      "Name":{  
         "value":"New Name",
         "act":"set"
      },
      "Scope":{  
         "value":"Scope:123",
         "act":"set"
      },
      "ChangeSets":[  
         {  
            "idref":"ChangeSet:123",
            "act":"add"
         }
      ]
   }
}'

Update

Update attributes of a specific asset

HTTP Request

POST http://V1Host/V1Instance/rest-1.v1/Data/:AssetType/:OidToken

{  
  "Attributes":{  
    "Name":{  
      "value":"Updated Name",
      "act":"set"
    },
    "Scope":{  
      "value":"Scope:123",
      "act":"set"
    },
    "ChangeSets":[  
      {  
        "idref":"ChangeSet:123",
        "act":"remove"
      },
      {  
        "idref":"ChangeSet:987",
        "act":"add"
      }
    ]
  }
}

HTTP Response

{
  "_type": "Assets",
  "total": 13768,
  "pageSize": 5,
  "pageStart": 0,
  "Assets": [
    {
      "_type": "Asset",
      "href": "/V1Instance/rest-1.v1/Data/Story/1234",
      "id": "Story:1432",
      "Attributes": {
        "Name": {
          "_type": "Attribute",
          "name": "Name",
          "value": "Story Name"
        },
        "Number": {
          "_type": "Attribute",
          "name": "Number",
          "value": "S-1001"
        },
        "Super": {
          "_type": "Attribute",
          "name": "Super",
          "value": "Epic:1234"
        }
      }
    }
  ]
}
curl "http://V1Host/V1Instance/rest-1.v1/Data/Story/123"
  -H "Authorization: Bearer <access-token>"
  -H "Accept: application/json"
  -H "Content-type: application/json"
  --request POST
  --data '{  
   "Attributes":{  
      "Name":{  
         "value":"Updated Name",
         "act":"set"
      },
      "Scope":{  
         "value":"Scope:123",
         "act":"set"
      },
      "ChangeSets":[  
         {  
            "idref":"ChangeSet:123",
            "act":"add"
         },
         {  
            "idref":"ChangeSet:987",
            "act":"remove"
         }
      ]
   }
}'

Query

Query for assets of a specific asset type.

HTTP Request

GET http://V1Host/V1Instance/rest-1.v1/Data/:AssetType

HTTP Response

{
  "_type": "Assets",
  "total": 13768,
  "pageSize": 5,
  "pageStart": 0,
  "Assets": [
    {
      "_type": "Asset",
      "href": "/V1Instance/rest-1.v1/Data/Story/1234",
      "id": "Story:1432",
      "Attributes": {
        "Name": {
          "_type": "Attribute",
          "name": "Name",
          "value": "Story Name"
        },
        "Number": {
          "_type": "Attribute",
          "name": "Number",
          "value": "S-1001"
        },
        "Super": {
          "_type": "Attribute",
          "name": "Super",
          "value": "Epic:1234"
        }
      }
    }
  ]
}
curl "https://V1Host/V1Instance/rest-1.v1/Data/<AssetType>"
  -H "Authorization: Bearer <access-token>"
  -H "Accept: application/json"

Execute Operation

Execute an operation on a single asset

HTTP Request

POST http://V1Host/V1Instance/rest-1.v1/Data/:AssetType/:OidToken?op=<operationName>

{  
  "Attributes":{  
    "Name":{  
      "value":"Updated Name",
      "act":"set"
    },
    "Scope":{  
      "value":"Scope:123",
      "act":"set"
    },
    "ChangeSets":[  
      {  
        "idref":"ChangeSet:123",
        "act":"remove"
      },
      {  
        "idref":"ChangeSet:987",
        "act":"add"
      }
    ]
  }
}

HTTP Response

{
  "_type": "Assets",
  "total": 13768,
  "pageSize": 5,
  "pageStart": 0,
  "Assets": [
    {
      "_type": "Asset",
      "href": "/V1Instance/rest-1.v1/Data/Story/1234",
      "id": "Story:1432",
      "Attributes": {
        "Name": {
          "_type": "Attribute",
          "name": "Name",
          "value": "Story Name"
        },
        "Number": {
          "_type": "Attribute",
          "name": "Number",
          "value": "S-1001"
        },
        "Super": {
          "_type": "Attribute",
          "name": "Super",
          "value": "Epic:1234"
        }
      }
    }
  ]
}
curl "http://V1Host/V1Instance/rest-1.v1/Data/Story/123?op=Close"
  -H "Authorization: Bearer <access-token>"
  -H "Accept: application/json"
  --request POST

~/loc-2.v1

This endpoint provides localization and allows a client to retrieve the suggested localization of multiple strings. Often other VersionOne endpoints will return unlocalized strings such as suggested names or error messages. These unlocalized strings may be passed to loc-2.v1 which will attempt to translate the strings into locale specific strings returned as a JSON object with key-value pairs for each translation.

Asset Types

Retrieve the localized names of the <AssetType>s requested`.

HTTP Request

GET http://V1Host/V1Instance/loc-2.v1?[<AssetType>,<AssetType>]

HTTP Response

{
  "Scope": "Project",
  "Timebox": "Sprint"
}
curl "https://V1Host/V1Instance/loc-2.v1?[Scope,Timebox]"
  -H "Authorization: Bearer <access-token>"
  -H "Accept: application/json"

Attribute Definitions

Retrieve the localized names of the <AttributeDefinition>s requested`.

HTTP Request

GET http://V1Host/V1Instance/loc-2.v1?[<AttributeDefinition>,<AttributeDefinition>]

HTTP Response

{
  "AttributeDefinition'Name'Story": "Title",
  "AttributeDefinition'Description'Story": "Description"
}
curl "https://V1Host/V1Instance/loc-2.v1?[AttributeDefinition'Name'Story,AttributeDefinition'Description'Story]"
  -H "Authorization: Bearer <access-token>"
  -H "Accept: application/json"