Asana API Documentation

Back to Developer Home »
Asana API Documentation

Overview

The Asana API is a RESTful interface, providing programmatic access to much of the data in the system. It provides predictable URLs for accessing resources, and uses built-in HTTP features to receive commands and return responses. This makes it easy to communicate with from a wide variety of environments, from command-line utilities to gadgets to the browser URL bar itself.

The API accepts JSON or form-encoded content in requests. It returns JSON content in all of its responses, including errors. Only the UTF-8 character encoding is supported for both requests and responses.

Use Cases

The Asana API lets you build a variety of applications and scripts to integrate Asana with your business systems, show Asana data in other contexts, and create tasks from various locations.

Here are some examples of the things you can build with the Asana API:

  • A browser extension to quickly create tasks from any web page
  • Source Control Integration to mark a task as complete and add a link to the code submission as a comment when submitting code.
  • A desktop app that shows the tasks assigned to you
  • A dashboard page that shows a visual representation of complete and incomplete tasks in a project

Hello World

Here is a sample application that creates a new task named "Hello World!" and assigns it to a user.

First, we set up some constants to deal with values that will depend on who is using this script. These include the user-specific API key, the ID of the workspace in which the new task will be created, and the email address of the user to whom it will be assigned.

Next, we set up our HTTP connection. Note that the API only accepts secure connections via HTTPS.

Then we can start building the request. The most important part is setting the Authorization header to provide the API key (more details in the Authentication section below).

All API POST and PUT requests expect a top-level object with a single element in it named data. Successful responses will mirror this format. The data element should itself be an object, containing the parameters for the request. In the case of creating a new task, these are the fields we want to set on the task itself.

If the request was successful, we will get a response code of 201 indicating the object was created. That response will have a data field at its top level, which will contain complete information on the new task, including its ID.

If something went wrong during the request, we'll get a different status code and the JSON returned will contain an errors field at the top level containing a list of problems. We look at the first one and print out its message.

#!/usr/bin/env ruby require "rubygems" require "JSON" require "net/https"

api_key = API-KEY workspace_id = WORKSPACE-ID assignee = ASSIGNEE-EMAIL

# set up HTTPS connection uri = URI.parse("https://app.asana.com/api/1.0/tasks") http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true http.verify_mode = OpenSSL::SSL::VERIFY_PEER

# set up the request header = { "Content-Type" => "application/json" }

req = Net::HTTP::Post.new(uri.path, header) req.basic_auth(api_key, '') req.body = { "data" => { "workspace" => workspace_id, "name" => "Hello World!", "assignee" => assignee } }.to_json()

# issue the request res = http.start { |http| http.request(req) } # output body = JSON.parse(res.body) if body['errors'] then puts "Server returned an error: #{body['errors'][0]['message']}" else puts "Created task with id: #{body['data']['id']}" end

Example Applications

In addition to the Hello World application, we have written a Chrome extension which demonstrates using the API in a browser extension:

Authentication

All API requests must contain some mechanism for identifying the user and ensuring they are authorized to make the request. The Asana API supports two separate authentication schemes: OAuth 2.0 and HTTP Basic Authentication using API keys. A client with a user's authorization (be that the API key or an OAuth bearer token) may access information and make changes in the Asana system as if it were that user.

Asana Connect (OAuth)

The Asana API supports authentication via Asana Connect, which uses the OAuth 2.0 framework. While we do not support all the authentication strategies detailed in the specification, those we do support conform to Draft 31 of the OAuth 2.0 Authorization Framework, and should be compatible with popular implementations of OAuth 2.0 such as the omniauth gem for ruby (in fact, you can use the omniauth-asana gem to get started right out of the box).

Supported Strategies

We support the Authorization Code Grant flow (most common for traditional web apps, as well as native desktop and mobile applications), as well as the Implicit Grant (suitable for in-browser web apps, such as single-site apps written in JavaScript that cannot make arbitrary POST requests to the Asana API).

Registering an Application

Developers seeking to implement an Asana Connect application must first register their app to receive a Client ID and Client Secret. Fortunately, this process is fast and easy: visit your Account Settings dialog and click the Apps tab. There will be a link to "Register New Application". As with all OAuth apps, you must supply an Application URL as well as a Redirect URL that successful (or failed) authentications will redirect to. Additionally, you can set a name and an icon to enhance the recognizability of the application. When users are prompted to authorize your app, they will be more likely to click "Allow" if it is clear who they are passing their authorization on to.

Once you have created an app, the details view will include a Client ID, needed to uniquely identify your app to the Asana API, as well as a Client Secret. Applications implementing the Authorization Code Grant flow use the secret to securely identify themselves when retrieving the user's bearer token.

Requesting Authorization from the User

While a thorough discussion of the OAuth specification exceeds the scope of this documentation, (and use of existing OAuth libraries for those unfamiliar with the standard is generally recommended), a high-level overview can be useful. In the typical Authorization Code Grant flow, you will redirect the user (or Resource Owner, in the parlance of OAuth) to the authorization endpoint, passing along the parameters for the request as standard HTTP query parameters. The user will either authorize (or not) your application, and will be redirected back to the Redirect URL, along with parameters containing a code. This code can be exchanged via POST to the token exchange endpoint for a token, which can then be used to make authenticated requests against the API.

When prompting users to authenticate with Asana Connect, developers should use a button with the text "Sign in with Asana". We recommend the images shown on the right, but developers may adapt the designs to their app as appropriate.

For a more in-depth look at how Asana Connect is implemented, take a look at our OAuth Examples, which contain both example implementations and a detailed look at the mechanics of using OAuth directly, for the adventurous.

Using the Bearer Token

Once you have a bearer token, you can make authenticated requests against the API on the user's behalf. In order to do this, simply add an HTTP header of the form "Authorization: Bearer $TOKEN" to your requests.

# example header using bearer authentication Authorization: Bearer 0/d3afa84f920bc329e6b0d047c9a7bc9d # curl request using bearer token authentication curl -H "Authorization: Bearer 0/d3afa84f920bc329e6b0d047c9a7bc9d" https://app.asana.com/api/1.0/users/me

