Adobe Workfront Planning API basics

IMPORTANT
The information in this article refers to Adobe Workfront Planning, an additional capability from Adobe Workfront.
For a list of requirements to access Workfront Planning, see Adobe Workfront Planning access overview.
For general information about Workfront Planning, see Get started with Adobe Workfront Planning.

The goal of the Adobe Workfront Planning API is to simplify building integrations with Planning by introducing a RESTful architecture that operates over HTTP. This document assumes you are familiar with REST and JSON responses.

For complete endpoint reference, request/ response schemas, and version-specific details, see the Workfront Planning API developer documentation.

Authentication

The Workfront Planning API uses OAuth 2.0 for authentication. Credentials are set up via the Adobe Developer Console.

We support the following two flows depending on your integration type:

  • Server-to-server authentication (JWT): For automated integrations and backend services with no user interaction. Uses the OAuth Server-to-Server credential (client credentials grant — your application authenticates directly using its client ID and secret to obtain an access token, with no user login or consent step).

    For information, see Server to Server authentication.

  • User authentication (Authorization Code flow): for integrations acting on behalf of a specific user. Uses the OAuth Web App or Single Page App credential (authorization code grant — the user logs in and consents, after which your application receives an authorization code it exchanges for an access token).

    For information, see User Authentication.

To get started, create a project in the Adobe Developer Console and add the Workfront Planning API to obtain your credentials.

To set up credentials, create an OAuth2 application in Workfront.

For information, see Create OAuth2 applications for Workfront integrations.

NOTE
The /login endpoint and API key authentication are not supported for Workfront Planning. Do not use sessionID or apiKey parameters.

API versioning

The Planning API is versioned via the URL path.

The following are current supported versions:

Version
Release date
Version 1
July 2024
Version 2
May 2026
NOTE
The Workfront Planning connector for Workfront Fusion has not been updated to API Version 2 and it will continue to use Version 1 until further notice.

For more information about the current supported versions, see the article Workfront Planning API developer documentation.

We recommend explicitly targeting a version in all integrations:

https://{customer-domain}/maestro/api/v2/...

When a new major version is released, the previous version will continue to be available until a deprecation date is communicated.

Follow the Workfront release notes to stay informed of API changes.

URL structure and operations

Objects are manipulated by sending an HTTP request to their unique URI. The operation is specified by the HTTP method.

Method
Operation
GET
Retrieve a single object by ID, or search/list objects
POST
Create a new object
PUT
Replace an existing object (full update)
PATCH
Partially update an existing object (only provided fields are modified)
DELETE
Delete an object
NOTE
Version1 note: PATCH is not supported in Version 1. Use PUT for all updates.

For full endpoint paths and request/response examples, see the API reference at developer.adobe.com/wf-planning.

HTTP status codes

The Planning API returns standard HTTP status codes:

Code
Meaning
200 OK
Successful GET, PUT, or PATCH
201 Created
Successful POST (resource created)
204 No Content
Successful DELETE
207 Multi-Status
Bulk operation completed with mixed results, where some items succeeded and some failed. Check individual item responses for details.
400 Bad Request
Invalid request — see error response for details
401 Unauthorized
Missing or invalid authentication token
403 Forbidden
Authenticated but insufficient permissions
404 Not Found
Resource does not exist
409 Conflict
Write conflict, the resource was modified by another request. Retry with the latest version.
429 Too Many Requests
Rate limit exceeded
NOTE
Version 1 note: Version 1 returns 200 OK for all successful operations, including POST and DELETE.

Error handling

The Planning API returns errors in a consistent format. Each error response includes a human-readable message, a machine-readable error code, and a request ID for support escalation.

Example error response:

json
{
  "title": "Validation failed",
  "status": 400,
  "detail": "Request validation failed. See 'errors' for details.",
  "errorCode": "VALIDATION_FAILED",
  "requestId": "req-123",
  "errors": [
    { "field": "name", "message": "must not be blank" }
  ]
}

Use errorCode (not status) to drive programmatic error handling. It provides the most specific classification of the failure.

NOTE
Version 1 note: Version 1 error responses use a numeric type field (e.g. 40001) instead of a string errorCode, and wrap detail in a report object rather than a top-level detail field.

Filtering records

Use the filter parameter in record search requests to return only records matching specific criteria. For POST requests, filter is a JSON property in the request body. For GET requests, filter is a query parameter containing a JSON-encoded filter group. Filters use a typed composite structure with explicit logical operators.

