User Taste Understanding
Build a per-user taste profile and read it back, cluster the whole user base, and explain a user's taste in words.
Turn raw user activity into a portable read-out of what they like, and cluster your user base by taste for growth, sales, and marketing agents to act on.
Who this is for
AI Growth Agents, AI Sales Agents, and AI Marketing Agents that need a durable, queryable model of each user's taste.
The flow
- Create the user with
POST /v1/entity. - Log content the user engaged with using
POST /v1/index, each linked viaentity_id. - Read the user's entity back with
GET /v1/entity?entity_id=…. - Read cluster reads across the whole user base with
GET /v1/clustersandGET /v1/cluster. - Explain the user's taste in words with
POST /v1/explain.
entity_id on /v1/index is a link target, not a new id
On POST /v1/index, the entity_id in the request body is the user id you're attaching content to. The entity_id returned in the response is a new hashed id for the content item itself.
Phase 1 vs Phase 2 indexing
POST /v1/index returns synchronously (Phase 1). A background job (Phase 2, roughly 30 seconds) enriches name and description. If you GET /v1/entity?entity_id=… immediately, expect URL-host-based placeholder text until Phase 2 finishes.
Copy-paste walkthrough
export API_KEY="galya_..."
export USER_ID="shopper_jordan"
export BASE="https://api.galya.io/v1"1. Create the user
curl -sS -X POST "$BASE/entity" \
-H "X-API-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"id": "'"$USER_ID"'",
"type": "user",
"name": "Jordan",
"description": "Coastal minimalist."
}'2. Log content the user engaged with
curl -sS -X POST "$BASE/index" \
-H "X-API-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": {
"url": "https://store.example/oak-credenza",
"type": "text",
"content": "Low oak credenza, linen front, coastal minimalist.",
"skip_url_fetch": true
},
"entity_id": "'"$USER_ID"'"
}'Response 200:
{
"entity_id": "a1b2c3d4e5f6...",
"created": true
}3. Read the user entity back
GET /v1/entity uses a query param, not a path segment.
curl -sS "$BASE/entity?entity_id=$USER_ID" \
-H "X-API-Key: $API_KEY"Response 200:
{
"id": "shopper_jordan",
"name": "Jordan",
"description": "Coastal minimalist.",
"type": "user",
"linked_content": [],
"linked_entities": []
}linked_content and linked_entities are always returned as empty arrays on this endpoint; use the cluster endpoints below for cross-user reads.
4. Read taste clusters across the user base
List clusters (all params are optional):
curl -sS "$BASE/clusters?entity_type=content&limit=20&offset=0" \
-H "X-API-Key: $API_KEY"Response 200:
{
"results": [
{
"id": "cl_coastal_minimal",
"entity_type": "content",
"clustered_entities": []
}
]
}Fetch a single cluster:
curl -sS "$BASE/cluster?cluster_id=cl_coastal_minimal" \
-H "X-API-Key: $API_KEY"Response 200:
{
"id": "cl_coastal_minimal",
"entity_type": "content",
"clustered_entities": []
}Cluster shapes are returned verbatim from the workspace's cluster store; new workspaces may see empty results until enough content is indexed and composed.
5. Explain the user's taste in words
curl -sS -X POST "$BASE/explain?relative_to_entity_id=$USER_ID&in_terms_of_entity_type=content" \
-H "X-API-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"query": "Summarize this shopper taste: palette, materials, silhouette."
}'Response 200:
{
"explanation": "Jordan gravitates toward calm coastal palettes..."
}Optional query hints supported today: domain (discovery, design, decisions, data) and task (coding-agent, commerce-agent, design-agent, insight-agent).
Surfaces
Multiple ways to feed and read taste
The SDK, this REST API, a Galya Skill, and (coming soon) an MCP server are all valid surfaces for tracking user responsiveness. Pick whichever matches your agent stack.