API Keys

Each user has their own unique API key, which they can provide to applications to talk to Asana on their behalf. The API uses the widely supported HTTP Basic Authentication mechanism to authenticate requests with the API key. (See Using basic authentication below for details.)

Getting an API key

Any user can get their own API key by visiting the Account Settings dialog and clicking on the Apps tab. The API key is located at the bottom of this dialog.

You can go directly to the tab now to see your API key.

Using basic authentication

To authenticate a request, clients should use HTTP Basic Authentication and pass the API key as the username, and an empty password. This will cause the client to send a header like the following:

Username FcZ23.M4xsMtXmTKmDA4ssLCkEnYi
The API key for the requesting user.
Note: Most utilities and libraries that allow you to specify a username and password will handle proper encoding of the header for you. However, if you need to set the Authorization header manually, the header value is constructed by adding a colon (:) to the API key, then base64-encoding that string. You can read more on basic authentication if you need further details.
Password empty
The password should be blank.

# curl request using basic authentication curl -u FcZ23.M4xsMtXmTKmDA4ssLCkEnYi: https://app.asana.com/api/1.0/users/me
# Convert API key plus colon to base64 echo -n 'FcZ23.M4xsMtXmTKmDA4ssLCkEnYi:' | openssl enc -base64 >>> RmNaMjMuTTR4c010WG1US21EQTRzc0xDa0VuWWk6 # Example header using basic authentication Authorization: Basic RmNaMjMuTTR4c010WG1US21EQTRzc0xDa0VuWWk6

Errors

Sadly, sometimes requests to the API are not successful. Failures can occur for a wide range of reasons. In all cases, the API should return an HTTP Status Code that indicates the nature of the failure (below), with a response body in JSON format containing additional information.

200 Success. If data was requested, it will be available in the data field at the top level of the response body.
201 Success (for object creation). Its information is available in the data field at the top level of the response body. The API URL where the object can be retrieved is also returned in the Location header of the response.
400 Invalid request. This usually occurs because of a missing or malformed parameter. Check the documentation and the syntax of your request and try again.
401 No authorization. A valid API key was not provided with the request, so the API could not associate a user with the request.
403 Forbidden. The API key and request syntax was valid but the server is refusing to complete the request. This can happen if you try to read or write to objects or properties that the user does not have access to.
404 Not found. Either the request method and path supplied do not specify a known action in the API, or the object specified by the request does not exist.
429 Rate Limit Enforced. Asana imposes a limit on the rate at which users can make requests. The limit is currently around 100 requests per minute, but this is not guaranteed: it may vary with server load, and we may change it in the future. The Retry-After response header will specify the number of seconds until the user can make another request. Clients sending large bursts of requests should handle this error code to retry after the delay.

Rate limits are important to prevent abuse and keep the service available to everyone. If you definitely need a higher rate limit for your application, please contact developer support and we will look into granting an exception.
500 Server error. There was a problem on Asana's end.

In the event of an error, the response body will contain an errors field at the top level. This contains an array of at least one error object, described below:

message project: Missing input
Message providing more detail about the error that occurred, if available.
phrase 6 sad squid snuggle softly
500 errors only. A unique error phrase which can be used when contacting developer support to help identify the exact occurrence of the problem in Asana's logs.

Missing authorization header
# Request curl https://app.asana.com/api/1.0/users/me # Response HTTP/1.1 401 { "errors": [ { "message": "Not Authorized" } ] }
Bad request parameters
# Request curl -u <api_key>: https://app.asana.com/api/1.0/tasks # Response HTTP/1.1 400 { "errors": [ { "message": "workspace: Missing input" } ] }
Asana had a problem
# Request curl -u <api_key>: https://app.asana.com/api/1.0/users/me # Response HTTP/1.1 500 { "errors": [ { "message": "Server Error", "phrase": "6 sad squid snuggle softly" } ] }

Input/Output Options

In addition to providing fields and their values in a request, you may also specify options to control how your request is interpreted and how the response is generated. For GET requests, options are specified as URL parameters prefixed with opt_. For POST or PUT requests, options are specified in the body, inside the top-level options object (a sibling of the data object).

These options can be used in combination in a single request, though some of them may conflict in their impact on the response.

pretty ?opt_pretty
options: { pretty: true }
Provides the response in "pretty" output. In the case of JSON this means doing proper line breaking and indentation to make it readable. This will take extra time and increase the response size so it is advisable only to use this during debugging.
method options: { method: "put" }
In environments that do not support the full range of HTTP verbs, this can be helpful to override the request method sent by the browser, allowing access to the full range of actions in the API. This should only be used when absolutely necessary, as circumventing the browser's normal interpretation of the HTTP verbs can cause issues.
Note: For security reasons, you cannot use this parameter from a GET request, you can only use it to transform a POST request into something else (like a PUT or DELETE).
fields ?opt_fields=followers,assignee
options: { fields: ["followers", "assignee"] }
Some requests return compact representations of objects, to conserve resources and complete the request more quickly. Other times requests return more information than you may need. This option allows you to list the exact set of fields that the API should be sure to return for the objects. The field names should be provided as paths, described below.
Note: the id of included objects will always be returned, regardless of the field options.
expand ?opt_expand=followers
options: { expand: ["followers"] }
Query results and sub-objects are returned in compact form by default. This option can be used to expand query results or sub-objects to return more detailed information. Be sure you really need the information in the expanded form, as executing a query with many results in expanded form can be costly and return you a lot of data to consume.
Note: If the fields option is also used, it will take precedence over the expand option and prevent expansion.
jsonp ?opt_jsonp=myCallback
Returns the output in JSON-P format instead of plain JSON, to allow requests to come from within browsers and work around the "same origin policy." The function named as the value of the opt_jsonp parameter will be called with a single argument, a JavaScript object representing the response.
Note: This option is only allowed when using Asana Connect, for security reasons.