json
{
  "filter": {
    "operator": "AND",
    "conditions": [
      { "fieldId": "<fieldId>", "condition": "IS", "value": "Active" },
      { "fieldId": "<fieldId>", "condition": "CONTAINS", "value": "marketing" }
    ]
  }
}

Filters can be nested using AND / OR operators to build compound conditions:

json
{
  "filter": {
    "operator": "OR",
    "conditions": [
      {
        "operator": "AND",
        "conditions": [
          { "fieldId": "<fieldId>", "condition": "BETWEEN", "value": ["2024-03-31T20:00:00.000Z", "2024-04-01T20:00:00.000Z"] },
          { "fieldId": "<fieldId>", "condition": "IS", "value": "active" }
        ]
      },
      {
        "operator": "AND",
        "conditions": [
          { "fieldId": "<fieldId>", "condition": "IS_BETWEEN", "value": ["2024-04-15T00:00:00.000Z", "2024-04-16T00:00:00.000Z"] },
          { "fieldId": "<fieldId>", "condition": "IS", "value": "planned" }
        ]
      }
    ]
  }
}
NOTE
Version 1 note: Version 1 uses Mongo-style untyped operators in a filters object. Operators are prefixed with $ (e.g. $and, $or, $is, $contains, $isBetween). Pagination parameters (offset, limit) and recordTypeId are passed in the request body rather than as URL path and query parameters.

Field types and search modifiers

You can use modifiers and filters with fields to control what data will be returned in results.

For examples, see the Workfront Planning API developer documentation.

Using search modifiers

Workfront Planning supports the following search modifiers:

Modifier
Example
Description
Possible values
CONTAINS
{"fieldId":"<id>","condition":"CONTAINS","value":"product"}
Returns records whose field value contains the filter
"New Product Launch"
DOES_NOT_CONTAIN
{"fieldId":"<id>","condition":"DOES_NOT_CONTAIN","value":"product"}
Returns records where the field value does not contain the filter
"New Launch"
IS
{"fieldId":"<id>","condition":"IS","value":"new product launch"}
Returns records whose field value exactly matches the filter
"New Product Launch"
IS_NOT
{"fieldId":"<id>","condition":"IS_NOT","value":"product"}
Returns records whose field value does not exactly match the filter
"New Product Launch"
IS_EMPTY
{"fieldId":"<id>","condition":"IS_EMPTY"}
Returns records whose field value is empty
"" or null
IS_NOT_EMPTY
{"fieldId":"<id>","condition":"IS_NOT_EMPTY"}
Returns records whose field value is not empty
"New Product Launch"
GREATER_THAN
{"fieldId":"<id>","condition":"GREATER_THAN","value":"10"}
Returns records whose field value is greater than the filter
"11"
GREATER_THAN_OR_EQUAL
{"fieldId":"<id>","condition":"GREATER_THAN_OR_EQUAL","value":"10"}
Returns records whose field value is greater than or equal to the filter
"10", "11"
LESS_THAN
{"fieldId":"<id>","condition":"LESS_THAN","value":"10"}
Returns records whose field value is less than the filter
"9"
LESS_THAN_OR_EQUAL
{"fieldId":"<id>","condition":"LESS_THAN_OR_EQUAL","value":"10"}
Returns records whose field value is less than or equal to the filter
"9", "10"
IS_BETWEEN
{"fieldId":"<id>","condition":"IS_BETWEEN","value":["2024-01-01","2024-12-31"]}
Returns records whose field value falls between the two filter values
["2024-03-01","2024-06-30"]
IS_NOT_BETWEEN
{"fieldId":"<id>","condition":"IS_NOT_BETWEEN","value":["2024-01-01","2024-12-31"]}
Returns records whose field value does not fall between the two filter values
["2023-01-01","2025-06-30"]
IS_AFTER
{"fieldId":"<id>","condition":"IS_AFTER","value":"2024-01-01"}
Returns records whose date field value is after the filter
"2024-06-01"
IS_BEFORE
{"fieldId":"<id>","condition":"IS_BEFORE","value":"2024-12-31"}
Returns records whose date field value is before the filter
"2024-06-01"
IS_ANY_OF
{"fieldId":"<id>","condition":"IS_ANY_OF","value":["Active","Planned"]}
Returns records whose field value matches any value in the filter list
["Active","Planned","Complete"]
IS_NONE_OF
{"fieldId":"<id>","condition":"IS_NONE_OF","value":["Active","Planned"]}
Returns records whose field value matches none of the values in the filter list
["Active","Planned"]
HAS_ANY_OF
{"fieldId":"<id>","condition":"HAS_ANY_OF","value":["Tag1","Tag2"]}
Returns records whose multi-value field contains any of the filter values
["Tag1","Tag2"]
HAS_ALL_OF
{"fieldId":"<id>","condition":"HAS_ALL_OF","value":["Tag1","Tag2"]}
Returns records whose multi-value field contains all of the filter values
["Tag1","Tag2"]
IS_EXACTLY
{"fieldId":"<id>","condition":"IS_EXACTLY","value":["Tag1"]}
Returns records whose multi-value field contains exactly the filter values and no others
["Tag1"]
HAS_NONE_OF
{"fieldId":"<id>","condition":"HAS_NONE_OF","value":["Tag1"]}
Returns records whose multi-value field contains none of the filter values
["Tag1"]
NOTE
Version 1 note: V1 modifier names use $-prefixed camelCase (e.g. $contains, $isNot, $isEmpty, $greaterThan, $greaterThanOrEqual, $lessThan, $lessThanOrEqual, $isBetween, $isNotBetween, $isAnyOf, $hasAllOf). The behavior of each modifier is the same.

