> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tela.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Query Tasks

> Query and filter tasks from a Workstation/App using advanced filters on metadata and extracted data

Query tasks from a Workstation (App) with powerful filtering capabilities. This endpoint allows you to filter by metadata (status, dates, tags) and by extracted data fields using MongoDB-style operators.

## Basic Query

<CodeGroup>
  ```typescript theme={null}
  const API_KEY = process.env.TELA_API_KEY;

  const response = await fetch('https://api.tela.com/task/query', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${API_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      promptApplicationId: "your-app-uuid",
      limit: 20
    })
  });

  const data = await response.json();
  console.log(data);
  ```

  ```python theme={null}
  import requests
  import os

  API_KEY = os.getenv('TELA_API_KEY')

  response = requests.post(
      'https://api.tela.com/task/query',
      headers={
          'Authorization': f'Bearer {API_KEY}',
          'Content-Type': 'application/json'
      },
      json={
          'promptApplicationId': 'your-app-uuid',
          'limit': 20
      }
  )

  print(response.json())
  ```

  ```javascript theme={null}
  const API_KEY = process.env.TELA_API_KEY;

  fetch('https://api.tela.com/task/query', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${API_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      promptApplicationId: 'your-app-uuid',
      limit: 20
    })
  })
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error('Error:', error));
  ```
</CodeGroup>

## Query with Metadata Filters

Filter tasks by status, creation date, approval date, tags, and more.

<CodeGroup>
  ```typescript theme={null}
  const response = await fetch('https://api.tela.com/task/query', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${API_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      promptApplicationId: "your-app-uuid",
      filters: {
        status: ["approved", "completed"],
        createdAtSince: "2025-01-01T00:00:00Z",
        createdAtUntil: "2025-01-31T23:59:59Z",
        approvedBy: ["user@company.com"],
        tags: ["priority", "reviewed"]
      },
      orderBy: "createdAt",
      order: "desc",
      limit: 50
    })
  });
  ```

  ```python theme={null}
  response = requests.post(
      'https://api.tela.com/task/query',
      headers={
          'Authorization': f'Bearer {API_KEY}',
          'Content-Type': 'application/json'
      },
      json={
          'promptApplicationId': 'your-app-uuid',
          'filters': {
              'status': ['approved', 'completed'],
              'createdAtSince': '2025-01-01T00:00:00Z',
              'createdAtUntil': '2025-01-31T23:59:59Z',
              'approvedBy': ['user@company.com'],
              'tags': ['priority', 'reviewed']
          },
          'orderBy': 'createdAt',
          'order': 'desc',
          'limit': 50
      }
  )
  ```
</CodeGroup>

## Query by Extracted Data (outputQuery)

The most powerful feature is filtering by the data extracted from your documents. Use MongoDB-style operators to query any field in your task's output.

### Simple Equality

<CodeGroup>
  ```typescript theme={null}
  const response = await fetch('https://api.tela.com/task/query', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${API_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      promptApplicationId: "your-app-uuid",
      outputQuery: {
        "cliente": "Acme Corporation",
        "status": "active"
      }
    })
  });
  ```

  ```python theme={null}
  response = requests.post(
      'https://api.tela.com/task/query',
      headers={
          'Authorization': f'Bearer {API_KEY}',
          'Content-Type': 'application/json'
      },
      json={
          'promptApplicationId': 'your-app-uuid',
          'outputQuery': {
              'cliente': 'Acme Corporation',
              'status': 'active'
          }
      }
  )
  ```
</CodeGroup>

### Comparison Operators

<CodeGroup>
  ```typescript theme={null}
  const response = await fetch('https://api.tela.com/task/query', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${API_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      promptApplicationId: "your-app-uuid",
      outputQuery: {
        // Numeric comparisons
        "valor": { "$gte": 100000, "$lte": 500000 },

        // Date comparisons
        "dataVencimento": { "$lte": "2025-03-31" },

        // Text search (case-insensitive)
        "descricao": { "$contains": "compliance" },

        // Value in list
        "categoria": { "$in": ["financeiro", "juridico"] }
      }
    })
  });
  ```

  ```python theme={null}
  response = requests.post(
      'https://api.tela.com/task/query',
      headers={
          'Authorization': f'Bearer {API_KEY}',
          'Content-Type': 'application/json'
      },
      json={
          'promptApplicationId': 'your-app-uuid',
          'outputQuery': {
              # Numeric comparisons
              'valor': { '$gte': 100000, '$lte': 500000 },

              # Date comparisons
              'dataVencimento': { '$lte': '2025-03-31' },

              # Text search (case-insensitive)
              'descricao': { '$contains': 'compliance' },

              # Value in list
              'categoria': { '$in': ['financeiro', 'juridico'] }
          }
      }
  )
  ```