Paths for fields/expand options

Some output options allow you to reference fields of objects that specify paths of fields to either include or expand. These paths take the form a.b.c… where a is the name of a field on an object returned at the top level that refers to one or more child objects, b the name of a field on those child objects that refers to one or more grandchild objects, and so on. The leaf or final entry in the path refers to any field on that object and is the field affected by the option.

For example, when retrieving a task or tasks, consider the path followers.email. It refers to the email field all users mentioned in the followers field of the task or tasks returned, as illustrated in the annotated output below.

A period (.) on its own is the special designator for the root path, and refers to the object or objects returned at the root level.

Data Path
"data": { .
"id": 1001,
"name": "Feed the cat", name
"workspace": { workspace
"id": 14916,
"name": "Shared Projects", workspace.name
},
"followers": [{ followers
"id": 1234,
"email": "tbizarro@…", followers.email
}, {
"id": 5678,
"email": "gsanchez@…", followers.email
}]
}

Default output
# Request curl -u <api_key>: https://app.asana.com/api/1.0/users/me # Response HTTP/1.1 200 {"data":{"email":"sanchez@...","id":999,"name":"Greg Sanchez"}}
Pretty output (how all API requests in this doc are presented)
# Request curl -u <api_key>: "https://app.asana.com/api/1.0/users/me?opt_pretty" # Response HTTP/1.1 200 { "data": { "email": "sanchez@...", "id": 999, "name": "Greg Sanchez" } }
Get only name and description of task
# Request curl -u <api_key>: "https://app.asana.com/api/1.0/tasks/1224?opt_fields=name,notes" # Response HTTP/1.1 200 { "data": { "name": "Make a list", "notes": "Check it twice!", "id": 1224 } }
Reassign task, expanding projects in output
# Request curl --request PUT -u <api_key>: https://app.asana.com/api/1.0/tasks/1001 \ -d "assignee=1234" \ -d "options.expand=%2Aprojects%2A" # Response HTTP/1.1 200 { "data": { "id": 1001, "projects": [ { "archived": false, "created_at": "", "followers": [], "modified_at": "", "notes": "", "id": 1331, "name": "Things to buy" } ], ... } }

Pagination

The API supports paginating requests. This allows you to query for a small number of objects at a time, to get results faster; should there be more results, the API will return an offset that will allow you to access the next page.

To prevent current integrations from breaking, pagination is not enabled by default. Instead, you can request paginated results by providing the optional limit parameter in your query.

If you make a paginated request, the API will limit the number of results as specified by the limit parameter. If more results exist, then an offset to request the next page of results will be included in the offset attribute, contained in the next_page attribute. If there are no more pages available, next_page will be null and no offset will be provided. Do note that an offset token will expire after some time, as data may have changed.

limit 20
The number of objects to return per page. The value must be between 1 and 100.
offset eyJ0eXAiOJiKV1iQLCJhbGciOiJIUzI1NiJ9
An offset to the next page returned by the API. A pagination request will return an offset token, which can be used as an input parameter to the next request. If an offset is not passed in, the API will return the first page of results.
Note: You can only pass in an offset that was returned to you via a previously paginated request.

This method returns paginated results for tasks from a project.
# Request curl -u <api_key>: "https://app.asana.com/api/1.0/tasks?project=1337&limit=5&offset=eyJ0eXAiOJiKV1iQLCJhbGciOiJIUzI1NiJ9" # Response { "data": [ { "id": 1000, "name": "Task 1", ... }, ... ], "next_page": { "offset": "yJ0eXAiOiJKV1QiLCJhbGciOiJIRzI1NiJ9", "path": "/tasks?project=1337&limit=5&offset=yJ0eXAiOiJKV1QiLCJhbGciOiJIRzI1NiJ9", "uri": "https://app.asana.com/api/1.0/tasks?project=1337&limit=5&offset=yJ0eXAiOiJKV1QiLCJhbGciOiJIRzI1NiJ9" } }

Users

A user object represents an account in Asana that can be given access to various workspaces, projects, and tasks.

Like other objects in the system, users are referred to by numerical IDs. However, the special string identifier me can be used anywhere a user ID is accepted, to refer to the current authenticated user.

Users only have a small set of fields:

email gsanchez@example.com
Read-only. The user's email address.
name Greg Sanchez
Read-only. The user's name.
photo { "image_21x21": "https://...", ... }
Read-only. A map of the user's avatar in various sizes, or null if no avatar is set. Sizes provided are 21, 27, 36, 60, and 128, images are in PNG format.
workspaces [ { id: 14916, name: "My Workspace"} ... ]
Read-only. Workspaces and organizations this user may access.
Note: You may only see workspaces and organizations that you are in.

Showing a single user

GET /users/user-id
GET /users/me

This method returns the full user record for a single user.

Show a single user.
# Request curl -u <api_key>: https://app.asana.com/api/1.0/users/5678 # Response HTTP/1.1 200 { "data": { "email": "gsanchez@example.com", "id": 5678, "name": "Greg Sanchez", "workspaces": [ { "id": 1337, "name": "My Favorite Workspace" }, ... ] } }

Showing all users in all workspaces

GET /users

This method returns the user records, described above, for all users in all workspaces and organizations you may access.

Show names and emails of all users in all workspaces and organizations you're a member of.
# Request curl -u <api_key>: "https://app.asana.com/api/1.0/users?opt_fields=name,email" # Response HTTP/1.1 200 { "data": [ { "email": "tbizarro@example.com", "id": 1234, "name": "Tim Bizarro" }, { "email": "gsanchez@example.com", "id": 5678, "name": "Greg Sanchez" }, ... ] }

Showing all users in a single workspace or organization

GET /workspaces/workspace-id/users

This method returns the user records, described above, for all users in the specified workspace or organization.

Show all users in a single workspace or organization.
# Request curl -u <api_key>: https://app.asana.com/api/1.0/workspaces/1337/users # Response HTTP/1.1 200 { "data": [ { "id": 5678, "name": "Greg Sanchez" } ] }

