GraphQL · Growth Intelligence

GetUsers

Fetch a paginated, filtered, and sorted list of users enriched with acquisition, engagement, and demographic data. Use this endpoint to segment your user base, build cohort analysis, and power user-level personalization. filters[].key and sort.key must use paths recognized by the growth-intelligence user list registry (userFieldByGraphQLKey in the public-api-events service). Invalid keys produce a GraphQL error.

API details

PropertyValue
EndpointPOST /growth-intelligence
ProtocolGraphQL over HTTP
Authenticationx-api-key header
Content-Typeapplication/json
Operationquery GetUsers
Response formatJSON

User fields

Use this reference when choosing filters[].key and sort.key. It lists paths on User (and nested objects) and whether filtering or sorting is allowed. account.* is returned in query results but is not in that registry yet for filter/sort.

Basic
PathLabelFilterSortTypeDescriptionExample
idUser IDYesNoString!Unique user identifier"usr_abc123"
nameName (user)YesYesString!User display name"Alice Johnson"
emailEmailYesYesString!User email address"alice@acme.com"
Account
PathLabelFilterSortTypeDescriptionExample
accountAccountsNoNo[UserAccount!]CRM accounts linked to the user (empty array or null when none). Matches repeated account rows from the accounts service.[]
account.idAccount IDNoNoString!Id on each element of account[] (not a separate filter path; use User fields table for filter keys)."acc_xyz789"
account.nameAccount nameNoNoString!Display name on each account[] element."Acme Corp"
account.sourceAccount sourceNoNoString!Source stream on each account[] element."ThriveStack"
account.timestampAccount timestampNoNoString!Association timestamp on each account[] element."2024-01-10T09:00:00Z"
Status
PathLabelFilterSortTypeDescriptionExample
enrichedEnrichedYesYesBoolean!Whether enrichment data is availabletrue
softDeletedSoft deletedYesYesBoolean!Whether the user is soft-deletedfalse
sourceSourceYesYesString!User data source stream"ThriveStack"
timeToHardDeleteTime to hard deleteYesYesFloat!Days remaining until permanent deletion25.5
trackedTrackedYesYesBoolean!Whether a creation event was receivedtrue
Acquisition
PathLabelFilterSortTypeDescriptionExample
acquisition.abuseRuleResultAbuse rule resultNoNo[AbuseRuleResult!]!Per-rule abuse evaluation (query only)[{ "passed": true, "ruleId": "r1" }]
acquisition.abuseStatusAbuse statusYesYesString!Abuse classification"clean"
acquisition.initialUtmCampaignInitial UTM campaignYesYesString!UTM campaign from first touch"spring-launch"
acquisition.initialUtmContentInitial UTM contentYesYesString!UTM content from first touch"hero"
acquisition.initialUtmMediumInitial UTM mediumYesYesString!UTM medium from first touch"cpc"
acquisition.initialUtmSourceInitial UTM sourceYesYesString!UTM source from first touch"google"
acquisition.initialUtmTermInitial UTM termYesYesString!UTM term from first touch"product"
acquisition.isInvitedIs invitedYesYesBoolean!Whether user was invited by another usertrue
acquisition.signedUpOnSigned up onYesYesString!Signup date (ISO)"2024-01-10T09:00:00Z"
acquisition.timeToSignupDaysTime to signup (days)YesYesFloat!Days from first touch to signup4.5
acquisition.touchpointsToSignupTouchpoints to signupYesYesInt!Marketing touchpoints before signup3
Engagement
PathLabelFilterSortTypeDescriptionExample
engagement.isActiveIs activeYesYesBoolean!Active in last 30 daystrue
engagement.lastActiveAtLast active atYesYesString!Last activity timestamp"2024-01-22T11:30:00Z"
engagement.latestSigninTimestampLatest sign-inYesYesString!Most recent sign-in timestamp"2024-01-22T08:45:00Z"
engagement.totalSignInsTotal sign-insYesYesInt!Cumulative sign-in count47
Demographics
PathLabelFilterSortTypeDescriptionExample
demographics.avatarAvatarYesNoString!Avatar URL"https://cdn.example.com/a.png"
demographics.cityCityYesYesString!City"San Francisco"
demographics.countryCountryYesYesString!Country"United States"
demographics.countryCodeCountry codeYesYesString!ISO country code"US"
demographics.emailProviderEmail providerYesYesString!Email provider domain"gmail.com"
demographics.employmentDomainEmployment domainYesYesString!Employer company domain"acme.com"
demographics.employmentNameEmployment nameYesYesString!Company the user works at"Acme Corp"
demographics.employmentRoleEmployment roleNoNoString!Broad job role / function"product"
demographics.employmentSeniorityEmployment seniorityYesYesString!Seniority level"senior"
demographics.employmentSubRoleEmployment sub-roleYesYesString!Granular job sub-role"pm"
demographics.employmentTitleEmployment titleYesYesString!Job title"Head of Product"
demographics.facebookHandleFacebook handleYesNoString!Facebook handle"alice.j"
demographics.firstNameFirst nameYesYesString!First name (enriched)"Alice"
demographics.fullNameFull nameYesYesString!Full name from enrichment"Alice Johnson"
demographics.githubHandleGitHub handleYesNoString!GitHub username"alice"
demographics.lastNameLast nameYesYesString!Last name (enriched)"Johnson"
demographics.linkedinHandleLinkedIn handleYesNoString!LinkedIn profile handle"in/alice"
demographics.locationLocationNoNoString!Full location string"San Francisco, CA"
demographics.phonePhoneYesNoString!Phone number(s)"+1-415-555-0199"
demographics.stateStateYesYesString!State / province"California"
demographics.stateCodeState codeYesYesString!State code"CA"
demographics.timeZoneTime zoneYesYesString!IANA time zone"America/Los_Angeles"
demographics.twitterHandleTwitter handleYesNoString!Twitter/X handle"@alice"

