# Quickstart

Source: https://neondeerdata.com/docs/api/quickstart/

Examples for listing tables, querying rows, and reading paginated results.

This example reads and queries lookup tables, the generally available API family. The same Bearer authentication applies to other REST families; their operations, permissions, and resource versions are documented in the [API reference](https://neondeerdata.com/docs/api/).

[Create an API key](https://neondeerdata.com/docs/api/authentication/) and set `NEON_DEER_API_KEY` on your server. These examples use Node.js with built-in `fetch`, or Python with the `requests` package.

Replace the example IDs and field keys with those from your tables. The sample **Account owners** table has unique `account_domain` and `owner_email` fields, plus `owner_name` and `region`.

To try a request in Neon Deer first, open the [API Playground](https://neondeerdata.com/docs/api/testing/). Use [Who am I](https://neondeerdata.com/docs/api/meta/self/) to check the key and organization your server is using.

## List tables

List the tables your key can read. Use a returned ID in the requests below.

### cURL

```bash
curl 'https://api.neondeerdata.com/v1/lookup-tables' \
  -H "Authorization: Bearer $NEON_DEER_API_KEY"

```

### JavaScript

```javascript
const response = await fetch("https://api.neondeerdata.com/v1/lookup-tables", {
  headers: {
    Authorization: `Bearer ${process.env.NEON_DEER_API_KEY}`,
  },
});
if (!response.ok) throw new Error(`Request failed: ${response.status}`);
const result = await response.json();

```

### Python

```python
import os

import requests

response = requests.get(
    "https://api.neondeerdata.com/v1/lookup-tables",
    headers={"Authorization": f"Bearer {os.environ['NEON_DEER_API_KEY']}"},
    timeout=30,
)
response.raise_for_status()
result = response.json()

```

Example response:

```json
{
  "data": [
    {
      "id": "3f6c2a9e-8b1d-4c7a-9e2f-5a1b7c4d8e90",
      "object": "lookup_table",
      "name": "Account owners"
    }
  ],
  "pagination": {
    "next_cursor": null
  }
}

```

The table list is paginated too. If `next_cursor` is not `null`, request its next page.

## Get a table

Get the table's fields to find their keys, value types, and filtering options.

### cURL

```bash
curl 'https://api.neondeerdata.com/v1/lookup-tables/3f6c2a9e-8b1d-4c7a-9e2f-5a1b7c4d8e90' \
  -H "Authorization: Bearer $NEON_DEER_API_KEY"

```

### JavaScript

```javascript
const response = await fetch("https://api.neondeerdata.com/v1/lookup-tables/3f6c2a9e-8b1d-4c7a-9e2f-5a1b7c4d8e90", {
  headers: {
    Authorization: `Bearer ${process.env.NEON_DEER_API_KEY}`,
  },
});
if (!response.ok) throw new Error(`Request failed: ${response.status}`);
const result = await response.json();

```

### Python

```python
import os

import requests

response = requests.get(
    "https://api.neondeerdata.com/v1/lookup-tables/3f6c2a9e-8b1d-4c7a-9e2f-5a1b7c4d8e90",
    headers={"Authorization": f"Bearer {os.environ['NEON_DEER_API_KEY']}"},
    timeout=30,
)
response.raise_for_status()
result = response.json()

```

Example response:

```json
{
  "data": {
    "id": "3f6c2a9e-8b1d-4c7a-9e2f-5a1b7c4d8e90",
    "object": "lookup_table",
    "name": "Account owners",
    "fields": [
      {
        "object": "lookup_field",
        "key": "account_domain",
        "name": "Account domain",
        "type": "domain",
        "filterable": true,
        "unique": true
      },
      {
        "object": "lookup_field",
        "key": "owner_email",
        "name": "Owner email",
        "type": "email",
        "filterable": true,
        "unique": true
      },
      {
        "object": "lookup_field",
        "key": "owner_name",
        "name": "Owner name",
        "type": "text",
        "filterable": true,
        "unique": false
      },
      {
        "object": "lookup_field",
        "key": "region",
        "name": "Region",
        "type": "text",
        "filterable": true,
        "unique": false
      }
    ]
  }
}

```

## Find matching rows

Query the `account_domain` field, which this table marks as filterable and unique. This value can match at most one row. Other filterable fields can match several rows; empty-cell filters can also return several matches.

### cURL

```bash
curl -X POST 'https://api.neondeerdata.com/v1/lookup-tables/3f6c2a9e-8b1d-4c7a-9e2f-5a1b7c4d8e90/rows/query' \
  -H "Authorization: Bearer $NEON_DEER_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"filter":{"field":"account_domain","eq":"acme.example.com"}}'

```

### JavaScript

```javascript
const response = await fetch("https://api.neondeerdata.com/v1/lookup-tables/3f6c2a9e-8b1d-4c7a-9e2f-5a1b7c4d8e90/rows/query", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.NEON_DEER_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({"filter": {"field": "account_domain", "eq": "acme.example.com"}}),
});
if (!response.ok) throw new Error(`Request failed: ${response.status}`);
const result = await response.json();

```

### Python

```python
import os

import requests

response = requests.post(
    "https://api.neondeerdata.com/v1/lookup-tables/3f6c2a9e-8b1d-4c7a-9e2f-5a1b7c4d8e90/rows/query",
    headers={"Authorization": f"Bearer {os.environ['NEON_DEER_API_KEY']}"},
    json={'filter': {'field': 'account_domain', 'eq': 'acme.example.com'}},
    timeout=30,
)
response.raise_for_status()
result = response.json()

```

Example response:

```json
{
  "data": [
    {
      "id": "a1e4c7b2-5d3f-4e8a-9b6c-0f2d7e1a3c5b",
      "object": "lookup_row",
      "values": {
        "account_domain": "acme.example.com",
        "owner_email": "dana.whitfield@example.com",
        "owner_name": "Dana Whitfield",
        "region": "Southwest"
      }
    }
  ],
  "pagination": {
    "next_cursor": null
  }
}

```

No match returns HTTP `200` with `data: []`, not `404`.

## Read every page

Keep requesting pages until `pagination.next_cursor` is `null`, even if a page is short or empty. Process the rows from each response as they arrive.

### cURL

```bash
curl 'https://api.neondeerdata.com/v1/lookup-tables/3f6c2a9e-8b1d-4c7a-9e2f-5a1b7c4d8e90/rows?limit=100' \
  -H "Authorization: Bearer $NEON_DEER_API_KEY"
# Repeat with cursor=<next_cursor>, URL-encoded, until next_cursor is null.

```

### JavaScript

```javascript
const base = "https://api.neondeerdata.com/v1/lookup-tables/3f6c2a9e-8b1d-4c7a-9e2f-5a1b7c4d8e90/rows";
let cursor = null;
do {
  const url = new URL(base);
  url.searchParams.set("limit", "100");
  if (cursor !== null) url.searchParams.set("cursor", cursor);
  const response = await fetch(url, {
    headers: { Authorization: `Bearer ${process.env.NEON_DEER_API_KEY}` },
  });
  if (!response.ok) throw new Error(`Request failed: ${response.status}`);
  const page = await response.json();
  for (const row of page.data) console.log(row.id);
  cursor = page.pagination.next_cursor;
} while (cursor !== null);

```

### Python

```python
import os

import requests

url = "https://api.neondeerdata.com/v1/lookup-tables/3f6c2a9e-8b1d-4c7a-9e2f-5a1b7c4d8e90/rows"
headers = {"Authorization": f"Bearer {os.environ['NEON_DEER_API_KEY']}"}
params = {"limit": 100}
while True:
    response = requests.get(url, headers=headers, params=params, timeout=30)
    response.raise_for_status()
    page = response.json()
    for row in page["data"]:
        print(row["id"])
    cursor = page["pagination"]["next_cursor"]
    if cursor is None:
        break
    params["cursor"] = cursor

```

These examples request 100 rows per page. See [Pagination](https://neondeerdata.com/docs/api/lookup-tables/pagination/) for cursors and parallel reads, and [Rate limits](https://neondeerdata.com/docs/api/rate-limits/) for retry handling.