Tasks

The task is the basic object around which many operations in Asana are centered. In the Asana application, multiple tasks populate the middle pane according to some view parameters, and the set of selected tasks determine the more detailed information presented in the details pane.

Tasks have a rich set of metadata associated with them, some of which is exposed via the API. Here are the accessible fields on a task:

assignee { id: 1234, name: "Tim Bizarro" }
User to which this task is assigned, or null if the task is unassigned.
assignee_status upcoming
Scheduling status of this task for the user it is assigned to. One of the following values:
inbox In the inbox.
later Scheduled for later.
today Scheduled for today.
upcoming Marked as upcoming.
created_at 2012-02-22T02:06:58.147Z
Read-only. The time at which this task was created.
completed false
True if the task is currently marked complete, false if not.
completed_at 2012-02-22T02:06:58.147Z
Read-only. The time at which this task was completed, or null if the task is incomplete.
due_on 2012-03-26
Date on which this task is due, or null if the task has no due date.
followers [ { id: 1123, name: "Mittens" }, ... ]
Read-only. Array of users following this task.
hearted false
True if the task is hearted by the authorized user, false if not.
hearts [ { id: 1245, name: "Mittens" }, ... ]
Read-only. Array of users who have hearted this task.
modified_at 2012-02-22T02:06:58.147Z
Read-only. The time at which this task was last modified.
Note: This does not currently reflect any changes in associations such as projects or comments that may have been added or removed from the task.
name Buy catnip
Name of the task. This is generally a short sentence fragment that fits on a line in the UI for maximum readability. However, it can be longer.
notes Mittens really likes the stuff from Humboldt.
More detailed, free-form textual information associated with the task.
num_hearts 3
Read-only. The number of users who have hearted this task.
projects [ { id: 1331, name: "Stuff to Buy" }, ... ]
Create-only. Array of projects this task is associated with. At task creation time, this array can be used to add the task to many projects at once. After task creation, these associations can be modified using the addProject and removeProject endpoints.
parent { id: 52992, name: "My Parent task" }
Read-only. The parent of this task, or null if this is not a subtask. This property cannot be modified using a PUT request but you can change it with the setParent endpoint. You can create subtasks by using the subtasks endpoint.
workspace { id: 14916, name: "My Workspace" }
Create-only. The workspace this task is associated with. Once created, task cannot be moved to a different workspace. This attribute can only be specified at creation time.

Creating a new task

POST /tasks
POST /workspaces/workspace-id/tasks

Creating a new task is as easy as POSTing to the /tasks endpoint with a data block containing the fields you'd like to set on the task. Any unspecified fields will take on default values.

Every task is required to be created in a specific workspace, and this workspace cannot be changed once set. The workspace need not be set explicitly if you specify a parent task instead.

Create a task.
# Request curl -u <api_key>: https://app.asana.com/api/1.0/tasks \ -d "assignee=1235" \ -d "followers[0]=5678" \ -d "name=Hello, world%21" \ -d "notes=How are you today%3F" \ -d "workspace=14916" # Response HTTP/1.1 201 { "data": { "assignee": { "id": 1235, "name": "Tim Bizarro" }, "assignee_status": "inbox", "completed": false, "completed_at": null, "created_at": "2012-02-22T02:06:58.158Z", "due_on": null, "followers": [ { "id": 5678, "name": "Greg Sanchez" } ], "id": 1001, "modified_at": "2012-02-22T02:06:58.158Z", "name": "Hello, world!", "notes": "How are you today?", "parent": null, "projects": [ { "id": 14641, "name": "Cat Stuff" } ], "workspace": { "id": 14916, "name": "My Favorite Workspace" } } }

Showing a specific task

GET /tasks/task-id

You can retrieve an existing task given its ID with a simple GET request.

This method returns the complete task record, described above.

Show a task.
# Request curl -u <api_key>: https://app.asana.com/api/1.0/tasks/1001 # Response HTTP/1.1 200 { "data": { "assignee": { "id": 1234, "name": "Tim Bizarro" }, "created_at": "2012-02-22T02:06:58.158Z", ... } }

Updating an existing task

PUT /tasks/task-id

A specific, existing task can be updated by making a PUT request on the URL for that task. Only the fields provided in the data block will be updated; any unspecified fields will remain unchanged.

When using this method, it is best to specify only those fields you wish to change, or else you may overwrite changes made by another user since you last retrieved the task.

This method returns the complete updated task record, described above.

Assign a task to yourself.
# Request curl --request PUT -u <api_key>: https://app.asana.com/api/1.0/tasks/1001 \ -d "assignee=me" # Response HTTP/1.1 200 { "data": { "assignee": { "id": 1234, "name": "Tim Bizarro" }, "id": 1001, ... } }

Deleting an existing task

DELETE /tasks/task-id

A specific, existing task can be deleted by making a DELETE request on the URL for that task.

This method returns an empty data response on success.

Delete a task.
# Request curl -u <api_key>: https://app.asana.com/api/1.0/tasks/1001 # Response HTTP/1.1 200 { "data": { } }

Querying for tasks

GET /tasks
GET /projects/project-id/tasks
GET /workspaces/workspace-id/tasks

In the future we plan to expand the power of queries to enable filtering by arbitrary fields so you can more easily select the set of tasks you want. For now, you may limit your query either to a specific project or to an assignee and workspace, or recently completed tasks. The following parameters allow you to specify your query:

assignee 1234
The ID of the assignee to filter tasks on. Only unarchived tasks in the assignee's list will be returned.
Note: If you specify an assignee, you must also specify a workspace to filter on.
project 1331
The ID of a project to get tasks from. Only unarchived tasks in the project will be returned.
workspace 14619
The ID of the workspace or organization to filter tasks on.
Note: If you specify a workspace you must also specify an assignee to filter on.
completed_since 2012-02-22T02:06:58.158Z
Only return tasks that are either incomplete, or completed since the given time.
Note: You can also specify now to represent the current time.
modified_since 2012-02-22T02:06:58.158Z
Only return tasks that have been modified since the given time.
Note: You can also specify now to represent the current time.
Note: Actions that count as modifying the task include assigning, renaming, completing, and adding stories.

