Summary
We’re extending custom types beyond custom task types to also support custom projects and portfolios. With this release, you can:
-
Look up custom types across an entire workspace, not just within a single project
-
Identify Asana-created custom types via the new
asana_created_type_identifierfield (similar to the existingasana_created_fieldproperty on custom fields) -
Filter
GET /tasks,GET /projects, andGET /portfoliosdirectly bycustom_type -
Read
resource_subtypeandcustom_typeon projects and portfolios, matching the pattern already used for tasks -
Set a custom type when creating or updating projects and portfolios
Asana’s own built-in object types are represented using this same custom type framework. To avoid silently changing what your existing bulk queries return, we’re introducing a new opt-in flag, include_asana_created_custom_types, that controls whether Asana-created custom-typed objects are included in GET /tasks, GET /projects, and GET /portfolios responses when no explicit custom_type filter is provided.
Who is affected
-
If you call
GET /tasks,GET /projects, orGET /portfolioswithout acustom_typefilter and assume a fixed, closed set of objects orresource_subtypevalues comes back: this is a breaking change for you. Once Asana-created custom-typed objects begin appearing in these responses (after the default flips, see Timeline), clients that don’t handle unfamiliarresource_subtype/custom_typevalues could break. -
If you call
GET /custom_typestoday: theprojectparameter is no longer required on its own. Going forward, exactly one ofprojectorworkspacemust be provided. Existing requests that passprojectcontinue to work unchanged. -
If you read projects or portfolios: these objects will now include
resource_subtypeandcustom_typefields. This is additive and non-breaking — but if your integration validates response shapes strictly, be aware of the new fields. -
If you fetch objects by GID (e.g.,
GET /tasks/{task_gid}): no change. Requests against specific objects are unaffected by the new change header.
All changes other than the bulk-query behavior (new fields, the workspace parameter, the custom_type filters, write support) are additive and non-breaking on their own.
Timeline
| Phase | Target date | Description | |
|---|---|---|---|
| General availability (opt-in) | August 18, 2026 | New endpoints, fields, and filters are live. include_asana_created_custom_types defaults to off — existing bulk-query behavior is unchanged unless you opt in with Asana-Enable. |
|
| Opt-out (activation) | January 13, 2027 | The default flips to on: Asana-created custom-typed objects appear in bulk queries by default. Send Asana-Disable: include_asana_created_custom_types to temporarily restore the previous behavior. We’ll confirm the exact date and announce it in this thread ahead of time. |
|
| End of deprecation | TBD | include_asana_created_custom_types is permanently enabled and the Asana-Disable header is no longer accepted. |
Response headers
During the deprecation period, affected API responses will include an Asana-Change header:
Asana-Change: name=include_asana_created_custom_types;info=https://forum.asana.com/t/upcoming-enhanced-custom-type-support-for-projects-and-portfolios-plus-new-custom-type-filtering/1153530;affected=true
You can control behavior per-request with these headers:
-
Asana-Enable:include_asana_created_custom_types— opt in to the new behavior before the default flips -
Asana-Disable:include_asana_created_custom_types— temporarily restore the previous behavior after the default flips
For more details on how deprecation headers work, see Deprecations.
What’s changing
GET /custom_types — workspace-wide lookups
Previously, you could only list custom types for a single project (project was required). Now, exactly one of project or workspace must be provided:
GET /custom_types?workspace={workspace_gid}
{
"data": [
{
"gid": "1201234567890111",
"resource_type": "custom_type",
"name": "Release",
"asana_created_type_identifier": null
}
]
}
New response fields on custom types:
| Field | Type | Description | |
|---|---|---|---|
asana_created_type_identifier |
string (enum) |
Conditional. A unique identifier associating this custom type with an Asana-created type definition. null for custom types you create yourself. |
resource_subtype and custom_type on projects and portfolios
Projects and portfolios now include:
| Field | Type | Description | |
|---|---|---|---|
resource_subtype |
string (enum): default_project/default_portfolio, custom |
The subtype of this resource. Different subtypes share many of the same fields and behavior, but may render differently in Asana or represent resources with different semantic meaning. | |
custom_type |
object (CustomTypeCompact) |
Reference to the object’s custom type. Not returned if the project/portfolio doesn’t have a custom type. |
OAuth scopes: reading custom_type on projects and portfolios requires the custom_types:read scope. Task-level custom type fields continue to accept the existing task_custom_types:read scope (and also accept custom_types:read). Personal access tokens are unaffected.
These fields appear on project and portfolio responses across the API, including GET /projects, GET /portfolios, GET /teams/{team_gid}/projects, GET /workspaces/{workspace_gid}/projects, GET /workspaces/{workspace_gid}/projects/search, GET /tasks/{task_gid}/projects, and GET /goals/{goal_gid}/supportingWork.
You can also now set custom_type and resource_subtype when creating or updating a project or portfolio (e.g., POST /projects, PUT /projects/{project_gid}, POST /portfolios, PUT /portfolios/{portfolio_gid}). Note that custom_type can only be set when the object’s resource_subtype is custom. Some Asana-created custom types cannot be set via the API and attempting to, returns an error explaining why. Also task custom types can only be assigned within projects that have that type installed. The set returned by GET /custom_types is therefore a superset of what any particular object can be assigned.
Filtering by custom_type
GET /tasks, GET /projects, and GET /portfolios gain an optional custom_type query parameter:
-
Provide a custom type GID to return only objects of that custom type. Only the GID is supported (not the name). You can find a custom type’s GID via
GET /custom_types, or by looking up an object you already know to be the correct type. -
Provide an empty string to return only objects with no custom type assigned. For tasks, this currently includes milestones and approvals, as they’re handled separately from the custom type framework.
-
Omit the parameter to return all objects regardless of custom type (subject to the
include_asana_created_custom_typesbehavior described below).
GET /projects?custom_type=1201234567890111
{
"data": [
{
"gid": "1201234567890222",
"name": "Q3 Release",
"resource_subtype": "custom",
"custom_type": {
"gid": "1201234567890111",
"name": "Release"
}
}
]
}
Note: if you explicitly filter by a custom_type GID, matching objects are always returned — including Asana-created custom-typed objects — regardless of the include_asana_created_custom_types state. The change header only affects unfiltered bulk queries.
Opting in to see Asana-created custom-typed objects in bulk queries
GET /projects
Asana-Enable: include_asana_created_custom_types
{
"data": [
{
"gid": "1201234567890222",
"name": "Q3 Release",
"resource_subtype": "default_project"
},
{
"gid": "1201234567890333",
"name": "My Release Tracker",
"resource_subtype": "custom",
"custom_type": { "gid": "1201234567890111", "name": "Release" }
}
]
}
Migration steps
-
Audit how your integration handles
resource_subtypeon tasks, projects, and portfolios. If you expect only Asana native subtypes (default_task/milestone/approval), make sure to properly handle custom types going forward. -
Test the new behavior during the opt-in period by sending
Asana-Enable: include_asana_created_custom_typeson your bulk queries. -
When the default flips (January 13, 2027), either take no action if your integration is ready, or send
Asana-Disable: include_asana_created_custom_typesto temporarily restore the previous behavior while you finish migrating. -
If you need to identify or exclude Asana-created types specifically, use the
asana_created_type_identifierfield on custom types (it’snullfor user-created custom types).
Why we’re making this change
Custom types are becoming a core part of how objects are modeled in Asana, including object types that Asana itself creates. Exposing these objects through existing bulk endpoints without warning would be a breaking change for integrations that assume a closed set of object subtypes. The include_asana_created_custom_types change gives you a testing window and an escape hatch while you update your integration, and gets everyone to a consistent end state where these objects are fundamentally equivalent to any other object in the API.
Resources
Questions and feedback
If you have questions about migrating, or feedback on the custom type model for projects and portfolios, reply in this thread.