Asana Projects and Tasks for Attio
Bring Asana project and task context into Attio without asking your client team to copy delivery status from one tool to the other. This custom app pattern keeps Asana as the delivery system while giving sales, account, and client-service teams the project context they need inside Attio. Projects, tasks, Sections, selected custom fields, and optional People links are scoped before setup, then kept current through Asana webhooks plus API-backed resync and backfill paths.
Who this is for
This build is for teams that run delivery work in Asana and manage clients in Attio. It fits when the delivery team owns project and task updates in Asana, while the client-facing team needs project status, task context, sales follow-up, and client contacts in Attio.
It is also a fit when Asana structure needs translation before it belongs in a CRM. Asana uses Workspace or Organization, Team, Project, Section, and Task as the practical content model. In Attio, we map only the Projects, Sections, Tasks, and custom fields that have a clear client or reporting use.
How the sync works
The sync has three paths: live webhook intake for new and changed work, Attio writes shaped around Asana gid values, and optional People linking plus backfill for records that need more than live events.
Webhook flow
Asana webhooks are established with POST /webhooks against a specific resource GID and target URL. They are resource-scoped, not workspace-scoped by default. Workspace, Team, Portfolio, and Goal resources can be watched with filters, but those higher-level webhooks do not receive task, subtask, or story events.
For project coverage across a Team or Workspace, the app can use higher-level filters for resource_type=project with action=added and action=changed. For task coverage, the app subscribes at the in-scope Project or lower resource level so task added and changed actions propagate to the receiver.
Each webhook POST contains an events array. Each event includes a resource object with the resource gid and resource_type, plus an event-level action field. Changed events can also include a change object. The webhook event is compact, so the app fetches the current Project, Task, or Section from the Asana REST API before writing to Attio.
Attio write shape
Project writes preserve Asana identity first. The Asana project gid becomes the stable source key, and selected Project fields such as name, archived state, Workspace, Team, permalink, and scoped custom fields can update the matching Attio record.
Task writes use the Asana task gid as the stable source key for the Sales Tasks list entry. The scoped task surface can include task name, completion state, notes, permalink, resource subtype, Section, Project membership, and any fields the team needs for client follow-up.
Sections matter because they are the Asana object for a list header or board column inside a Project. When the Sales Tasks workflow uses Sections as sales stages, setup maps Section GIDs and names into Attio instead of calling them lists.
People linking and backfill
Email-to-People linking is optional. When it is in scope, the app extracts email addresses from Asana task or project notes, checks Attio People for a matching email, and writes the matched or created Person reference back to the Sales Task entry. Asana assignees and followers stay out of that flow by default because they usually represent internal workspace members rather than client contacts.
Historical imports and reconciliation use the Asana REST API rather than webhook history. Project, Task, and Section collection endpoints use limit and offset pagination, and the terminal condition is next_page returning null. That gives the app a controlled path for initial backfill, one-record resync, and bulk reconciliation.
What we configure during scope
The scoping call turns the Asana-to-Attio pattern into your build. These decisions are made before the app is installed.
| Decision | What we decide with you |
|---|---|
| Asana Workspace | Which Asana Workspace or Organization connects to the Attio workspace, and which Team boundaries matter for Project discovery and permissions. |
| Webhook resources | Which specific Asana resource GIDs receive webhooks. Webhooks are resource-scoped, so Project and task coverage cannot be treated as one blanket workspace subscription. |
| Project coverage | Which Asana Projects should create or update Attio project records, and whether archived Projects remain visible for reporting. |
| Sales Tasks source | Which Asana Project feeds the Sales Tasks list, which Sections become stages, and whether tasks from multiple Projects need explicit handling because Asana tasks can belong to more than one Project. |
| Project custom fields | Which Asana Project custom fields land in Attio, what each field should be called there, and which fields stay in Asana. |
| People linking | Whether the email-extraction flow is on, which note fields it scans, and whether unmatched emails should create new Attio People or only link existing ones. |
| Backfill and support actions | How much historical Project, Task, and Section data to import, which record or bulk resync actions should exist in Attio, and what support history should be visible without exposing application logs. |
Why this works with the Asana API
Asana exposes the pieces this pattern needs: OAuth 2.0 bearer-token access, resource-scoped webhook creation, a required webhook handshake, signed webhook deliveries, REST reads for Projects, Tasks, and Sections, offset pagination, and documented rate-limit responses.
Authentication uses Asana OAuth rather than a pasted personal access token. The OAuth docs document the authorization endpoint, token endpoint, refresh flow, bearer-token API access, and access-token expiry of 3600 seconds. The personal access token docs document PATs as user security credentials, which is why OAuth is the public setup model for this app.
Webhook creation is documented in the Asana webhooks guide and Create a webhook reference. The request supplies data.resource, the watched resource GID, and data.target, the receiver URL. Higher-level resources such as Workspace, Team, Portfolio, and Goal require filters. Filters can include resource_type, action, and, for changed events on lower-level resources, field filters.
The event shape is documented through Asana's Events reference and webhook guide. Public copy should describe task added or changed actions and project added or changed actions, not dotted event names. The event payload has a resource object and an action field. It does not have an action block.
Asana REST reads and pagination
The backfill and resync paths use Asana REST API v1.0 endpoints for Projects, Tasks from a Project, single Tasks, and Sections in a Project. Collection endpoints use limit and offset, with next_page set to null when there are no more pages.
Asana's object hierarchy docs matter to the mapping. A Project is the Asana container that most closely maps to a client delivery project, and a Section is the in-project grouping for list headers or board columns. Tasks can belong to multiple Projects, so scope decides which Project owns the Attio Sales Task entry.
How reliability is handled
The webhook handshake is part of Asana's creation flow. After POST /webhooks, Asana sends a test POST containing X-Hook-Secret. The receiver must echo that value and return 200 OK or 204 No Content while the create request is still in flight.
After the handshake, Asana sends X-Hook-Signature on webhook requests. The receiver verifies the request by computing an SHA256 HMAC over the full request body using the stored X-Hook-Secret. Empty events arrays are valid because Asana sends heartbeat events.
Asana retries failed or timed-out webhook deliveries with exponential backoff, and the receiver must return a successful status within 10 seconds. If delivery cannot succeed for 24 hours, Asana can delete the webhook. Asana also documents webhook delivery as at-most-once and says delivered webhooks cannot be replayed, so the integration does not depend on replay as the only recovery path.
The app writes idempotently by Asana gid, handles 429 responses using the Retry-After header, and uses resync or periodic reconciliation for backfill and missed-event recovery. Asana rate limits are per authorization token, with documented minute limits, concurrency limits, and cost limits.
How setup works
Setup separates authorization, webhook authenticity, and Attio provisioning. OAuth grants API access for the approved Asana user. The X-Hook-Secret handshake proves the webhook target can receive Asana deliveries. Attio setup controls what the client team can see and resync.
- Scope the Asana and Attio model. We confirm which Asana Workspace or Organization feeds Attio, which Teams and Projects are in scope, which Project feeds the dedicated Sales Tasks list, which Project custom fields should land in Attio, and whether email-based People linking or historical backfill belongs in the build.
- Connect Asana with OAuth. The approved Asana user completes the OAuth authorization flow. The app requests the scopes needed for the agreed resources, then uses OAuth bearer-token access for Asana API calls instead of asking the team to paste a personal access token into setup.
- Install the Attio app. We install the custom Attio app into your workspace and provision the agreed Attio attributes, Sales Tasks list, workspace settings, record actions, and support controls.
- Create resource-scoped webhooks. Asana webhooks are created against a specific resource GID, not as a blanket workspace subscription. During setup the app creates the agreed Project, Task, or higher-level resource webhooks, echoes the X-Hook-Secret during Asana's handshake, and stores that secret for future X-Hook-Signature verification.
- Run the initial backfill when scoped. If historical data is in scope, the app pulls Projects, Tasks, and Sections through the Asana REST API using limit and offset pagination until next_page is null. Backfills are paced around Asana rate limits and can be repeated for reconciliation.
- Turn on live sync. After setup, in-scope task added or changed actions and project added or changed actions update Attio. Record-level and bulk resync actions remain available for catch-up and support.
Known limitations
Custom app, not a marketplace install
This is a scoped custom engagement. It is not a public Asana marketplace app, not an Attio Marketplace app, and not a one-click install.
Webhooks are resource-scoped
Asana webhooks attach to a supplied resource GID. Workspace is one possible resource, but it is not the default unit for every subscription. The setup must choose the resources that should be watched.
Higher-level webhooks do not cover task events
Asana documents that task, subtask, and story events do not propagate to higher-level Workspace, Team, Portfolio, or Goal webhooks. Task sync needs Project-level or lower-level coverage for the work in scope.
Webhooks are not the historical backfill path
Webhooks handle new and changed records after setup. Historical Projects, Tasks, and Sections are imported through the Asana REST API with pagination and rate-limit handling.
Webhook replay is limited by Asana
Asana documents webhooks as at-most-once and not replayable after delivery. The build uses idempotent writes, resync actions, and reconciliation rather than assuming Asana can replay every missed event.
People linking is an implementation feature
Email extraction from Asana notes is not an Asana API matching feature. It is an optional implementation pattern, and it links only explicit email addresses from scoped note fields.
Assignees and followers stay out by default
Asana assignees and followers usually represent internal delivery users. We do not map them to Attio People unless the workspace has a clear client contact model for doing that.
Schema changes need controlled reprovisioning
New Asana custom fields, changed Attio attributes, or changed Sales Tasks rules need an update to the field map and a controlled reprovisioning pass before relying on new webhook writes.
Frequently asked questions
Is this a public Asana marketplace app?
No. This is a client-proven Asana-to-Attio custom app pattern, not a public marketplace app or a one-click install. We adapt the same scaffolding to the Asana Workspace, Attio schema, Project custom fields, People-linking rules, and support controls each engagement needs.
What Asana data flows into Attio?
The standard pattern syncs selected Asana Projects and selected Tasks into Attio. Projects can update Attio project-style records keyed by the Asana gid. Tasks from the scoped Project can update a dedicated Sales Tasks list keyed by the Asana task gid. Project custom fields, Sections, completion state, task notes, and permalinks are mapped only when they are part of scope.
Which Asana webhook actions are used?
Asana does not document dotted webhook event names for this surface. The receiver works from the event resource object and action field, such as resource_type task with action added or changed, and resource_type project with action added or changed.
Can one Workspace webhook capture every task change?
No. Asana webhooks attach to a supplied resource GID. Higher-level Workspace, Team, Portfolio, and Goal webhooks require filters, and Asana documents that task, subtask, and story events do not propagate to those higher-level webhooks. Task sync is scoped through the relevant Project or lower-level resources.
How are Asana records matched in Attio?
The durable Asana key is gid. Project writes use the Asana project gid as the source identifier, and task writes use the Asana task gid. Repeated deliveries update the existing Attio record or list entry instead of creating a second copy.
Does the integration create Attio People from Asana?
Only when that flow is scoped. Email addresses found in Asana task or project notes can be extracted, matched against Attio People, and linked back to the Sales Task entry. This is our implementation pattern, not an Asana API feature. Asana assignees and followers are not treated as client contacts by default.
What happens if an Asana webhook fails or an event is missed?
Asana retries failed webhook deliveries with exponential backoff and can delete a webhook after 24 hours of failed delivery. Asana also documents webhooks as at-most-once and not replayable after delivery. The integration verifies signatures, writes idempotently, and uses resync or periodic reconciliation when the workspace needs recovery beyond webhook delivery.
Do we need OAuth or a personal access token?
The public setup flow uses OAuth. Asana documents personal access tokens for direct authentication and testing, but PATs are user security credentials. For this build pattern, OAuth is the right default because the app acts on behalf of an authorized Asana user and can use refresh tokens for continued access.
API sources checked
- Asana OpenAPI specification
- Asana REST API quick start
- Asana OAuth
- Asana OAuth scopes
- Asana personal access tokens
- Asana webhooks guide
- Asana Create a webhook
- Asana Events reference
- Asana object hierarchy
- Asana pagination
- Asana rate limits
- Asana Get multiple projects
- Asana Get a project
- Asana Get tasks from a project
- Asana Get a task
- Asana Get sections in a project
- Attio Upsert a Record
- Attio App SDK record actions
- Attio App SDK bulk record actions