Input: GetUsersRequest

All three input fields are optional — omit them to retrieve the first page of all users. Combine filters, sort, and pagination to build segments.

filters · optional · array

An array of filter objects. All filters are ANDed: a user must satisfy every filter. Each object has:

{
  "key": "",
  "operator": "equals | not_equals | greater_than | less_than | greater_than_or_equal | less_than_or_equal",
  "value": ""
}

value is always a string and is coerced server-side.

Operators

OperatorSymbolDescriptionExample
equals=Exact matchkey: "acquisition.abuseStatus", value: "clean"
not_equalsExcludes the given valuekey: "engagement.isActive", value: "false"
greater_than>Numeric or date comparison (exclusive)key: "engagement.totalSignIns", value: "10"
less_than<Numeric or date comparison (exclusive)key: "engagement.totalSignIns", value: "3"
greater_than_or_equalNumeric or date comparison (inclusive)key: "engagement.totalSignIns", value: "5"
less_than_or_equalNumeric or date comparison (inclusive)key: "engagement.totalSignIns", value: "100"

sort · optional · object

Sort by exactly one field per request. sort.key must be a path whose Sort column is Yes in the User fields table above.

{
  "key": "",
  "direction": "asc" | "desc"
}

Tip: Sort by engagement.totalSignIns desc for most active users, acquisition.signedUpOn desc for newest signups, or demographics.employmentSeniority asc by seniority.

pagination · optional · object

Page-based pagination. Defaults to page 1, size 10 if omitted. size max 100.

{
  "number": 1,
  "size": 25
}

Increment number until the returned user array is empty.

Example request

Active users with more than 5 sign-ins and clean abuse status, ordered by sign-in count descending.

GraphQL query

