List behavioral person profiles, filterable by customer-defined attributes, and get cohort distributions - for every declared attribute, the top value buckets, the long-tail count, and how many persons have no value set.
List persons
curl "https://www.vevee.org/api/v1/analytics/persons?attr.plan=pro&cols=plan,goal&limit=50" \
-H "Authorization: Bearer sk_live_YOUR_KEY"Parameters
| Name | Type | Description | |
|---|---|---|---|
attr.<key> | optional | string | Equality filter on a declared attribute, e.g. attr.plan=pro. Repeat for multiple attributes (AND'd together). Max 5 filters; extras are dropped. |
cols | optional | string | Comma-separated attribute keys to include in each person's attributes object. Max 20; invalid keys are silently skipped. Omit to leave attributes off the response entirely. |
cursor | optional | string | Opaque pagination token from a previous response's nextCursor. Treat it as an opaque string - do not parse or construct it. |
limit | optional | number | Page size, 1 to 100. Defaults to 50. |
{
"ok": true,
"data": {
"persons": [
{
"personId": "psn_7f3a2c",
"distinctId": "user_abc123",
"isIdentified": true,
"firstSeenAt": "2026-05-14T08:02:11.000Z",
"lastSeenAt": "2026-08-01T09:41:03.000Z",
"properties": { "email": "sam@example.com", "plan": "pro" },
"attributes": { "plan": "pro", "goal": "lesson_planning" }
},
{
"personId": "psn_1b9d40",
"distinctId": "user_def456",
"isIdentified": true,
"firstSeenAt": "2026-06-02T14:20:44.000Z",
"lastSeenAt": "2026-07-30T17:12:56.000Z",
"properties": { "email": "jo@example.com" },
"attributes": { "plan": "pro", "goal": null }
}
],
"nextCursor": "2026-07-30T17:12:56.000Z|psn_1b9d40"
}
}attributes is only present on each person when cols is passed. nextCursor is null on the last page. It is a composite lastSeenAt|personId string - always treat it as opaque and pass it back verbatim as cursor.
Attribute stats
Cohort distributions (“personas”): for every non-archived attribute declared on the app, the top value buckets by count, a long-tail otherCount, and how many persons in the cohort have no value set for it.
curl "https://www.vevee.org/api/v1/analytics/persons/attribute-stats?attr.plan=pro" \
-H "Authorization: Bearer sk_live_YOUR_KEY"Accepts the same attr.<key> filters as the list endpoint (max 5), used to narrow the cohort before computing distributions - omit them to see the whole app.
{
"ok": true,
"data": {
"totalPersons": 219,
"stats": [
{
"key": "goal",
"displayName": "Goal",
"type": "single_choice",
"setCount": 188,
"nullCount": 31,
"buckets": [
{ "value": "lesson_planning", "count": 96 },
{ "value": "grading", "count": 54 },
{ "value": "content_creation", "count": 38 }
],
"otherCount": 0
},
{
"key": "persona",
"displayName": "Persona",
"type": "single_choice",
"setCount": 219,
"nullCount": 0,
"buckets": [
{ "value": "teacher", "count": 171 },
{ "value": "student", "count": 48 }
],
"otherCount": 0
}
]
}
}totalPersons and the buckets. This is an aggregate, not a per-person view, so the same rule that applies to overview and subscriber stats applies here too.Errors
invalid_key(401) - bad or revoked API key.requires_secret_key(403) - apk_*key was used.
list_persons and get_attribute_stats - see MCP server.