Follow
API Basics

Workfront API's

The goal for the Workfront API is to simplify building integrations with Workfront by introducing a REST-ful architecture that operates over HTTP. This document assumes that the reader has a familiarity with REST and JSON responses and describes the approach taken by the new Workfront API. A familiarity with the Workfront schema will assist the reader in understanding the database relationships that can be utilized to pull data out of Workfront for integration purposes. Please refer to the section of this document titled Workfront Database Relationships as you prepare your own API integrations.

Limits and Guidelines

In order to ensure consistent Workfront On-Demand system performance, each customer is limited to ten concurrent API threads. The Sandbox environment will have the same limit in place, allowing customers and partners to accurately test API calls before releasing their code in production.

Disclaimer

Any use of the API should be tested in Workfront's beta environment prior to being run in the production environment. If any customer uses the API for a process that Workfront reasonably believes to be burdensome to the On-Demand Software (i.e. the process is causing a materially negative effect on the performance of the software for other customers), Workfront reserves the right to request that the customer discontinue that process and, if the customer does not comply and the problem persists, Workfront reserves the right to terminate the process.

REST Basics

An brief description of REST principles and a high level introduction of how to interact with the Workfront REST API.

Object URI

Each object in the system is given a unique URI consisting of the object type and the ID. For example, here are URIs describing three unique objects:

/attask/api/v7.0/project/4c78821c0000d6fa8d5e52f07a1d54d0
/attask/api/v7.0/task/4c78821c0000d6fa8d5e52f07a1d54d1
/attask/api/v7.0/issue/4c78821c0000d6fa8d5e52f07a1d54d2

The object type is case insensitive and can be either the abbreviated ObjCode (proj) or the alternate object name (project). A list of valid ObjCodes are provided in the API Explorer along with each objects fields and relations.

Operations

Objects are manipulated by sending an HTTP request to their unique URI. The operation to be performed is specified by the HTTP method. The standard HTTP methods correspond to the following operations.

  • GET - Retrieves an object by ID, searches for all objects by a query, run reports, or executes named queries.
  • POST - Inserts a new object.
  • PUT - Edits an existing object.
  • DELETE - Deletes an object.

The method parameter can be used to override HTTP behavior (in order to work around client deficiencies or protocol length limits). For example, a get operation may be implemented by posting the following URI:

GET /attask/api/v7.0/project?id=4c78...54d0&method=get
GET /attask/api/v7.0/project/4c78...54d0?method=get

Response

Each request will be given a response in JSON format. The response will have either a data attribute if the request was successful or an error attribute if there was a problem. For example:

GET /attask/api/v7.0/proj/4c7c08b20000002de5ca1ebc19edf2d5

might return the following JSON response:
{
    "data": [
        {
            "percentComplete": 0,
            "status": "CUR",
            "priority": 2,
            "name": "Brand New Project",
            "ID": "4c7c08b20000002de5ca1ebc19edf2d5"
        }
    ]
}

Warning:

When executing a GET request through your browser's address bar, it is not necessary to include the sessionID as part of the request.

Special security has been added around PUT, POST, and DELETE requests. Any request that results in writing to or deleting from the database can only be executed if the sessionID=abc123 is included in the URI. The following examples show how this would look for a DELETE request:

GET /attask/api/v7.0/project?id=4c78...54d0&method=delete&sessionID=abc123
GET /attask/api/v7.0/project/4c78...54d0?method=delete&sessionID=abc123

 

 

Authentication

The API authenticates each request to ensure that the client has access to view or modify the requested object.

Session ID

Authentication is performed by passing in a session ID which can be given in one of three ways -- request header, request parameter, or cookie.

Request Header

The preferred method of authentication is to pass a request header named SessionID containing the session token. This has the advantage of being safe against Cross-site Request Forgery (CSRF) attacks and not interfering with the URI for caching purposes. For example (as a request header):

GET /attask/api/v7.0/project/search
SessionID: abc1234

Request Parameter

It is also possible to authenticate by passing in a request parameter named sessionID. For example:

GET /attask/api/v7.0/project/4c78821c0000d6fa8d5e52f07a1d54d0?sessionID=abc1234

Cookie