Supported filter conditions by field type

Field Type
Supported Conditions
text, long-text
CONTAINS, DOES_NOT_CONTAIN, IS, IS_NOT, IS_EMPTY, IS_NOT_EMPTY
number, percentage, currency
IS, IS_NOT, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, IS_EMPTY, IS_NOT_EMPTY
date
IS, IS_NOT, IS_AFTER, IS_BEFORE, IS_BETWEEN, IS_NOT_BETWEEN, IS_EMPTY, IS_NOT_EMPTY
single-select
IS, IS_NOT, IS_ANY_OF, IS_NONE_OF, IS_EMPTY, IS_NOT_EMPTY
multi-select, user
HAS_ANY_OF, HAS_ALL_OF, IS_EXACTLY, HAS_NONE_OF, IS_EMPTY, IS_NOT_EMPTY
boolean
IS
formula
CONTAINS, DOES_NOT_CONTAIN, IS, IS_NOT, IS_EMPTY, IS_NOT_EMPTY
created-by
IS, IS_NOT, IS_ANY_OF, IS_NONE_OF
updated-by
IS, IS_NOT, IS_ANY_OF, IS_NONE_OF, IS_EMPTY, IS_NOT_EMPTY
created-at
IS, IS_NOT, IS_AFTER, IS_BEFORE, IS_BETWEEN, IS_NOT_BETWEEN
updated-at
IS, IS_NOT, IS_AFTER, IS_BEFORE, IS_BETWEEN, IS_NOT_BETWEEN, IS_EMPTY, IS_NOT_EMPTY
reference
HAS_ANY_OF, HAS_ALL_OF, IS_EXACTLY, HAS_NONE_OF, IS_EMPTY, IS_NOT_EMPTY
lookup
Depends on the linked field type
NOTE
Version 1 note: Version 1 uses $-prefixed operator names (e.g. $contains, $greaterThan, $isAnyOf, $hasAllOf). The set of supported conditions per field type is the same.

Filtering by People fields

People field filters (user, created-by, updated-by, approved-by) accept both Adobe IMS user IDs and Workfront user IDs. A plain string value is interpreted as an Adobe IMS user ID.

To set the identifier type to check the Workfront user ID, you need to explicitly pass id and idType parameters. Supported values for idType are “WF” for Workfront user IDs, and “IMS” for Adobe IMS user IDs.

{
  "filter": {
   "operator": "AND",
    "conditions": [
      {
        "fieldId": "<userFieldId>",
        "condition": "HAS_ANY_OF",
        "value": [
          { "id": "63e3b13000078c1795146248182d15dc", "idType": "WF" }
        ]
      }
    ]
  }
}
NOTE
Version 1 note: V1 only supports filtering by users’ IMS ID.

Filtering External Reference Fields by External ID

External reference fields link records to objects in other Adobe systems (such as Workfront projects or AEM Assets). Internally, Planning assigns Planning record IDs to these objects. To filter such fields directly by their original object ID, add "matchExternalId": true to a filter condition.

This flag is only valid for reference fields where referenceOptions.isExternal is true; it is ignored for non-external reference fields. If a single string value cannot be resolved, the request fails with 400 Bad Request. If a list value is supplied, unresolved entries pass through unchanged and simply do not match.

