API Reference

Group

The Group call associates a user with an account — a company, organization, workspace, or team. It lets you capture account-level traits and link user activity to account-level signals in ThriveStack.

When to call

Call group whenever a user is associated with an account:

  • Account creationWhen a new workspace or organization is created for the first time.
  • User added to accountWhen an existing user joins an account via invitation or SSO.
  • Account profile changesWhen account attributes such as name, plan, or domain are updated.

Two IDs drive the Group call: user_id (who is performing the action) and group_id (which account they belong to). A single user can belong to multiple groups — each association is a separate Group call with the same user_id and a different group_id.

Endpoint

POST /api/group

Authentication

Pass your API key in the x-api-key header on every request. You can find your key in the ThriveStack dashboard under Settings → API Keys.

accept: */*
content-type: application/json
x-api-key: YOUR_API_KEY

Request body

Send an array containing one or more group objects.

FieldTypeRequiredDescription
group_idstringYesUnique identifier for the account/group (UUID recommended). Stable across the account's lifetime.
user_idstringYesThe user being associated with this account.
traitsobjectNoFree-form dictionary of account attributes. See Reserved traits below.
context.device_idstringNoUnique identifier for the user's device.
context.session_idstringNoCurrent session identifier.
context.sourcestringNo"product" for in-app events, "marketing" for public-facing website events.
timestampstringNoISO 8601 timestamp. Defaults to server time if omitted.

Reserved traits

ThriveStack recognises the following account trait names and gives them special handling in dashboards, segmentation, and alerts. Use these exact names when sending standard account attributes.

TraitTypeDescription
account_namestringDisplay name of the account or organization.
account_domainstringPrimary domain of the account (e.g., "acme.com").
group_typestringType of group (e.g., "Account", "Team").
industrystringIndustry classification of the account.
employeesnumberNumber of employees in the organization.
planstringCurrent subscription plan (e.g., "free", "enterprise").
websitestringAccount's website URL.
phonestringAccount contact number.
created_atstringISO 8601 date when the account was created.
descriptionstringShort description or biography of the account.
avatarstringURL of the account's logo or avatar image.

You can also include any custom traits alongside the reserved ones. Trait names are case-insensitive — use a consistent casing in your codebase.

Example

cURL

curl --location 'https://api.app.thrivestack.ai/api/group' \
--header 'accept: */*' \
--header 'content-type: application/json' \
--header 'x-api-key: YOUR_API_KEY' \
--data '[
  {
    "group_id": "ac8db7ba-5139-4911-ba6e-523fd9c4704b",
    "user_id": "18f716ac-37a4-464f-adb7-3cc30032308c",
    "context": {
      "device_id": "7d08298f",
      "session_id": "session_e2iukz3vduo",
      "group_id": "ac8db7ba-5139-4911-ba6e-523fd9c4704b",
      "source": "product"
    },
    "traits": {
      "group_type": "Account",
      "account_domain": "acme.com",
      "account_name": "Acme Corporation",
      "industry": "Technology",
      "plan": "enterprise"
    },
    "timestamp": "2024-01-15T10:30:00Z"
  }
]'

JavaScript

const myHeaders = new Headers();
myHeaders.append("accept", "*/*");
myHeaders.append("content-type", "application/json");
myHeaders.append("x-api-key", "YOUR_API_KEY");

const raw = JSON.stringify([
  {
    group_id: "ac8db7ba-5139-4911-ba6e-523fd9c4704b",
    user_id: "18f716ac-37a4-464f-adb7-3cc30032308c",
    context: {
      device_id: "7d08298f",
      session_id: "session_e2iukz3vduo",
      group_id: "ac8db7ba-5139-4911-ba6e-523fd9c4704b",
      source: "product"
    },
    traits: {
      group_type: "Account",
      account_domain: "acme.com",
      account_name: "Acme Corporation",
      industry: "Technology",
      plan: "enterprise"
    },
    timestamp: "2024-01-15T10:30:00Z"
  }
]);

fetch("https://api.app.thrivestack.ai/api/group", {
  method: "POST",
  headers: myHeaders,
  body: raw,
  redirect: "follow"
})
  .then((response) => response.text())
  .then((result) => console.log(result))
  .catch((error) => console.error(error));

Python

import requests
import json

url = "https://api.app.thrivestack.ai/api/group"

payload = json.dumps([
  {
    "group_id": "ac8db7ba-5139-4911-ba6e-523fd9c4704b",
    "user_id": "18f716ac-37a4-464f-adb7-3cc30032308c",
    "context": {
      "device_id": "7d08298f",
      "session_id": "session_e2iukz3vduo",
      "group_id": "ac8db7ba-5139-4911-ba6e-523fd9c4704b",
      "source": "product"
    },
    "traits": {
      "group_type": "Account",
      "account_domain": "acme.com",
      "account_name": "Acme Corporation",
      "industry": "Technology",
      "plan": "enterprise"
    },
    "timestamp": "2024-01-15T10:30:00Z"
  }
])
headers = {
  'accept': '*/*',
  'content-type': 'application/json',
  'x-api-key': 'YOUR_API_KEY'
}

response = requests.request("POST", url, headers=headers, data=payload)
print(response.text)

Go

package main

import (
  "fmt"
  "strings"
  "net/http"
  "io"
)

func main() {
  url := "https://api.app.thrivestack.ai/api/group"
  method := "POST"

  payload := strings.NewReader(`[
  {
    "group_id": "ac8db7ba-5139-4911-ba6e-523fd9c4704b",
    "user_id": "18f716ac-37a4-464f-adb7-3cc30032308c",
    "context": {
      "device_id": "7d08298f",
      "session_id": "session_e2iukz3vduo",
      "group_id": "ac8db7ba-5139-4911-ba6e-523fd9c4704b",
      "source": "product"
    },
    "traits": {
      "group_type": "Account",
      "account_domain": "acme.com",
      "account_name": "Acme Corporation",
      "industry": "Technology",
      "plan": "enterprise"
    },
    "timestamp": "2024-01-15T10:30:00Z"
  }
]`)

  client := &http.Client{}
  req, err := http.NewRequest(method, url, payload)
  if err != nil {
    fmt.Println(err)
    return
  }
  req.Header.Add("accept", "*/*")
  req.Header.Add("content-type", "application/json")
  req.Header.Add("x-api-key", "YOUR_API_KEY")

  res, err := client.Do(req)
  if err != nil {
    fmt.Println(err)
    return
  }
  defer res.Body.Close()

  body, err := io.ReadAll(res.Body)
  if err != nil {
    fmt.Println(err)
    return
  }
  fmt.Println(string(body))
}

Response

200 OK

{
  "success": true,
  "eventId": "evt_abc123xyz"
}

Error codes

StatusMeaning
400Bad Request — invalid JSON or missing required fields
401Unauthorized — invalid or missing API key
429Rate Limit Exceeded
500Server Error — try again later