Asana

Tasks and projects in your client's Asana workspaces.

Website
asana.com
Connects by
Signing in with Asana
Category
Projects and tasks
Services
1
Tools
250
ServiceKey
Asanaasana

Connecting

Your client presses Connect, signs in to Asana, and allows access.

Check they're connected
curl https://api.operate.as/v1/me/clients \  -H "Authorization: Bearer $OPERATE_AS_API_KEY"
Response
[  {    "id": "6f1c2a7e-...",    "name": "Miller Dental",    "services": [      "asana"    ]  }]

Good to know

Whatever your client's user can reach

The connection reaches what your client's Asana user can reach, in each workspace and organization they belong to.

Find the workspace first

Most Asana calls need a workspace or project ID. List their workspaces first with GET workspaces.

Bodies are wrapped in data

Asana wraps request and response bodies in data, so a task you create goes in { "data": { … } }, and the answer comes back the same way.

Permissions

What the client readsPermission it asks for
See, add and change tasks and projects in your workspacesChosen on the provider's screen

Tools

Install Asana's typed package for your language:

pip install operate-as-asana
Run asana.add_custom_field_setting_for_goal
curl -X POST https://api.operate.as/v1/actions/asana.add_custom_field_setting_for_goal \  -H "Authorization: Bearer $OPERATE_AS_API_KEY" \  -H "Content-Type: application/json" \  -d '{    "clientId": "6f1c2a7e-...",    "input": {      "goal_gid": "<goal_gid>"    }  }'

Shows the required inputs. Every input, with its JSON Schema: GET /v1/actions/asana.add_custom_field_setting_for_goal

Response
{  "status": 200,  "data": {    "…": "the service's own response"  },  "encoding": "json"}

Pass-through

Paths continue from https://app.asana.com/api/1.0.

See Pass-through requests for the full request and response format.

Call any endpoint
GET /v1/clients/{clientId}/asana/workspaces
POST /v1/clients/{clientId}/asana/tasks
POST /v1/clients/{clientId}/asana/tasks
Authorization: Bearer oa_...
Content-Type: application/json

{ "data": { "name": "Send monthly report", "projects": ["{projectId}"] } }

When access ends

How long access lastsAn hour at a time. Operate As renews it before it runs out and checks every connection daily.
RenewalThe renewal key keeps working for as long as your client keeps the app authorized.
What ends itYour client removes the app in their Asana settings.
When it's removedWe cancel the access with Asana too.

See Keeping access alive and Removing access.

Calls answer
HTTP/1.1 409 ConflictContent-Type: application/json{  "detail": "Miller Dental's Asana access ended. Send them their link to reconnect."}
Your webhook receives
{  "id": "evt_3f9a1c…",  "type": "connection.expired",  "createdAt": "2026-10-16T08:00:00+00:00",  "data": {    "clientId": "6f1c2a7e-...",    "clientName": "Miller Dental",    "provider": "asana",    "services": [      "asana"    ],    "reconnectUrl": "https://…"  }}