---
title: "Run a structured query across one or more tables"
method: POST
path: "/tables/query"
tags: ["tables"]
---

# Run a structured query across one or more tables

`POST /tables/query`

Runs a structured query against Clay table data and returns records with field metadata. Results are paginated: pass the returned cursor back to fetch the next page. Scans return rows in least-recently-updated-first order and reflect writes that land while you paginate — a scan returns every record visible when it started and picks up records written while it runs, and a record updated mid-scan can be returned again with fresher data, so deduplicate by id if you need each record once.

## Request body

- StructuredQueryRequest
  - `cursor` string — Opaque cursor from the previous response. Scans page in least-recently-updated-first order and reflect concurrent writes: a record updated mid-scan can be returned again, so deduplicate by id.
  - `limit` integer
  - `query` StructuredQuery, required
    - `field_mode` 'names' | 'ids'
    - `filter` union
      - FilterPredicate
        - `field` string, required
        - `op` '=' | '!=' | '>' | '>=' | '<' | '<=' | 'contains' | 'not_contains' | 'starts_with' | 'ends_with' | 'in' | 'not_in' | 'is_empty' | 'is_not_empty', required
        - `path` string[]
        - `value` union
          - string
          - number
          - boolean
          - union[]
            - union
              - …
      - FilterAnd
        - `and` FilterExpression[], required
      - FilterOr
        - `or` FilterExpression[], required
      - FilterNot
        - `not` FilterExpression, required — recursive
    - `group_by` string[]
    - `join` object[]
      - `on` object, required
        - `left` string, required
        - `right` string, required
      - `table` string, required
      - `type` 'inner' | 'left'
    - `order_by` object[] — Custom sort. Queries with a custom order_by do not support cursor pagination.
      - `direction` 'asc' | 'desc'
      - `field` string, required
    - `select` union[]
      - union
        - AggregateSelect
          - `as` string, required
          - `field` string, required
          - `fn` 'count' | 'sum' | 'avg' | 'max' | 'min', required
          - `path` string[]
        - FieldSelect
          - `as` string
          - `field` string, required
          - `path` string[]
          - `table` string
    - `tables` object[], required
      - `alias` string
      - `id` string, required

## Response `200`

200

- QueryResponse
  - `cursor` string
  - `data` object[], required
  - `fields` object

## Other responses

- `400` — 400
- `401` — 401
- `403` — 403
- `404` — 404
- `422` — 422
- `429` — 429

---

[API](https://skmtc.net/clay/apis/clay-public-api.md) · [All operations](https://skmtc.net/clay/apis/clay-public-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/clay/clay-public-api/versions/c1f3cd4d89da/schema)
