Skip to main content

Table queries

The user and team list endpoints work like a spreadsheet export: you say which columns you want, how to filter and sort, and which page to return. The same request body is used by:

EndpointRows
POST /users/tableUsers of the account
POST /team/tableTeams
POST /team/{team_id}/members/tableMembers of one team
POST /campaigns/tableCampaigns of the account
POST /campaigns/{campaign_id}/users/tableParticipants of one campaign; select users.invite_campaign_user.token for personal invite links
POST /team/{team_id}/members/table/countJust total and pages for the same filters

1. Discover the columns​

Column keys differ per endpoint, so fetch them first:

  • GET /users/columns for user tables (also used by participant tables)
  • GET /team/columns for team tables
  • GET /campaigns/columns for campaign tables

The response lists every queryable column with its type (keyword, numeric, date, name, email) and, for users, ready-made table views (All users, Core Drivers, Core Values, Competencies) whose payload you can send as-is.

{
"table_views": [
{
"name": "All users",
"payload": {
"columns": ["users.email", "users.first_name", "users.last_name", "users.display_status", "users.usergroups.name"],
"filters": []
}
}
],
"columns": {
"users.id": { "name": "User id", "type": "numeric", "key": "users.id" },
"users.email": { "name": "Email", "type": "email", "key": "users.email" },
"users.created_at": { "name": "Created", "type": "date", "key": "users.created_at" }
}
}

Assessment scores and HRIS fields are columns too (for example users.core_drivers.drive or a field you imported such as hris.business_unit), which is how you export results in bulk.

2. Query​

curl -X POST https://api.deepersignals.com/api/external/users/table \
-H "X-TOKEN: $DS_API_TOKEN" -H "Content-Type: application/json" \
-d '{
"columns": ["users.id", "users.email", "users.first_name", "users.last_name", "users.created_at"],
"filters": [
{ "field": "users.created_at", "type": "between", "value": ["2026-01-01 00:00:00", "2026-03-31 23:59:59"] },
{ "field": "users.usergroups.name", "type": "in", "value": ["Sales", "Marketing"] }
],
"sort": { "users.created_at": "desc" },
"pagination": { "limit": 100, "page": 1 },
"q": "doe"
}'
{
"items": [
{ "users.id": 523108, "users.email": "jane.doe@example.com", "users.first_name": "Jane", "users.last_name": "Doe", "users.created_at": "2026-02-16 08:41:47" }
],
"total": 1,
"pages": 1
}

Request body​

KeyRequiredDescription
columnsyes1 to 100 column keys from the columns endpoint. Rows are objects keyed by these.
filtersnoUp to 5 conditions, combined with AND. See operators below.
sortnoOne entry, { "<column>": "asc" | "desc" }.
paginationno{ "limit": <1..500>, "page": <1..> }. Defaults to the first page of 25.
qnoFree-text search over first name, last name and e-mail.

Filter operators​

Each filter is { "field": "<column>", "type": "<operator>", "value": ... }.

OperatorValueColumn types
eq, neqsingle valueall
in, not_inlist of valuesall
contains, not_contains, starts_with, ends_withstringtext-like columns
gt, gte, lt, ltenumber or datenumeric, date
between, not_between[low, high]numeric, date
empty, not_emptyno valueall

An entry of the form { "type": "or", "filters": [ ... ] } groups conditions with OR.

Dates are YYYY-MM-DD HH:MM:SS in UTC.

Limits​

See Rate limits → Request shape limits. A request that breaks a limit is answered with 400 and a details object naming the constraint.

Paging through everything​

Loop over page until page * limit >= total. Keep the same filters and sort for every page; sort by a stable column such as users.id so rows do not shift between pages when users are created while you export.