Show non-archived tasks assigned to me in a workspace or organization.
# Request curl -u <api_key>: "https://app.asana.com/api/1.0/tasks?workspace=14916&assignee=me" # Response HTTP/1.1 200 { "data": [ { "id": 1248, "name": "Buy catnip" }, { "id": 24816, "name": "Reflect on role of kittens in society" }, { ... } ] }

Working with subtasks

GET /tasks/task-id/subtasks
POST /tasks
POST /tasks/parent-id/subtasks
POST /tasks/task-id/setParent

Creating a subtask is the same as a creating an normal task, but instead of specifying a workspace you must specify a parent task. Each task can only have a single parent and you can use the setParent endpoint to add or remove a parent from an existing task.

Created subtasks are added to the end of their parent's list of subtasks.

You can find all of the subtasks of a task via the tasks/:ID/subtasks endpoint.

parent 1331
The ID of the parent to add to the task, or null to remove an existing parent.

Create a subtask.
# Request curl -u <api_key>: https://app.asana.com/api/1.0/tasks/2272/subtasks \ -d "assignee=1235" \ -d "followers[0]=5678" \ -d "name=Tell Luke" \ -d "notes=He%27s going to be upset." # Response HTTP/1.1 201 { "data": { "assignee": { "id": 1235, "name": "Darth Vader" }, "assignee_status": "inbox", "completed": false, "completed_at": null, "created_at": "2012-02-22T02:06:58.158Z", "due_on": null, "followers": [ { "id": 5678, "name": "Emperor Palpatine" } ], "id": 1001, "modified_at": "2012-02-22T02:06:58.158Z", "name": "Tell Luke", "notes": "He's going to be upset.", "parent": { "id": 2272, "name": "Tell kids I am their father." }, "projects": [], "workspace": { "id": 14916, "name": "Star Wars" } } }
Show all of a task's subtasks.
# Request curl -u <api_key>: https://app.asana.com/api/1.0/tasks/7331/subtasks # Response { "data": [ { "id": 5005, "name": "Steal Underwear" }, { "id": 6709, "name": "???" }, { "id": 9812, "name": "Profit" } ] }
Set the parent for an existing task.
# Request curl -u <api_key>: https://app.asana.com/api/1.0/tasks/2272/setParent \ -d "parent=1331" # Response HTTP/1.1 200 { "data": { "id": 2272, "name": "Tell Luke", "parent": [ { "id": 1331, "name": "Tell kids I am their father" } ], ... } }

Reading task activity and comments

GET /tasks/task-id/stories

Tasks, like some other objects in the system, have a series of stories associated with them. A story can be an indicator of some action taken on a task (such as completing it), or it could be a comment left by a user.

See the section on querying for all stories on an object for more information.

Commenting on a task

POST /tasks/task-id/stories

See the section on commenting on an object for more information.

Working with projects associated with a task and reordering within a project

GET /tasks/task-id/projects
POST /tasks/task-id/addProject
POST /tasks/task-id/removeProject

Each task can be associated with zero or more projects in the system. The API allows you to query and change those associations.

You can query the list of projects associated with a task by using the projects endpoint on a task, which will return a compact representation of each of the projects on the task specified.

You can add or remove a project using the addProject or removeProject endpoints, respectively, providing the parameters below. You can also use addProject to reorder tasks that are already part of that project.

Requests to add/remove projects, if successful, will return success and an empty data block.

project 1331
The ID of the project to add or remove from the task.
insert_after 2272
The ID of the task in the same project to insert after, or "null" to insert at the beginning of the list.
insert_before 2272
The ID of the task in the same project to insert before, or "null" to insert at the end of the list.

Show list of projects on a task.
# Request curl -u <api_key>: https://app.asana.com/api/1.0/tasks/1001/projects # Response { "data": [ { "id": 1331, "name": "Things To Buy" }, { "id": 14641, "name": "Cat Stuff" } ] }
Add project to a task.
# Request curl -u <api_key>: https://app.asana.com/api/1.0/tasks/1001/addProject \ -d "project=14641" # Response { "data": { } }
Remove project from a task.
# Request curl -u <api_key>: https://app.asana.com/api/1.0/tasks/1001/removeProject \ -d "project=14641" # Response { "data": { } }

Working with tags on a task

GET /tasks/task-id/tags
POST /tasks/task-id/addTag
POST /tasks/task-id/removeTag

Each task can be associated with zero or more tags in the system. The API allows you to query and change those associations.

You can query the list of tags associated with a task by using the tags endpoint on a task, which will return a compact representation of each of the tags on the task specified.

You can add or remove a tag using the addTag or removeTag endpoints, respectively, providing the parameters below.

Requests to add/remove tags, if successful, will return success and an empty data block.

tag 1331
The ID of the tag to add or remove from the task.

Show list of tags on a task.
# Request curl -u <api_key>: https://app.asana.com/api/1.0/tasks/1001/tags # Response { "data": [ { "id": 1331, "name": "orange" }, { "id": 1771, "name": "fluffy" } ] }
Add tag to a task.
# Request curl -u <api_key>: https://app.asana.com/api/1.0/tasks/1001/addTag \ -d "tag=1771" # Response { "data": { } }
Remove tag from a task.
# Request curl -u <api_key>: https://app.asana.com/api/1.0/tasks/1001/removeTag \ -d "tag=1771" # Response { "data": { } }

Working with followers on a task

POST /tasks/task-id/addFollowers
POST /tasks/task-id/removeFollowers

Each task can be associated with zero or more followers in the system.

You can add or remove followers using the addFollowers or removeFollowers endpoints, respectively, providing the parameters below.

Requests to add/remove followers, if successful, will return the complete updated task record, described above.