Finally, the API will use the same cookie based authentication that is used by the web UI to the system. This means that if the client logs into Workfront using the web UI, any AJAX calls made from within the same browser will use the same authentication.

Note that this method of authentication is only available for read only operations to protect against the possibility of CSRFattacks.

Login

To obtain a session ID, the following request can be made with a valid username and password.

POST /attask/api/v7.0/login?username=admin&password=user

This will set a cookie to authenticate future requests as well as return a JSON response with the newly created sessionID, the userID of the logged in user, and other session attributes.

API key

Note:

If you have a designated API user who is also an administrator, it is strongly suggested you use an API key to log in. You can generate your API key when you log into the system as that user.

PUT /attask/api/v7.0/user?action=generateApiKey&username=username&password=password&method=put

You may also retrieve an API key that has been previously generated for a particular user.

PUT /attask/api/v7.0/user?action=getApiKey&username=user@email.com&password=userspassword&method=put

You can use this result to authenticate any API call by adding ‘apiKey’ as a request parameter with this value in place of a sessionID or username and password. This is beneficial from a security perspective.

An example of retrieving data from a project using the apikey:

 

GET /attask/api/v7.0/project/abc123xxxxx?apiKey=123abcxxxxxxxxx

If the API key value has been compromised you can run ‘clearApiKey’ which invalidates the current API key.

 

GET /attask/api/v7.0/user?action=clearApiKey&username=user@email.com&password=userspassword&method=put

Once cleared, you can run getApiKey again for a new API key.

Logout

When a session is complete, the following request can be made to log the user out, preventing any further access with the sessionID.

GET /attask/api/v7.0/logout?sessionID=abc1234

The sessionID to be logged out can be specified either as a cookie, a request header, or as a request parameter.

Try this now
  1. Go to your login screen (do not log in).
  2. Change the URL to /attask/api/v7.0/project/search.
  3. Notice the page cannot be found.
  4. Replace the word search with login?username=admin&password=user; substituting your username and password for admin and user
  5. Notice the response provided.
  6. Change the URL back to /attask/api/v7.0/project/search.
  7. Notice the response provided.

The session you initiated in step 4 is stored in the browser as a cookie and does not need to be restated in each subsequent GET request. You must always include the sessionID provided after log in when performing PUT, POST, and DELETE requests.

 

 

GET Behavior

The HTTP get method is used to retrieve an object or multiple objects. It can also be used to run reports.

ID Based Retrieval

If the ID for an object is known, it can be retrieved by accessing its unique URI. For example:

GET /attask/api/v7.0/project/4c78821c0000d6fa8d5e52f07a1d54d0

might return the following

{
    "percentComplete": 0,
    "status": "CUR",
    "priority": 2,
    "name": "Brand New Project",
    "ID": "4c7c08b20000002de5ca1ebc19edf2d5"
}

It is possible to retrieve multiple objects in the same request by specifying the id request parameter and giving a comma separated list of ID's.

GET /attask/api/v7.0/project?id=4c78...54d0,4c78...54d1

Note:

Notice the response for the /attask/api/v7.0/project?id=... request is the same as the /attask/api/v7.0/project/... request.

Search

It is possible to retrieve an object by criteria other than the ID by using the search URI.

GET /attask/api/v7.0/project/search

would return a list of all the projects in the system. Filters are specified using request parameters as name-value pairs. For example, the following would find all current projects:

GET /attask/api/v7.0/project/search?status=CUR

The following will find all the tasks that are not yet complete that are assigned to a user named John.

GET /attask/api/v7.0/task/search?percentComplete=100
&percentComplete_Mod=lt
&assignedTo:firstName=John

Listed below are some of the modifiers you can use through the Workfront API.

eq returns results that are in the status of closed.
...status=cls&status_Mod=eq...
ne returns results that are not in the status of closed.
...status=cls&status_Mod=ne...
gte returns results that have a percent complete greater then or equal to 50
...percentComplete=50&percentComplete_Mod=gte...
lte returns results that have a percent complete less then or equal to 50
...percentComplete=50&percentComplete_Mod=lte...
isnull returns results where description is null
...description_Mod=isnull...
notnull returns results where description is not null
...description_Mod=notnull...
contains returns results where name contains "Workfront"
...name=Workfront&name_Mod=contains...
between returns results that have an entry date within the last 7 days
...entryDate=$$TODAY-7d&entryDate_Range=$$TODAY&entryDate_Mod=between...
Note:

Capitalization matters, remember to make sure _Mod and _Range have the correct capitalization if you are gettings erors.

Map Results

By default, the data returned is a JSON array. Depending on the client's use case, it may be more efficient to get the result as a JSON object indexed by ID. This can be done by using the map request parameter. For example:

/attask/api/v7.0/task/search?map=true

would return a response indexed by ID like the following:

{
    "data": {
        "4c9a97db0000000f13ee4446b9aead9b": {
            "percentComplete": 0,
            "status": "NEW",
            "name": "first task",
            "ID": "4c9a97db0000000f13ee4446b9aead9b",
            "taskNumber": 1
        },
        "4ca28ba600002024cd49e75bd43cf601": {
            "percentComplete": 0,
            "status": "INP:A",
            "name": "second task",
            "ID": "4ca28ba600002024cd49e75bd43cf601",
            "taskNumber": 2
        }
    }
}

Fields

By default, retrieving an object only returns the most commonly used subset of fields. Use the fields request parameter to specify a comma separated list of specific fields that should be returned.

/attask/api/v7.0/task/search?fields=plannedStartDate,priority

would return

{
    "priority": 2,
    "name": "first task",
    "ID": "4c7c08fa0000002ff924e298ee148df4",
    "plannedStartDate": "2010-08-30T09:00:00:000-0600"
}

These field names are case sensitive.

Please note

A list of possible field references is available in the Workfront Database Relationships section of this document.

Nested Objects

It is also possible to obtain nested objects. For instance to get all issues along with their owners, do the following:

/attask/api/v7.0/issue/search?fields=owner

By default, nested objects are returned with only the name and ID. If more information is required you can request a nested field using colon syntax. To get all issues along with the owner's name, ID, title and phone number, do the following:

/attask/api/v7.0/issue/search?fields=owner:title,owner:phoneNumber

which would return

{
    "name": "an important issue",
    "ID": "4c78285f00000908ea8cfd66e084939f",
    "owner": {
        "title": "Operations Specialist",
        "phoneNumber": "555-1234",
        "name": "Admin User",
        "ID": "4c76ed7a0000054c172b2c2d9f7f81c3"
    }
}

Collections

It is also possible to retrieve nested collections of objects. For example, to get a project with all its tasks:

/attask/api/v7.0/project/search?fields=tasks

Another example is if you wish to get all task assignments:

/attask/api/v7.0/task/search?fields=assignments

By default only the name and ID of each task is returned, but additional nested fields can be specified with colon syntax. To view all available fields for a related object or collection, simply append a colon and asterisk to the object/collection reference.

/attask/api/v7.0/task/search?fields=assignments:*

Custom Data

Custom data fields can also be retrieved by using the prefix "DE:". For instance, to request a project with a parameter called "CustomText" the following request could be made.

/attask/api/v7.0/project/search?fields=DE:CustomText

which would return

{
    "name": "custom data project",
    "ID": "4c9a954f0000001afad0687d7b1b4e43",
    "DE:CustomText": "task b"
}

It is also possible to retrieve all the custom data for an object by requesting the parameterValues field.

/attask/api/v7.0/project/search?fields=parameterValues

would might return something like

{
    "name": "custom data project",
    "ID": "4c9a954f0000001afad0687d7b1b4e43",
    parameterValues: {
        "DE:CustomText": "task b",
        "DE:CustomNumber": 1.4,
        "DE:CustomCheckBoxes": ["first", "second", "third"]
    }
}

Named Queries

Some object types have named searches that are commonly executed. These are available by appending the name of the query to the end of the object type URI. For example, the following will retrieve the work items (tasks and issues) to which the user is currently assigned.

/attask/api/v7.0/work/myWork

Named queries support requesting the fields parameter to retrieve additional fields. Some named queries accept additional filters as well. A list of allowed named queries are available within the API Explorer under "actions" for each object.

Count