{
  "filter": {
    "operator": "AND",
    "conditions": [
      {
        "fieldId": "<externalReferenceFieldId>",
        "condition": "IS_ANY_OF",
        "value": [
          "5f6a4f6e00000123456789abcdef0123",
          "/content/dam/wknd/en/adventures/bali-surf-camp"
        ],
        "matchExternalId": true
      }
    ]
  }
}
NOTE
Version 1 note: V1 does not support filtering by external object IDs.

External connection fields

Planning record types can host external reference fields that link records to objects in other Adobe systems instead of other Planning record types.

To create an external reference field via the API, set referenceOptions.recordTypeId on a new REFERENCE field to the ID of the desired external record type. The server automatically derives referenceOptions.isExternal=true and the connection metadata (connectionName, objectName) from the target record type.

Supported external object types include Workfront objects (projects, tasks, programs, portfolios, companies, groups, teams, users) and AEM Assets (assets, content fragments).

NOTE
Version 1 note: V1 does not support creating external connection fields.

Sorting

Sort results by any field by including a sort array in your request:

json
{
  "sort": [
    { "fieldId": "F6527ecb25df57c441d92b9fc", "direction": "asc" },
    { "fieldId": "F658afcbd4a0273c67c346fd5", "direction": "desc" }
  ]
}

Multiple sort fields are evaluated in order. Always apply a sort when paginating to ensure consistent ordering across pages.

To group results, include a group array alongside sort:

{
  "sort": [{ "fieldId": "F001", "direction": "asc" }],
  "group": [{ "fieldId": "F002", "direction": "asc" }]
}
NOTE
Version 1 note: V1 uses sorting (not sort), groupingFieldIds (array of field IDs, not group objects), and the now-deprecated rowOrderViewId to apply an existing view’s row order. None of these V1 parameters are supported in Version

Field projection

To limit which fields are returned in a response, use the fieldIds or fieldAliases query parameters with a comma-separated list. This reduces response payload size and is recommended for high-volume or latency-sensitive integrations.

NOTE
Version 1 note: Version 1 uses ?attributes= for projection (e.g. ?attributes=data,createdBy) rather than ?fieldIds= or ?fieldAliases=.

Pagination

The Planning API supports paginated responses to manage large datasets.

  • Cursor-based pagination is used for workspaces, record types, fields, and views. Pass a cursor value from the previous response to retrieve the next page. Cursor-based responses include a hasMore flag to indicate if there are more pages or not.
  • Page-based pagination is used for record search. Use page and size as query parameters. Always apply a sort when paginating to ensure consistent ordering across pages. Note that pagination is zero-based, so in order to retrieve the results of the second page, use “page=1” as the parameter.

For example, use the following request to retrieve the second page of 500 records from a record search:

POST /v2/record-types/{recordTypeId}/records/search?page=1&size=500
{
  "sort": [{ "fieldId": "F6527ecb25df57c441d92b9fc", "direction": "asc" }],
  "filter": { "operator": "AND", "conditions": [
    { "fieldId": "<fieldId>", "condition": "IS", "value": "active" }
  ] }
}

All paginated responses include a structured envelope indicating whether more results are available. Always apply a sort when paginating to ensure consistent ordering across pages.

NOTE
Version 1 note: V1 uses offset and limit passed in the request body (default 500, max 2,000). To retrieve records 2001–4000, set “offset”: “2000”, “limit”: “2000” in the request body. The response returns a flat records array with a totalCount field.

Bulk operations

The Planning API supports bulk create, update, patch, and delete of records in a single request. Refer to the API reference at developer.adobe.com/wf-planning for endpoint paths, request formats, and per-operation record limits.

NOTE
Version 1 note: Bulk operations are not available in Version 1.

Permissions

Permissions to entities are managed through a dedicated Permissions API, separate from the resource endpoints themselves. This allows you to read current permissions, manage the sharing list, and handle access requests independently of data operations. For more information, see the “API references” section in the article Workfront Planning API.

NOTE
Version 1 note: Version 1 does not expose a public Permissions API. Permission level is embedded directly in resource response DTOs.

Using the Planning API with Workfront custom forms

You can call the Planning API from an External lookup field in a Workfront custom form to surface Planning data directly within Workfront objects. For more information, see Examples of the External lookup field in a custom form.

For more API-related documentation, also see the following articles:

recommendation-more-help
workfront-help-quicksilver