</CodeGroup>

### Querying Nested Arrays with \$elemMatch

When your extracted data contains arrays (e.g., line items, categories, participants), use `$elemMatch` to query elements within those arrays.

<Tip>
  `$elemMatch` supports nesting, so you can query deeply nested structures like `categories[].items[].price`.
</Tip>

<CodeGroup>
  ```typescript theme={null}
  // Example: Find menus that have any item under $10
  const response = await fetch('https://api.tela.com/task/query', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${API_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      promptApplicationId: "your-app-uuid",
      outputQuery: {
        "categories": {
          "$elemMatch": {
            "items": {
              "$elemMatch": {
                "price": { "$lt": 10 }
              }
            }
          }
        }
      }
    })
  });
  ```

  ```python theme={null}
  # Example: Find menus that have any item under $10
  response = requests.post(
      'https://api.tela.com/task/query',
      headers={
          'Authorization': f'Bearer {API_KEY}',
          'Content-Type': 'application/json'
      },
      json={
          'promptApplicationId': 'your-app-uuid',
          'outputQuery': {
              'categories': {
                  '$elemMatch': {
                      'items': {
                          '$elemMatch': {
                              'price': { '$lt': 10 }
                          }
                      }
                  }
              }
          }
      }
  )
  ```
</CodeGroup>

#### More \$elemMatch Examples

```typescript theme={null}
// Find invoices with any line item over $1000
{
  "outputQuery": {
    "lineItems": {
      "$elemMatch": {
        "amount": { "$gt": 1000 }
      }
    }
  }
}

// Find contracts with a specific signatory
{
  "outputQuery": {
    "signatories": {
      "$elemMatch": {
        "name": { "$contains": "John" },
        "role": "CEO"
      }
    }
  }
}

// Find menus with vegan options in the beverages category
{
  "outputQuery": {
    "categories": {
      "$elemMatch": {
        "category_name": "BEVERAGES",
        "items": {
          "$elemMatch": {
            "dietary_tags": { "$contains": "Vegan" }
          }
        }
      }
    }
  }
}
```

## Select Specific Fields

Reduce response size by selecting only the fields you need from the extracted data.

<CodeGroup>
  ```typescript theme={null}
  const response = await fetch('https://api.tela.com/task/query', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${API_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      promptApplicationId: "your-app-uuid",
      outputQuery: {
        "valor": { "$gt": 100000 }
      },
      select: ["cliente", "valor", "dataVencimento", "status"]
    })
  });
  ```

  ```python theme={null}
  response = requests.post(
      'https://api.tela.com/task/query',
      headers={
          'Authorization': f'Bearer {API_KEY}',
          'Content-Type': 'application/json'
      },
      json={
          'promptApplicationId': 'your-app-uuid',
          'outputQuery': {
              'valor': { '$gt': 100000 }
          },
          'select': ['cliente', 'valor', 'dataVencimento', 'status']
      }
  )
  ```
</CodeGroup>

## Pagination

Use `limit` and `offset` for paginating through large result sets.

<CodeGroup>
  ```typescript theme={null}
  // First page
  const page1 = await fetch('https://api.tela.com/task/query', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${API_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      promptApplicationId: "your-app-uuid",
      limit: 20,
      offset: 0
    })
  });

  // Second page
  const page2 = await fetch('https://api.tela.com/task/query', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${API_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      promptApplicationId: "your-app-uuid",
      limit: 20,
      offset: 20
    })
  });
  ```
</CodeGroup>

***

## Request Body

| Field                 | Type      | Required | Description                                                   |
| --------------------- | --------- | -------- | ------------------------------------------------------------- |
| `promptApplicationId` | string    | Yes      | UUID of the Workstation/App to query                          |
| `filters`             | object    | No       | Metadata filters (see below)                                  |
| `outputQuery`         | object    | No       | Filters on extracted data fields                              |
| `select`              | string\[] | No       | Fields to return from output. If empty, returns all fields    |
| `limit`               | number    | No       | Max results to return (1-100, default: 50)                    |
| `offset`              | number    | No       | Number of results to skip (default: 0)                        |
| `orderBy`             | string    | No       | Sort field: `createdAt`, `updatedAt`, `approvedAt`, or `name` |
| `order`               | string    | No       | Sort direction: `asc` or `desc`                               |