It is possible to retrieve only the number of results that would be returned by a given search. This allows the server to process the request more quickly and saves bandwidth. For example, the following request

GET /attask/api/v7.0/project/count?status=CUR

would return the number of results in the following format

{
    "count": 3
}

resulting in a much smaller download than if the full objects were sent. The filter syntax is identical to the search command.

Report

Report requests can also be performed, where only the aggregate of some field is desired, with one or more groupings. The report syntax is the same as the syntax for the SOAP API.

GET /attask/api/v7.0/hour/report?project:name_1_GroupBy=true&hours_AggFunc=sum

would return the following result

{
    "First Project": {
        "sum_hours": 15
    },
     "Second Project": {
        "sum_hours": 30
    }
}

Adding the $$ROLLUP=true parameter will also include a total at each grouping level.

{
    "First Project": {
        "sum_hours": 15
    },
    "Second Project": {
        "sum_hours": 30
    },
    "$$ROLLUP": {
        "sum_hours": 45
    }
}

Limits

To ensure a quality in performance certain limits have been placed on requests you make. These limits are listed below:

Default Number of Results 100 If no limit is specified in the query filter (ie, $$LIMIT), the result will contain no more than 100 primary objects. See the example below for instructions on how to use the $$LIMIT in your query filter.
Max Number of Results 2,000 Providing a value larger than 2,000 (the maximum number of results allowed) for $$LIMIT will result in an IllegalArgumentException error message.
Max Field Depth 4 When identifying the fields you wish to display, you cannot go more than 4 steps away from the object being queried.
Max Number of Objects 50,000 The result set may include at most 50000 primary and secondary objects.
Max Number of Fields 1,000,000 When the result set is fewer than 50000 objects., you results may include at most 1,000,000 fields.
Max Number of Batch Updates 100 The maximum batch update limit is 100.

*Primary vs. Secondary objects: For example, if a query is for projects, up to 2,000 projects can be returned. These 2,000 projects are primary objects. If a query is for the 'tasks' field on the projects, the 'tasks' field is a collection and a secodary object to the primary object Project, and can include hundreds or thousands of tasks of a project. In total, the combined number of projects and tasks returned cannot exceed the maximum of 50,000.

Paginated Responses

To override the default number of results and set the response to provide 200 results you would include the following in your query:

GET /attask/api/v7.0/project/search?$$LIMIT=200

To ensure reliability and performance for other tenants in the system, the maximum allowed limit per query is 2000 objects. Attempting to specify a larger limit will result in an error.

Therefore, it is recommended you consider using paginated responses for large datasets. To specify the first result that should be returned, the $$FIRST filter can be added. The following will return results 201-250 for a query.

GET /attask/api/v7.0/project/search?$$FIRST=201&$$LIMIT=50

Access Rule

For example, to set a project so it is shared only with a user with ID "abc123":

GET /attask/api/v7.0/project/123abcxxxxxxxxxxxxxxxxxxxxxxxxxx?method=put &updates={ accessRules: [ {accessorID: 'abc123', accessorObjCode: 'USER', coreAction: 'VIEW'} ] }

Alternatively to share only with a new person and keep existing permissions intact:

GET /attask/api/v7.0/project/123abcxxxxxxxxxxxxxxxxxxxxxxxxxx/share?method=put&accessorID=abc123&accessorObjCode=USER&coreAction=VIEW

Example of retrieving the existing access rules:

GET /attask/api/v7.0/project/123abcxxxxxxxxxxxxxxxxxxxxxxxxxx?fields=accessRules:*

 

 

POST Behavior

POST inserts a new object. The syntax is identical to PUT, but with a few exceptions. Because the new object does not yet exist it does not have an ID. For this reason the URI does not include the ID.

Create

To create a new project, the following request could be used.

POST /attask/api/v7.0/project?name=New Project

The response will include the newly created project along with its new ID and any other fields specified.

Copy

Some objects support being copied. For these object types it is possible to create a new object by posting with a copySourceID parameter. For example, the following request will copy the given project, giving it a new name.

POST /attask/api/v7.0/project?copySourceID=4c7...&name=Copied Project

The Workfront Explorer page displays which objects support the Copy action.