followers [1235]
The IDs of the users to add or remove as followers to/from the task.

Add followers to a task.
# Request curl -u <api_key>: https://app.asana.com/api/1.0/tasks/1001/addFollowers \ -d "followers[0]=1235" # Response HTTP/1.1 200 { "data": { "followers": [ { "id": 1235, "name": "Darth Vader" } ], "id": 1001, ... } }
Remove followers from a task.
# Request curl -u <api_key>: https://app.asana.com/api/1.0/tasks/1001/removeFollowers \ -d "followers[0]=1235" # Response HTTP/1.1 200 { "data": { "followers": [], "id": 1001, ... } }

Projects

A project represents a prioritized list of tasks in Asana. It exists in a single workspace or organization and is accessible to a subset of users in that workspace or organization depending on its permissions.

Projects in organizations are shared with a single team. You cannot currently change the team of a project via the API. Non-organization workspaces do not have teams and so you should not specify the team of project in a regular workspace.

Projects, like tasks, can have rich metadata associated with them, including the following fields:

archived false
True if the project is archived, false if not. Archived projects do not show in the UI by default and may be treated differently for queries.
created_at 2012-02-22T02:06:58.147Z
Read-only. The time at which this project was created.
followers [ { id: 1123, name: "Mittens" }, ... ]
Read-only. Array of users following this project.
modified_at 2012-02-22T02:06:58.147Z
Read-only. The time at which this project was last modified.
Note: This does not currently reflect any changes in associations such as tasks or comments that may have been added or removed from the project.
name Stuff to buy
Name of the project. This is generally a short sentence fragment that fits on a line in the UI for maximum readability. However, it can be longer.
color dark-red
Color of the project. Must be either null or one of: dark-pink, dark-green, dark-blue, dark-red, dark-teal, dark-brown, dark-orange, dark-purple, dark-warm-gray, light-pink, light-green, light-blue, light-red, light-teal, light-yellow, light-orange, light-purple, light-warm-gray
notes These are things we need to purchase.
More detailed, free-form textual information associated with the project.
workspace { id: 14916, name: "My Workspace" }
Create-only. The workspace or organization this project is associated with. Once created, projects cannot be moved to a different workspace. This attribute can only be specified at creation time.
team { id: 692353, name: "organization.com Marketing" }
Create-only. The team that this project is shared with. This field only exists for projects in organizations.

Creating a new project

POST /projects
POST /workspaces/workspace-id/projects

This method creates a new project and returns its full record.

Every project is required to be created in a specific workspace or organization, and this workspace cannot be changed once set. Note that you can use the workspace parameter regardless of whether or not it is an organization.

If the workspace for your project is an organization, you must also supply a team to share the project with.

Create a new project.
# Request curl -u <api_key>: https://app.asana.com/api/1.0/projects \ -d "name=Things to Buy" \ -d "notes=These are things we want to purchase." \ -d "workspace=14916" # Response HTTP/1.1 201 { "data": { "id": 1331, "name": "Things to Buy", "notes": "These are things we want to purchase.", ... } }

Showing a single project

GET /projects/project-id

This method returns the full record for a single project.

Show a specific project.
# Request curl -u <api_key>: https://app.asana.com/api/1.0/projects/1331 # Response HTTP/1.1 200 { "data": { "id": 1331, "name": "Things to Buy", "notes": "These are things we want to purchase.", ... } }

Updating a project

PUT /projects/project-id

This method modifies the fields of a project provided in the request, then returns the full updated record.

Update project notes.
# Request curl --request PUT -u <api_key>: https://app.asana.com/api/1.0/projects/1331 \ -d "notes=These are things we NEED to purchase." # Response HTTP/1.1 200 { "data": { "id": 1331, "name": "Things to Buy", "notes": "These are things we NEED to purchase.", ... } }

Deleting a project

DELETE /projects/project-id

A specific, existing project can be deleted by making a DELETE request on the URL for that project.

This method returns an empty data response on success.

Delete a project.
# Request curl -u <api_key>: https://app.asana.com/api/1.0/projects/1331 # Response HTTP/1.1 200 { "data": { } }

Querying for tasks in a project

GET /projects/project-id/tasks

Returns the list of non-archived tasks in this project. Tasks can exist in more than one project at a time.

Get visible tasks on a project.
# Request curl -u <api_key>: https://app.asana.com/api/1.0/projects/1331/tasks # Response HTTP/1.1 200 { "data": [ { "id": 2001, "name": "Catnip" }, { "id": 2002, "name": "Kitty litter" }, ... ] }

Querying for projects

GET /projects
GET /workspaces/workspace-id/projects

This method returns the projects, described above, according to the filter criteria provided.

archived false
If provided, this parameter will filter on projects whose archived field takes on the specified value.
workspace 14916
If provided, this parameter will filter on projects which belong in the specified workspace

Show all projects in a workspace or organization.
# Request curl -u <api_key>: https://app.asana.com/api/1.0/workspaces/14916/projects # Response HTTP/1.1 200 { "data": [ { "id": 1331, "name": "Things to buy" }, { "id": 14641, "name": "Cat Stuff" }, ... ] }

Tags

A tag is a label that can be attached to any task in Asana. It exists in a single workspace or organization.

Tags have some metadata associated with them, but it is possible that we will simplify them in the future so it is not encouraged to rely too heavily on it. Unlike projects, tags do not provide any ordering on the tasks they are associated with.

Tags have the following fields:

created_at 2012-02-22T02:06:58.147Z
Read-only. The time at which this tag was created.
followers [ { id: 1123, name: "Mittens" }, ... ]
Read-only. Array of users following this tag.
name Stuff to buy
Name of the tag. This is generally a short sentence fragment that fits on a line in the UI for maximum readability. However, it can be longer.
color dark-red
Color of the tag. Must be either null or one of: dark-pink, dark-green, dark-blue, dark-red, dark-teal, dark-brown, dark-orange, dark-purple, dark-warm-gray, light-pink, light-green, light-blue, light-red, light-teal, light-yellow, light-orange, light-purple, light-warm-gray
notes These are things we need to purchase.
More detailed, free-form textual information associated with the project.
workspace { id: 14916, name: "My Workspace" }
Create-only. The workspace this tag is associated with. Once created, tag cannot be moved to a different workspace. This attribute can only be specified at creation time.