### Filters Object

| Field             | Type      | Description                                               |
| ----------------- | --------- | --------------------------------------------------------- |
| `status`          | string\[] | Filter by task status (e.g., `["approved", "completed"]`) |
| `createdAtSince`  | string    | Tasks created after this ISO datetime                     |
| `createdAtUntil`  | string    | Tasks created before this ISO datetime                    |
| `approvedAtSince` | string    | Tasks approved after this ISO datetime                    |
| `approvedAtUntil` | string    | Tasks approved before this ISO datetime                   |
| `approvedBy`      | string\[] | Filter by approver email addresses                        |
| `createdBy`       | string\[] | Filter by creator email addresses                         |
| `tags`            | string\[] | Filter by task tags                                       |

### Output Query Operators

| Operator     | Example                               | Description                  |
| ------------ | ------------------------------------- | ---------------------------- |
| (none)       | `"field": "value"`                    | Exact equality match         |
| `$gt`        | `{ "$gt": 100 }`                      | Greater than                 |
| `$gte`       | `{ "$gte": 100 }`                     | Greater than or equal        |
| `$lt`        | `{ "$lt": 100 }`                      | Less than                    |
| `$lte`       | `{ "$lte": 100 }`                     | Less than or equal           |
| `$eq`        | `{ "$eq": 100 }`                      | Explicit equality            |
| `$ne`        | `{ "$ne": 100 }`                      | Not equal                    |
| `$in`        | `{ "$in": ["a", "b"] }`               | Value in array               |
| `$contains`  | `{ "$contains": "text" }`             | Case-insensitive text search |
| `$elemMatch` | `{ "$elemMatch": {...} }`             | Match element in array       |
| `$type`      | `{ "$gt": "100", "$type": "number" }` | Override type inference      |

### Type Inference

The system automatically infers data types from values:

| Value Format             | Inferred Type | SQL Cast      |
| ------------------------ | ------------- | ------------- |
| `100`, `3.14`            | number        | `::numeric`   |
| `true`, `false`          | boolean       | `::boolean`   |
| `"2025-03-01"`           | date          | `::date`      |
| `"2025-03-01T10:00:00Z"` | timestamp     | `::timestamp` |
| Other strings            | string        | (none)        |

Use `$type` to override when needed:

```json theme={null}
{ "codigo": { "$gt": "100", "$type": "number" } }
```

***

## Response

```json theme={null}
{
  "data": [
    {
      "taskId": "550e8400-e29b-41d4-a716-446655440000",
      "taskName": "Invoice-2025-001.pdf",
      "status": "approved",
      "createdAt": "2025-01-15T10:30:00Z",
      "approvedAt": "2025-01-15T11:00:00Z",
      "output": {
        "cliente": "Acme Corporation",
        "valor": 150000,
        "dataVencimento": "2025-03-31"
      }
    }
  ],
  "meta": {
    "totalCount": 142,
    "limit": 20,
    "offset": 0,
    "currentPage": 1,
    "totalPages": 8
  }
}
```

### Response Fields

| Field               | Type           | Description                                    |
| ------------------- | -------------- | ---------------------------------------------- |
| `data`              | array          | Array of matching tasks                        |
| `data[].taskId`     | string         | Unique task identifier                         |
| `data[].taskName`   | string         | Task name (usually the document filename)      |
| `data[].status`     | string         | Current task status                            |
| `data[].createdAt`  | string         | ISO datetime when task was created             |
| `data[].approvedAt` | string \| null | ISO datetime when task was approved            |
| `data[].output`     | object         | Extracted data (all fields or selected fields) |
| `meta.totalCount`   | number         | Total number of matching tasks                 |
| `meta.limit`        | number         | Results per page                               |
| `meta.offset`       | number         | Number of results skipped                      |
| `meta.currentPage`  | number         | Current page number                            |
| `meta.totalPages`   | number         | Total number of pages                          |

***

## Error Responses

| Status | Description                                    |
| ------ | ---------------------------------------------- |
| `400`  | Invalid request body or malformed query        |
| `401`  | Missing or invalid data token                  |
| `403`  | Token doesn't have access to the specified app |
| `404`  | App not found                                  |
| `500`  | Internal server error                          |
