---
title: List data tables
url: /docs/developers/reference/data-tables-query
---

# List data tables

`data.tables.query@1`

Lists the tables this key can read, with their fields. Each table's `resourceRef` is what [Read a list](data-view-source-query.md) and [Change items](data-collection-mutate.md) need, and each field's `id` is how rows name its value.

## Call it

Send `POST /invocations` with the `target` this operation's catalogue entry gives (`GET /catalog`): replace `YOUR_FEATURE_ID` with its `featureId`. The input is empty.

```curl tabs
# A new operationId for each new request; the same one to retry it.
curl https://api.growlocal.site/api/v1/profiles/YOUR_BUSINESS_ID/invocations \
  -H "Authorization: Bearer gl_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "target": {
    "featureId": "YOUR_FEATURE_ID",
    "export": "tables",
    "contractRef": "data.tables.query@1"
  },
  "operationId": "list-tables-1",
  "input": {}
}'
```

```javascript tabs
// A new operationId for each new request; the same one to retry it.
const response = await fetch(
  "https://api.growlocal.site/api/v1/profiles/YOUR_BUSINESS_ID/invocations",
  {
    method: "POST",
    headers: {
      Authorization: "Bearer gl_YOUR_API_KEY",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      "target": {
        "featureId": "YOUR_FEATURE_ID",
        "export": "tables",
        "contractRef": "data.tables.query@1"
      },
      "operationId": "list-tables-1",
      "input": {}
    }),
  },
);
const receipt = await response.json();
console.log(response.status, receipt);
```

```python tabs
import requests

# A new operationId for each new request; the same one to retry it.
response = requests.post(
    "https://api.growlocal.site/api/v1/profiles/YOUR_BUSINESS_ID/invocations",
    headers={"Authorization": "Bearer gl_YOUR_API_KEY"},
    json={
        "target": {
            "featureId": "YOUR_FEATURE_ID",
            "export": "tables",
            "contractRef": "data.tables.query@1",
        },
        "operationId": "list-tables-1",
        "input": {},
    },
    timeout=30,
)
print(response.status_code, response.json())
```

## Parameters

This operation takes no parameters: send `"input": {}`.

## Response

A call that worked answers `200` with an `applied` receipt; its `output` holds these fields, among others. `GET /catalog/data.tables.query@1` answers the complete shape as JSON Schema.

| Name | Type | Description |
|---|---|---|
| `tables` | array of object | Every table this key can read, at most 100. |
| `tables[].resourceRef` | string | The table, as `resourceRef` in Read a list and Change items. |
| `tables[].title` | string | The table's name, as the business sees it. |
| `tables[].origin` | one of `member`, `owner` | `member` for a table someone in the business made, `owner` for one a feature keeps. |
| `tables[].canCreate` | boolean | Whether a row can be added here with Change items. When it's `false`, `createUnavailable` says why. |
| `tables[].canArchive` | boolean | Whether rows here can be archived. |
| `tables[].fields` | array of object | The table's fields, in order. |
| `tables[].fields[].id` | string | The field's id, such as `f_email`: the key of its value in a row's `values`. It stays the same when the field is renamed. |
| `tables[].fields[].label` | string | The field's name, as the business sees it. |
| `tables[].fields[].type` | one of `string`, `number`, `integer`, `boolean`, `object`, `array` | The kind of value the field holds. |
| `tables[].fields[].required` | boolean | Whether every row must have a value here. |
| `tables[].fields[].editable` | boolean | Whether this key may write the field with Change items right now. |
| `tables[].fields[].options` | array of string | The choices of a choice field. |
| `tables[].fields[].format` | string | For a text field with a fixed format: `date`, `date-time`, `time-local`, `uri` or `email`. |
| `tables[].fields[].query` | object | What Read a list can do with this field: which `filters` operators it takes, and whether it can `sort` and `search` by it. |
| `tables[].archivedAt` | string or null | When the table was archived, or `null` while it's in use. |
| `tables[].description` | string | What the table is for, if someone said. |

```json title="Response"
{
  "status": "applied",
  "operationId": "list-tables-1",
  "output": {
    "tables": [
      {
        "id": "4f9d2c1e-8a7b-4c3d-9e2f-1a2b3c4d5e6f",
        "featureId": "juniper-cakes.data",
        "collectionId": "juniper-cakes.quote-requests",
        "resourceRef": "juniper-cakes.quote-requests",
        "title": "Quote requests",
        "schemaRef": "…",
        "origin": "member",
        "emitsRowChanges": true,
        "fields": [
          {
            "id": "f_name",
            "label": "Name",
            "type": "string",
            "required": false,
            "editable": true,
            "editing": "ordinary",
            "query": {
              "filters": [
                "eq",
                "in",
                "not-in",
                "contains",
                "empty",
                "present"
              ],
              "sort": true,
              "search": true
            },
            "semanticRole": "record-title"
          },
          {
            "id": "f_email",
            "label": "Email",
            "type": "string",
            "required": false,
            "editable": true,
            "editing": "ordinary",
            "query": {
              "filters": [
                "eq",
                "in",
                "not-in",
                "contains",
                "empty",
                "present"
              ],
              "sort": true,
              "search": true
            },
            "format": "email"
          }
        ],
        "canCreate": true,
        "createUnavailable": null,
        "canArchive": true,
        "canDeleteRows": true,
        "canConfigure": true,
        "canConfigureTable": true,
        "canArchiveTable": true,
        "canDeleteTable": true,
        "archivedAt": null,
        "revision": 1,
        "description": "",
        "color": null,
        "opensAs": "table",
        "columnPolicy": {
          "canAddColumns": true,
          "permittedFamilies": [
            "text",
            "long_text",
            "email",
            "date"
          ],
          "fields": [
            {
              "id": "f_name",
              "canRename": true,
              "canRemove": false,
              "canAddOptions": false,
              "states": "open"
            },
            {
              "id": "f_email",
              "canRename": true,
              "canRemove": true,
              "canAddOptions": false,
              "states": "open"
            }
          ]
        },
        "process": null,
        "views": [],
        "recordLayouts": []
      }
    ]
  }
}
```

## Errors

It reads and changes nothing. Besides the answers every request can get ([Errors](../errors.md)), its receipt can say:

| Status | HTTP | What it means |
|---|---|---|
| `rejected` | 400, or 403 when it's a matter of access | Not done. `diagnostics` says why: each has a `code`, a `path` into what you sent and a `message`. |
