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.
Create an API key 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. Use Who am I 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
curl 'https://api.neondeerdata.com/v1/lookup-tables' \
-H "Authorization: Bearer $NEON_DEER_API_KEY"
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
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:
{
"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
curl 'https://api.neondeerdata.com/v1/lookup-tables/3f6c2a9e-8b1d-4c7a-9e2f-5a1b7c4d8e90' \
-H "Authorization: Bearer $NEON_DEER_API_KEY"
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
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:
{
"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
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
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
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:
{
"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
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
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
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 for cursors and parallel reads, and Rate limits for retry handling.