# Asana

Asana is a project management platform for teams to organize, track, and manage their work. The Sling Asana connector extracts data from the Asana REST API, supporting workspaces, projects, tasks, users, teams, tags, sections, stories, attachments, and more.

{% hint style="success" %}
**CLI Pro Required**: APIs require a [CLI Pro token](https://docs.slingdata.io/sling-cli/cli-pro) or [Platform Plan](https://docs.slingdata.io/sling-platform/platform).
{% endhint %}

## Setup

The following credentials are accepted:

**Secrets:**

* `access_token` **(required)** -> Your Asana Personal Access Token

### Getting Your Personal Access Token

1. Log in to [Asana](https://app.asana.com)
2. Go to the [Developer Console](https://app.asana.com/0/developer-console)
3. Navigate to the **Personal access tokens** tab
4. Click **Create new token**
5. Give it a name (e.g., "Sling Integration")
6. Agree to the API Terms and click **Create token**
7. Copy the token immediately — it won't be shown again

{% hint style="warning" %}
**Important:** Personal access tokens grant the same access as your user account. Use a service account with minimal permissions for production workloads.
{% endhint %}

### Using `sling conns`

Here are examples of setting a connection named `ASANA`. We must provide the `type=api` property:

{% code overflow="wrap" %}

```bash
sling conns set ASANA type=api spec=asana secrets='{ access_token: 2/xxxxxxxxxxxx/xxxxxxxxxxxx:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx }'
```

{% endcode %}

### Environment Variable

{% code overflow="wrap" %}

```bash
export ASANA='{ type: api, spec: asana, secrets: { access_token: "2/xxxxxxxxxxxx/xxxxxxxxxxxx:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" } }'
```

{% endcode %}

### Sling Env File YAML

See [here](https://docs.slingdata.io/sling-cli/environment#sling-env-file-env.yaml) to learn more about the sling `env.yaml` file.

```yaml
connections:
  ASANA:
    type: api
    spec: asana
    secrets:
      access_token: "2/xxxxxxxxxxxx/xxxxxxxxxxxx:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
```

## Replication

Here's an example replication configuration to sync Asana data to a PostgreSQL database:

```yaml
source: ASANA
target: MY_POSTGRES

defaults:
  mode: full-refresh
  object: asana.{stream_name}

streams:
  # sync all endpoints
  '*':
```

**Incremental sync for tasks:**

```yaml
source: ASANA
target: MY_POSTGRES

defaults:
  object: asana.{stream_name}

streams:
  workspaces:
    mode: full-refresh

  users:
    mode: full-refresh

  teams:
    mode: full-refresh

  projects:
    mode: full-refresh

  tasks:
    mode: incremental

  sections:
    mode: full-refresh

  tags:
    mode: full-refresh

  stories:
    mode: full-refresh

  attachments:
    mode: full-refresh

  team_memberships:
    mode: full-refresh

  portfolios:
    mode: full-refresh

  custom_fields:
    mode: full-refresh
```

## Endpoints

| Endpoint           | Description                                         | Incremental | Depends On   |
| ------------------ | --------------------------------------------------- | ----------- | ------------ |
| `workspaces`       | All workspaces accessible to the authenticated user | No          | —            |
| `users`            | All users in each workspace                         | No          | `workspaces` |
| `teams`            | All teams in each workspace                         | No          | `workspaces` |
| `projects`         | All projects in each workspace                      | No          | `workspaces` |
| `tasks`            | All tasks in each project                           | Yes         | `projects`   |
| `sections`         | All sections in each project                        | No          | `projects`   |
| `tags`             | All tags in each workspace                          | No          | `workspaces` |
| `stories`          | All stories (comments, updates) for each task       | No          | `tasks`      |
| `attachments`      | All attachments for each task                       | No          | `tasks`      |
| `team_memberships` | All memberships for each team                       | No          | `teams`      |
| `portfolios`       | All portfolios in each workspace                    | No          | `workspaces` |
| `custom_fields`    | All custom fields in each workspace                 | No          | `workspaces` |

The connector uses a **queue-based architecture** to handle parent-child relationships. The `workspaces` endpoint runs first and populates workspace IDs, which are used by `users`, `teams`, `projects`, `tags`, `portfolios`, and `custom_fields`. The `projects` endpoint populates project IDs for `tasks` and `sections`. The `tasks` endpoint populates task IDs for `stories` and `attachments`. The `teams` endpoint populates team IDs for `team_memberships`.

To discover available endpoints:

```bash
sling conns discover ASANA
```

### Endpoint Details

**`workspaces`** — Returns all workspaces (organizations and personal workspaces) the authenticated user belongs to. Workspace IDs are queued for child endpoints.

**`users`** — Returns workspace members including name, email, photo, and resource type.

**`teams`** — Returns all teams in each workspace. Team IDs are queued for the `team_memberships` endpoint.

**`projects`** — Returns all projects with metadata including name, owner, status, dates, color, notes, and archive status. Project IDs are queued for `tasks` and `sections`.

**`tasks`** — Returns all tasks in each project with full detail: assignee, completion status, dates, notes, subtask count, tags, and parent info. Supports incremental sync via `modified_since`. Task IDs are queued for `stories` and `attachments`.

**`sections`** — Returns all sections (columns in Board view, groups in List view) for each project.

**`tags`** — Returns all tags in each workspace.

**`stories`** — Returns all stories for each task, including comments, status updates, and system-generated activity entries.

**`attachments`** — Returns all file attachments for each task.

**`team_memberships`** — Returns all memberships for each team, showing which users belong to which teams.

**`portfolios`** — Returns all portfolios owned by the authenticated user in each workspace.

**`custom_fields`** — Returns all custom field definitions in each workspace.

## Incremental Sync

The `tasks` endpoint supports incremental sync using the `modified_since` parameter:

* **First run:** Fetches all tasks modified in the last 365 days
* **Subsequent runs:** Only fetches tasks modified after the last sync timestamp

All other endpoints run in full-refresh mode since Asana does not provide server-side time-based filtering for those resources.

## Rate Limiting

The Asana API enforces rate limits:

* **Standard limit:** Approximately 1,500 requests per minute

The connector automatically:

* Uses rate limiting (20 requests/second with concurrency of 3)
* Retries with exponential backoff on 429 (rate limit) responses
* Allows up to 5 retry attempts with a base delay of 5 seconds

## Common Use Cases

### Sync All Asana Data

```yaml
source: ASANA
target: MY_POSTGRES

defaults:
  mode: full-refresh
  object: asana.{stream_name}

streams:
  '*':
```

### Sync Tasks Incrementally

```yaml
source: ASANA
target: MY_POSTGRES

defaults:
  object: asana.{stream_name}

streams:
  workspaces:
    mode: full-refresh
  projects:
    mode: full-refresh
  tasks:
    mode: incremental
```

### Extract Task Comments for Analysis

```yaml
source: ASANA
target: MY_POSTGRES

defaults:
  mode: full-refresh
  object: asana.{stream_name}

streams:
  workspaces:
  projects:
  tasks:
  stories:
```

### Sync Team Structure

```yaml
source: ASANA
target: MY_POSTGRES

defaults:
  mode: full-refresh
  object: asana.{stream_name}

streams:
  workspaces:
  users:
  teams:
  team_memberships:
```

If you are facing issues connecting, please reach out to us at <support@slingdata.io>, on [discord](https://discord.gg/q5xtaSNDvp) or open a Github Issue [here](https://github.com/slingdata-io/sling-cli/issues).