Uploads and Documents

API 2.0 allows users to upload documents through the following API URL:

POST /attask/api/v7.0/upload

The API expects the content type to be multipart/form-data. The parameter name for the file must be uploadedFile. The server will return the following JSON data:

{
    "handle": "4c7c08fa0000002ff924e298ee148df4"
}

The handle can then be used when creating an Workfront Document. To create an Workfront Document you will post to to the following URL:

POST /attask/api/v7.0/document?updates={
    name: aFileName,
    handle: abc...123, (handle from the file upload)
    docObjCode: PROJ, (or TASK, OPTASK, etc)
    objID: abc...123,
    currentVersion:{version:v1.0,fileName:aFileName}
}

 

 

PUT Behavior

PUT is used to update an existing object.

Edit

Updates to objects are always done by ID using the object's unique URI. Fields to be updated are specified as request parameters. For instance, to change the name of a project the following request could be sent.

PUT /attask/api/v7.0/project/4c7...?name=New Project Name
PUT /attask/api/v7.0/project?id=4c7...&name=New Project Name

Since update requires an ID, this operation fails (without insertion) if the object does not exist on the server.

JSON Edits

It is also possible to specify the fields to be updated using JSON syntax by using the updates request parameter. For example:

PUT /attask/api/v7.0/project/4c7...?updates=
{
     name: "New Project Name",
     status: "CUR",
     ...
}

Nested Updates

Some objects have privately owned collections that can be updated. The following example will overwrite the existing assignments for a given task.

PUT /attask/api/v7.0/task/4c7...?updates=
{
    assignments: [
        {
            assignedToID: "2222...54d0,
            assignmentPercent: 50.0
        },{
            roleID: "1111...54d0"
        }
    ]
}

It's important to note that while updates done at a top level are sparse, updates to a collection or nested object will completely replace the existing collection. To edit a single assignment on a task without affecting the others, do a PUT on the assignment rather than on the task.

As an additional example, the following will make a project a public help desk queue. Note that the existing queue properties are replaced.

PUT /attask/api/v7.0/project/4c7...?updates=
{
    queueDef: {
        isPublic: 1
    }
}

Response

The response for a PUT is identical to a GET, the server returning the new state of the object after the update. All rules that can be used to alter the response to a GET request will also work with a PUT, such as specifying additional fields to be returned, custom data, etc.

Actions

Some objects support additional actions that can be performed besides simple edits. These can be specified using the action request parameter. For example, the following request will recalculate the timeline for a given project.

PUT /attask/api/v7.0/project/4c7...?action=calculateTimeline

or

PUT /attask/api/v7.0/project/4c7.../calculateTimeline

The Workfront Objects page displays which actions can be made for each object.

Move

The following demonstrates the syntax for moving a task from one project to another:

PUT /attask/api/v7.0/task/4c7.../move?projectID=5d8...

An example for each action type is provided here:

PUT /attask/api/v7.0/project/1234/approveApproval

PUT /attask/api/v7.0/project/1234/calculateFinance

PUT /attask/api/v7.0/project/1234/calculateTimeline

PUT /attask/api/v7.0/project/1234/calculateDataExtension

PUT /attask/api/v7.0/project/1234/recallApproval

PUT /attask/api/v7.0/project/1234/rejectApproval

PUT /attask/api/v7.0/task/1234/move

PUT /attask/api/v7.0/workitem/1234/markViewed

Only the move action requires identifying additional attributes to specify the project where the work item will be moved.

The Workfront Objects page displays which objects support the Move action.

Details about which actions are available for each object type are available later in this document.

An example for each action type is provided here:

PUT /attask/api/v7.0/project/1234?method=put&updates={accessRules:[{accessorID: 'abc123', accessorObjCode: 'USER', coreAction: 'VIEW'}]}

Sharing Objects

To share a project with a team, you would do this:

PUT /attask/api/v7.0/project/123abcxxxxxxxxxxxxxxxxxxxxxxxxxx/share?accessorID=123abcxxxxxxxxxxxxxxxxxxxxxxxxxx&accessorObjCode=TEAMOB

Also, when editing an object, you can replace all access rules on an object by doing a PUT and sending updates like this:

PUT /attask/api/v7.0/project/123abcxxxxxxxxxxxxxxxxxxxxxxxxxx?method=PUT&updates={accessRules:[{accessorID:'123abcxxxxxxxxxxxxxxxxxxxxxxxxxx',accessorObjCode:'TEAMOB',coreAction:'VIEW'}]}

The following demonstrates the syntax for moving a task from one project to another:

PUT /attask/api/v7.0/task/4c7.../move?projectID=5d8...

 

 

DELETE Behavior

DELETE deletes an object. In every case, the URI may include the parameter force=true to cause the server to remove the specified data and its dependants. For example, a task is deleted through executing the HTTP DELETE method on the following URI.

DELETE /attask/api/v7.0/task/4c78821c0000d6fa8d5e52f07a1d54d0
DELETE /attask/api/v7.0/task?id=4c78821c0000d6fa8d5e52f07a1d54d0
DELETE /attask/api/v7.0/task/4c78821c0000d6fa8d5e52f07a1d54d0?force=true
DELETE /attask/api/v7.0/task?id=4c78821c0000d6fa8d5e52f07a1d54d0?force=true

 

Batch Processing (Bulk Updates)

A bulk update statement updates multiple objects at the same time within a single API call. A bulk create API call is built very similarly to a normal update call. See the following examples:

PUT /attask/api/v7.0/proj?updates=[{“name”:”Test_Project_1”},{“name”:”Test_Project_2”}]&method=POST&apiKey=123ab-cxxxxxxxxxxxxxxxxxxxxxxxxxx

That call returns something similar to this:

data: [{
    ID: “53ff8d3d003b438b57a8a784df38f6b3”,
    name: “Test_Project_1”,
    objCode: “PROJ”,
    percentComplete: 0,
    plannedCompletionDate: “2014-08-28T11:00:00:000-0400”,
    plannedStartDate: “2014-08-28T11:00:00:000-0400”,
    priority: 0,
    projectedCompletionDate: “2014-08-28T16:12:00:000-0400”,
    status: “CUR”
},
{
    ID: “53ff8d49003b43a2562aa34eea3b6b10”,
    name: “Test_Project_2”,
    objCode: “PROJ”,
    percentComplete: 0,
    plannedCompletionDate: “2014-08-28T11:00:00:000-0400”,
    plannedStartDate: “2014-08-28T11:00:00:000-0400”,
    priority: 0,
    projectedCompletionDate: “2014-08-28T16:12:00:000-0400”,
    status: “CUR”
}]

You also can do a bulk update like this:

PUT /attask/api/v7.0/proj?method=PUT&updates=[{"ID":"123abcxxxxxxxxxxxxxxxxxxxxxxxxxx","name":"Test_Project_1_ Edit"},{"ID":"123abcxxxxxxxxxxxxxxxxxxxxxxxxxx","name":"Test_Project_2_Edit"}]&apiKey=123abcxxxxxxxxxxxxxxxxxxxxxxxxxx

That call returns something similar to this:

data: [ {
     ID: "53ff8e15003b461d4560f7f65a440078",
     name: "Test_Project_1_Edit",
     objCode: "PROJ",
     percentComplete: 0,
     plannedCompletionDate: "2014-08-28T11:00:00:000-0400",
     plannedStartDate: "2014-08-28T11:00:00:000-0400",
     priority: 0,
     projectedCompletionDate: “2014-08-28T16:16:00:000-0400”,
     status: “CUR”
},
{
    ID: “53ff8e19003b46238a58d303608de502”,
    name: “Test_Project_2_Edit”,
    objCode: “PROJ”,
    percentComplete: 0,
    plannedCompletionDate: “2014-08-28T11:00:00:000-0400”,
    plannedStartDate: “2014-08-28T11:00:00:000-0400”,
    priority: 0,
    projectedCompletionDate: “2014-08-28T16:16:00:000-0400”,
    status: “CUR”
}]

If you want all operations to happen in the same transaction, add “atomic=true” to your batch API call as a request parameter. This way, if any of the operations fail, all of them will be rolled back. There is a limitation, however. Atomic batch operations can only return “success: true” or an error.