query GetUsers($input: GetUsersRequest!) {
  getUsers(input: $input) {
    message
    user {
      id
      name
      email
      account {
        id
        name
        source
        timestamp
      }
      source
      tracked
      enriched
      softDeleted
      timeToHardDelete
      acquisition {
        signedUpOn
        isInvited
        abuseStatus
        touchpointsToSignup
        timeToSignupDays
        initialUtmSource
        initialUtmMedium
        initialUtmCampaign
        initialUtmTerm
        initialUtmContent
      }
      engagement {
        isActive
        lastActiveAt
        totalSignIns
        latestSigninTimestamp
      }
      demographics {
        firstName
        lastName
        employmentTitle
        employmentRole
        employmentSeniority
        city
        country
        timeZone
      }
    }
  }
}

Variables (JSON)

{
  "input": {
    "filters": [
      { "key": "engagement.isActive", "operator": "equals", "value": "true" },
      { "key": "engagement.totalSignIns", "operator": "greater_than", "value": "5" },
      { "key": "acquisition.abuseStatus", "operator": "equals", "value": "clean" }
    ],
    "sort": { "key": "engagement.totalSignIns", "direction": "desc" },
    "pagination": { "number": 1, "size": 25 }
  }
}

cURL

curl --location 'https://api.app.thrivestack.ai/growth-intelligence' \\
--header 'content-type: application/json' \\
--header 'x-api-key: YOUR_API_KEY' \\
--data '{
  "query": "query GetUsers($input: GetUsersRequest!) { getUsers(input: $input) { message user { id name email } } }",
  "variables": {
    "input": {
      "filters": [
        { "key": "engagement.isActive", "operator": "equals", "value": "true" },
        { "key": "engagement.totalSignIns", "operator": "greater_than", "value": "5" },
        { "key": "acquisition.abuseStatus", "operator": "equals", "value": "clean" }
      ],
      "sort": { "key": "engagement.totalSignIns", "direction": "desc" },
      "pagination": { "number": 1, "size": 25 }
    }
  }
}'

Example response

Matching users are under data.getUsers.user (array). message may be "success" or omitted depending on the server.

{
  "data": {
    "getUsers": {
      "message": "success",
      "user": [
        {
          "id": "usr_abc123",
          "name": "Alice Johnson",
          "email": "alice@acme.com",
          "account": [
            { "id": "acc_xyz789", "name": "Acme Corp", "source": "ThriveStack", "timestamp": "2024-01-10T09:00:00Z" }
          ],
          "source": "ThriveStack",
          "tracked": true,
          "enriched": true,
          "softDeleted": false,
          "timeToHardDelete": 0,
          "acquisition": {
            "signedUpOn": "2024-01-10T09:00:00Z",
            "isInvited": true,
            "abuseStatus": "clean",
            "touchpointsToSignup": 3,
            "timeToSignupDays": 4.5,
            "initialUtmSource": "google",
            "initialUtmMedium": "cpc",
            "initialUtmCampaign": "spring-launch"
          },
          "engagement": {
            "isActive": true,
            "lastActiveAt": "2024-01-22T11:30:00Z",
            "totalSignIns": 47,
            "latestSigninTimestamp": "2024-01-22T08:45:00Z"
          },
          "demographics": {
            "firstName": "Alice",
            "lastName": "Johnson",
            "employmentTitle": "Head of Product",
            "employmentRole": "product",
            "employmentSeniority": "senior",
            "city": "San Francisco",
            "country": "United States",
            "timeZone": "America/Los_Angeles"
          }
        }
      ]
    }
  }
}

Tips and best practices

  • Filter values are always strings — use "true" / "false" for booleans and numeric strings for numbers; the server coerces them.
  • All filters are ANDed. Use separate filter objects for each condition (e.g. active and 10+ sign-ins).
  • Account on the user record: query account { id name source timestamp } as a list of UserAccount. account.* is not filterable/sortable in the current user-list registry; prefer email, demographics.employmentDomain, or other fields, then narrow client-side if needed.
  • Organic power users: e.g. acquisition.isInvited equals "false" with high engagement.totalSignIns.
  • Paginate by incrementing pagination.number until user is empty.