Creating a new tag

POST /tags
POST /workspaces/workspace-id/tags

This method creates a new tag and returns its full record.

Every tag is required to be created in a specific workspace or organization, and this workspace cannot be changed once set.

Create a new tag.
# Request curl -u <api_key>: https://app.asana.com/api/1.0/tags \ -d "name=fluffy" \ -d "workspace=14916" # Response HTTP/1.1 201 { "data": { "id": 1771, "name": "fluffy", ... } }

Showing a single tag

GET /tags/tag-id

This method returns the full record for a single tag.

Show a specific tag.
# Request curl -u <api_key>: https://app.asana.com/api/1.0/tags/1331 # Response HTTP/1.1 200 { "data": { "id": 1331, "name": "Things to Buy", "notes": "These are things we want to purchase.", ... } }

Updating a tag

PUT /tags/tag-id

This method modifies the fields of a tag provided in the request, then returns the full updated record.

Update tag name.
# Request curl --request PUT -u <api_key>: https://app.asana.com/api/1.0/tags/1331 \ -d "name=Things to Sell" # Response HTTP/1.1 200 { "data": { "id": 1331, "name": "Things to Sell", ... } }

Querying for tasks with a tag

GET /tags/tag-id/tasks

Returns the list of all tasks with this tag. Tasks can have more than one tag at a time.

Get all tasks with a tag.
# Request curl -u <api_key>: https://app.asana.com/api/1.0/tags/1331/tasks # Response HTTP/1.1 200 { "data": [ { "id": 2001, "name": "Catnip" }, { "id": 2002, "name": "Kitty litter" }, ... ] }

Querying for tags

GET /tags
GET /workspaces/workspace-id/tags

This method returns the tags, described above, according to the filter criteria provided.

workspace 14916
If provided, this parameter will filter on tags which belong in the specified workspace

Show all tags in a workspace.
# Request curl -u <api_key>: https://app.asana.com/api/1.0/workspaces/14916/tags # Response HTTP/1.1 200 { "data": [ { "id": 1331, "name": "Things to buy" }, { "id": 14641, "name": "Cat Stuff" }, ... ] }

Stories

A story represents an activity associated with an object in the Asana system. Stories are generated by the system whenever users take actions such as creating or assigning tasks, or moving tasks between projects. Comments are also a form of user-generated story.

Stories are a form of history in the system, and such they are read-only. Once generated, it is not possible to modify a story.

created_at 2012-02-22T02:06:58.147Z
Read-only. The time at which this story was created.
created_by { id: 1123, name: "Mittens" }
Read-only. The user who created the story.
hearted false
True if the story is hearted by the authorized user, false if not.
Note: This property only exists for stories that provide hearts.
hearts [ { id: 1245, name: "Mittens" }, ... ]
Read-only. Array of users who have hearted this story.
Note: This property only exists for stories that provide hearts.
num_hearts 3
Read-only. The number of users who have hearted this story.
Note: This property only exists for stories that provide hearts.
text marked today
Create-only. Human-readable text for the story or comment. This will not include the name of the creator.
Note: This is not guaranteed to be stable for a given type of story. For example, text for a reassignment may not always say "assigned to ...". The API currently does not provide a structured way of inspecting the meaning of a story.
target { id: 1234, name: "Buy catnip" }
Read-only. The object this story is associated with. Currently may only be a task.
source web
Read-only. The component of the Asana product the user used to trigger the story. Valid values are:
web Via the Asana web app.
email Via email.
mobile Via the Asana mobile app.
api Via the Asana API.
unknown Unknown or unrecorded.
type comment
Read-only. The type of story this is. Valid values are:
comment A comment from a user. The text will be the message portion of the comment.
system A system-generated story based on a user action. The text will be a description of the action.

Querying for all stories on an object

GET /tasks/task-id/stories

Returns the list of stories associated with the object, sorted chronologically by creation time (oldest first). As usual with queries, stories are returned in compact form. However, the compact form for stories contains more information by default than just the ID. There is presently no way to get a filtered set of stories.

Show all stories on a task.
# Request curl -u <api_key>: https://app.asana.com/api/1.0/tasks/1001/stories # Response { "data": [ { "created_at": "2011-12-21T23:23:01.259Z", "created_by": { "id": 5678, "name": "Greg Sanchez" }, "id": 2001, "text": "added to Things To Buy", "type": "system" }, { "created_at": "2012-01-02T21:32:40.112Z", "created_by": { "id": 1234, "name": "Tim Bizarro" }, "id": 2002, "text": "Again? Wow, we really go through this stuff fast.", "type": "comment" } ] }

Showing a single story

GET /stories/story-id

This method returns the full record for a single story.

Show a specific story.
# Request curl -u <api_key>: https://app.asana.com/api/1.0/stories/2001 # Response HTTP/1.1 200 { "data": { "created_at": "2012-02-22T02:06:58.147Z", "created_by": { "id": 1123, "name": "Mittens" }, "id": 2001, "source": "web", "target": { "id": 1234, "name": "Buy catnip" }, "text": "Yes, please!", "type": "comment" } }

Commenting on an object

POST /tasks/task-id/stories

Adds a comment to an object. The comment will be authored by the authorized user, and timestamped when the server receives the request. You can provide the following parameters when posting the comment:

text Hello!
The body of the comment to add.

Comment on a task.
# Request curl -u <api_key>: https://app.asana.com/api/1.0/tasks/1001/stories \ -d "text=This is a very nice comment." # Response { "data": { "created_at": "2011-12-21T23:23:01.259Z", "created_by": { "id": 5678, "name": "Greg Sanchez" }, "id": 2001, "source": "api", "target": { "id": 1001, "name": "Buy catnip" }, "text": "This is a very nice comment.", "type": "comment" } }

