API Reference

Identify

The Identify call lets you associate actions with a specific user and capture descriptive traits about them — such as their email, name, and account membership. It is the foundation of user-level analytics in ThriveStack.

When to call

Call identify at the following moments in your application:

  • After registrationWhen a new user completes sign-up for the first time.
  • After loginEach time a returning user successfully authenticates.
  • When profile changesWhenever a user updates their email, name, or other profile attributes.

Use your internal database ID (UUID v4 recommended) as user_id. Database IDs never change, making them more reliable than emails or usernames.

Endpoint

POST /api/identify

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 identify objects.

FieldTypeRequiredDescription
user_idstringYesUnique identifier for the user. Use a stable database ID (UUID recommended) — never use email as the ID.
traitsobjectNoFree-form dictionary of descriptive attributes about the user. See Reserved traits below.
context.group_idstringNoThe account or organization this user belongs to. Required to link user activity to account-level signals.
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 of when the event occurred. Defaults to the time the server receives the request.

Reserved traits

ThriveStack recognises the following trait names and gives them special handling across the platform. Use these exact names when sending standard user attributes.

TraitTypeDescription
user_emailstringUser's email address.
user_namestringUser's full display name.
first_namestringFirst name.
last_namestringLast name.
phonestringPhone number.
avatarstringURL of the user's avatar image.
titlestringJob title or professional role.
usernamestringUsername or handle.
created_atstringISO 8601 date when the user account was created.
planstringCurrent subscription plan (e.g., "free", "pro").

You can also include any custom traits alongside the reserved ones.

Example

cURL

curl --location 'https://api.app.thrivestack.ai/api/identify' \
--header 'accept: */*' \
--header 'content-type: application/json' \
--header 'x-api-key: YOUR_API_KEY' \
--data '[
  {
    "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": {
      "user_email": "john.doe@acme.com",
      "user_name": "John Doe"
    },
    "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([
  {
    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: {
      user_email: "john.doe@acme.com",
      user_name: "John Doe"
    },
    timestamp: "2024-01-15T10:30:00Z"
  }
]);

fetch("https://api.app.thrivestack.ai/api/identify", {
  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/identify"

payload = json.dumps([
  {
    "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": {
      "user_email": "john.doe@acme.com",
      "user_name": "John Doe"
    },
    "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/identify"
  method := "POST"

  payload := strings.NewReader(`[
  {
    "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": {
      "user_email": "john.doe@acme.com",
      "user_name": "John Doe"
    },
    "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