Hebbrix
Profiles

User Profiles

Build rich user profiles through dialectic conversations. Hebbrix learns user preferences, interests, and personality traits to provide personalized AI experiences.

How Profiles Work

Automatic Learning

Profiles are built automatically from conversations. Every interaction adds to the user's profile.

Dialectic Chat

Use the dialectic endpoint to have focused conversations that extract specific profile information.

Profile Fields

Profiles can store any structured data. Common fields include:

name
preferences
interests
expertise
communication_style
goals
timezone
language
industry
role
personality_traits
custom_fields

Endpoints

Per-Fact CRUD

Beyond the bulk PATCH, every profile fact can be read, created, edited, or removed individually. Each of these also honours the multi-tenant collection_id scoping described below.

Code Examples

Get User Profile

Python
import requests

# GET /v1/profile
# Flat convenience fields (name/timezone/language) live at the top
# level; all other facts sit under the "profile.static" and
# "profile.dynamic" buckets.
r = requests.get(
    "https://api.hebbrix.com/v1/profile",
    headers={"Authorization": "Bearer <your-api-key>"},
)
data = r.json()

print(f"Name: {data.get('name')}")
print(f"Timezone: {data.get('timezone')}")
print(f"Language: {data.get('language')}")

# Every other fact lives under profile.static (long-lived) or
# profile.dynamic (short-lived). Each entry is {key, value, confidence, ...}.
for fact in data["profile"]["static"]:
    print(f"  static · {fact['key']} = {fact['value']}")
for fact in data["profile"]["dynamic"]:
    print(f"  dynamic · {fact['key']} = {fact['value']}")

Dialectic Conversation

Python (Dialectic)
import requests

# POST /v1/profile/dialectic — ask natural-language questions about the user.
# Send the prompt as `user_message` (preferred); legacy `message` / `question`
# are still accepted.
r = requests.post(
    "https://api.hebbrix.com/v1/profile/dialectic",
    headers={"Authorization": "Bearer <your-api-key>"},
    json={"user_message": "What are this user's main professional interests?"},
)
body = r.json()

# Preferred response fields
print(body["assistant_message"])   # the LLM answer
print(body["session_id"])          # echo back in the next turn for continuity

# Legacy alias (same value as assistant_message)
# body["response"] is also available for older integrations.

# Continue the conversation — reuse session_id to link turns
r2 = requests.post(
    "https://api.hebbrix.com/v1/profile/dialectic",
    headers={"Authorization": "Bearer <your-api-key>"},
    json={
        "user_message": "Tell me more about how they like to communicate.",
        "session_id": body["session_id"],
    },
)

Update Profile Manually

Python (Manual Update)
import requests

# PATCH /v1/profile — bulk-update profile facts. Body is a flat
# {fact_key: fact_value} dict. Existing facts are updated; new ones
# are created as "static" / "other" automatically.
r = requests.patch(
    "https://api.hebbrix.com/v1/profile",
    headers={"Authorization": "Bearer <your-api-key>"},
    json={
        "name": "John Doe",
        "timezone": "UTC",
        "language": "en",
        "role": "Senior Engineer",
        "company": "Acme Inc",
    },
)

body = r.json()
print(body["status"])     # "success"
print(body["updated"])    # count of facts updated in place
print(body["created"])    # count of new facts created
print(body["message"])    # e.g. "Updated 3, created 2 profile facts"

cURL Example

GET/v1/profile
curl -X GET "https://api.hebbrix.com/v1/profile" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json"

Profile Injection in Chat

When using the chat completions endpoint, profile data is automatically injected:

Python
import os
import requests

BASE = "https://api.hebbrix.com/v1"
H = {"Authorization": f"Bearer {os.environ['HEBBRIX_API_KEY']}"}

# POST /v1/chat/completions — set features.user_profile=True to have
# the backend inject profile facts into the context automatically.
r = requests.post(
    f"{BASE}/chat/completions",
    headers=H,
    json={
        "model": "gpt-5-nano",
        "messages": [
            {"role": "user", "content": "Recommend a book for me"},
        ],
        "features": {
            "memory": True,
            "user_profile": True,  # inject profile context
        },
    },
)

# The assistant sees the caller's profile and gives a personalized answer
print(r.json()["choices"][0]["message"]["content"])

Multi-Tenant Scoping (collection_id)

If you run a multi-tenant SaaS where many end-users share one Hebbrix account, you can keep each end-user's profile isolated by tagging their facts to a per-end-user collection_id. A scoped read returns only the facts belonging to that collection, so one end-user's profile never leaks into another's.

Isolation model

  • A fact written without a collection_id is account-wide (legacy / global).
  • A scoped read (with collection_id) returns only facts tagged to that collection or derived from its memories.
  • Omitting collection_id everywhere keeps the legacy account-wide behavior — fully backward compatible.

Where it applies

GET /v1/profile, GET /v1/profile/facts (query param), PATCH /v1/profile and POST /v1/profile/facts (body key).

Preview before you write

Send dry_run: true on PATCH /v1/profile to get a preview of the planned changes (would_update / would_create) without persisting anything.

Scoped Write with Dry-Run Preview

Python (Multi-Tenant Scoping)
import requests

BASE = "https://api.hebbrix.com/v1"
H = {"Authorization": "Bearer <your-api-key>"}

# Each end-user in your SaaS gets their own collection id.
COLLECTION = "coll_123"

# 1) PREVIEW — dry_run returns the planned changes WITHOUT persisting.
preview = requests.patch(
    f"{BASE}/profile",
    headers=H,
    json={
        "role": "Product Manager",
        "timezone": "America/New_York",
        "collection_id": COLLECTION,  # reserved key — scopes the facts
        "dry_run": True,              # reserved key — preview only
    },
).json()

print(preview["status"])         # "preview"
print(preview["would_update"])   # N facts that would be updated in place
print(preview["would_create"])   # N facts that would be created
print(preview["collection_id"])  # "coll_123"
print(preview["changes"])        # [...] per-fact diff, nothing written yet

# 2) REAL WRITE — drop dry_run (or set it False) to persist the facts,
#    tagged to this end-user's collection so they stay isolated.
written = requests.patch(
    f"{BASE}/profile",
    headers=H,
    json={
        "role": "Product Manager",
        "timezone": "America/New_York",
        "collection_id": COLLECTION,
    },
).json()
print(written["status"])   # "success"
print(written["updated"], written["created"])

# 3) SCOPED READ — only facts for this collection come back; another
#    end-user's profile never leaks in.
profile = requests.get(
    f"{BASE}/profile",
    headers=H,
    params={"collection_id": COLLECTION},
).json()

for fact in profile["profile"]["static"]:
    print(f"  {fact['key']} = {fact['value']}")

Assistant

Ask me anything about Hebbrix