Workspaces and Organizations

A workspace is the most basic organizational unit in Asana. All projects and tasks have an associated workspace.

An organization is a special kind of workspace that represents a company. In an organization, you can group your projects into teams. You can read more about how organizations work on the Asana Guide. To tell if your workspace is an organization or not, check its is_organization property.

Over time, we intend to migrate most workspaces into organizations and to release more organization-specific functionality. We may eventually deprecate using workspace-based APIs for organizations. Currently, and until after some reasonable grace period following any further announcements, you can still reference organizations in any workspace parameter.

Workspaces expose the following fields:

name My Favorite Workspace
Name of the workspace.
is_organization false
Whether this workspace is an organization

Showing available workspaces

GET /workspaces

This method returns the workspace records, described above.

Show all available workspaces.
# Request curl -u <api_key>: https://app.asana.com/api/1.0/workspaces # Response { "data": [ { "id": 1337, "name": "My Favorite Workspace" }, ... ] }

Updating an existing workspace

PUT /workspaces/workspace-id

A specific, existing workspace can be updated by making a PUT request on the URL for that workspace. Only the fields provided in the data block will be updated; any unspecified fields will remain unchanged.

Currently the only field that can be modified for a workspace is its name.

This method returns the complete updated workspace record, described above.

Rename a workspace.
# Request curl --request PUT -u <api_key>: https://app.asana.com/api/1.0/workspaces/1337 \ -d "name=Everyone%27s Favorite Workspace" # Response { "data": { "id": 1337, "name": "Everyone's Favorite Workspace" } }

Teams

A team is used to group related projects and people together within an organization. Each project in an organization is associated with a team.

name Engineering
Name of the team

Show all teams you're a member of in an organization

GET /organizations/organization-id/teams

This method returns team records that match the given organization.

Show all teams in the the MLB organization.
# Request curl -u <api_key>: https://app.asana.com/api/1.0/organizations/13523 # Response { "data": [ { "id": 5832, "name": "Atlanta Braves" }, { "id": 15923, "name": "New York Yankees" }, ... ] }

Attachments

An attachment object represents any file attached to a task in Asana.

created_at 2012-02-22T02:06:58.147Z
Read-only. The time at which this attachment was uploaded.
download_url https://www.dropbox.com/s/123/Screenshot.png?dl=1
Read-only. The URL containing the content of the attachment.
Note: May be null if the attachment is hosted by box. If present, this URL may only be valid for 1 hour from the time of retrieval. You should avoid persisting this URL somewhere and just refresh it on demand to ensure you do not keep stale URLs.
host dropbox
Read-only. The service hosting the attachment. Valid values are asana, dropbox, gdrive and box.
name Screenshot.png
Read-only. The name of the file.
parent { id: 1123, name: "Fix this bug" }
Read-only. The task this attachment is attached to.
view_url https://www.dropbox.com/s/123/Screenshot.png
Read-only. The URL where the attachment can be viewed, which may be friendlier to users in a browser than just directing them to a raw file.

Showing a single attachment

GET /attachments/attachment-id

This method returns the full record for a single attachment.

Show a single attachment.
# Request curl -u <api_key>: https://app.asana.com/api/1.0/attachments/5678 # Response HTTP/1.1 200 { "data": { "created_at": "", "download_url": "https://www.dropbox.com/s/1234567890abcdef/Screenshot.png?dl=1", "host": "dropbox", "id": 5678, "name": "Screenshot.png", "parent": { "id": 1337, "name": "My Task" }, "view_url": "https://www.dropbox.com/s/1234567890abcdef/Screenshot.png" } }

Showing all attachments on a task

GET /tasks/task-id/attachments

This method returns the compact records for all attachments on a task.

Get filenames and IDs of all attachments on a task.
# Request curl -u <api_key>: https://app.asana.com/api/1.0/tasks/1234/attachments # Response HTTP/1.1 200 { "data": [ { "id": 5678, "name": "Background.png" }, { "id": 9012, "name": "New Design Draft.pdf" }, ... ] }

Uploading an attachment to a task

POST /tasks/task-id/attachments

This method uploads an attachment to a task.

file @file.txt
The file (<=10MB) you want to upload. Needs to be an actual file, not a stream of bytes.
Note: If you use curl, make sure add an @ before the file path, and use the --form option instead of the -u option.
Note: (PDF files only) To upload a pdf file through curl, force the content-type to be pdf by appending the content type to the file path: --form "file=@file.pdf;type=application/pdf".

Upload an attachment.
# Request curl -u <api_key>: --form "file=@file.txt" https://app.asana.com/api/1.0/tasks/1337/attachments # Response HTTP/1.1 200 { "data": { "id": 5678, "name": "file.txt" } }

Typeahead

The typeahead search API allows you to query for objects from a single workspace and retrieves read only information that can be used for creating auto-completion/typeahead search. This feature is meant to provide results quickly, so do not rely on this API to provide extremely accurate search results. The results sets are limited and you won’t be able to paginate them via the API.

type project
Read-only. The type of object to look up. You can choose from one of the following: project, user, task, and tag. Note that unlike other endpoints, the types listed here are in singular form. Using multiple types is not yet supported.
query Red
Read-only. The value to look up. This is a string that will be used to search for relevant objects. If an empty string is passed in, the API will currently return an empty set.
count 20
Read-only. The number of results to return. The default is 20 if this parameter is omitted, with a minimum of 1 and a maximum of 100. If there are fewer results found than requested, all will be returned.

Search results via typeahead query

GET /workspace/workspace-id/typeahead

This method returns typeahead search results.

Show all users whose names contain "Greg"
# Request curl -u <api_key>: "https://app.asana.com/api/1.0/workspaces/1337/typeahead?type=user&query=Greg" # Response { "data": [ { "id": 999, "name": "Greg Sanchez", ... }, ... ] }