UsersGET /api/v1/usersGET /api/v1/users/{userId}
Metering-side end users - their plan, lifetime events, 30-day events and cost, and first/last seen - sortable and pageable, plus a single-user deep-dive: current plan and subscription, quota counters for the current period, usage by event type, credit balances, attributes, recent events, and subscription history.
List users
curl "https://www.vevee.org/api/v1/users?sort=events_30d&dir=desc&page=1&pageSize=25" \
-H "Authorization: Bearer sk_live_YOUR_KEY"Parameters
| Name | Type | Description | |
|---|---|---|---|
sort | optional | last_seen | first_seen | events_30d | cost_30d | lifetime_events | user | Defaults to last_seen. |
dir | optional | asc | desc | Defaults to desc. |
page | optional | number | 1-based page number. Defaults to 1. |
pageSize | optional | number | 1 to 100. Defaults to 25. |
planId | optional | string | Filter to end users currently on this plan - accepts a plan id or plan name (case-insensitive). |
{
"ok": true,
"data": {
"users": [
{
"endUserId": "user_abc123",
"plan": {
"id": "plan_pro",
"name": "Pro",
"startedAt": "2026-05-14T08:02:11.000Z",
"endsAt": null
},
"lifetimeEvents": 3021,
"events30d": 412,
"cost30dCents": 8840,
"firstSeen": "2026-05-14T08:02:11.000Z",
"lastSeen": "2026-08-01T09:41:03.000Z"
},
{
"endUserId": "user_def456",
"plan": null,
"lifetimeEvents": 18,
"events30d": 0,
"cost30dCents": 0,
"firstSeen": "2026-04-02T14:20:44.000Z",
"lastSeen": "2026-04-10T11:03:22.000Z"
}
],
"total": 842,
"page": 1,
"pageSize": 25
}
}plan is null for end users with events but no subscription on file. AI-opted-out and pending-deletion end users are excluded from both the list and the total count.
Get a single user
curl https://www.vevee.org/api/v1/users/user_abc123 \
-H "Authorization: Bearer sk_live_YOUR_KEY"The KPI window and usageByEventType cover the trailing 30 days (see window.from / window.to in the response); counters reflects the current billing period per limit group; recentEvents and history are capped at the 20 most recent rows each.
{
"ok": true,
"data": {
"endUserId": "user_abc123",
"plan": {
"id": "plan_pro",
"name": "Pro",
"startedAt": "2026-05-14T08:02:11.000Z",
"endsAt": null
},
"kpis": {
"eventsInPeriod": 412,
"costInPeriodCents": 8840,
"lifetimeEvents": 3021,
"lastSeen": "2026-08-01T09:41:03.000Z"
},
"counters": [
{
"groupId": "lg_total_images",
"groupName": "Total images",
"unit": "count",
"quota": 500,
"count": 118,
"costCents": 0,
"pctUsed": 0.236
},
{
"groupId": "lg_llm_tokens",
"groupName": "LLM tokens",
"unit": "tokens",
"quota": 2000000,
"count": 812400,
"costCents": 8840,
"pctUsed": 0.4062
}
],
"usageByEventType": [
{ "eventType": "image.render", "count": 118, "costCents": 0 },
{ "eventType": "llm.tokens", "count": 294, "costCents": 8840 }
],
"credits": [
{
"balanceId": "crb_9a12f0",
"packId": "cpk_image_topup_50",
"packName": "50 image top-up",
"packItemId": null,
"kind": "generic",
"unit": "count",
"remaining": 32,
"initial": 50,
"grantedAt": "2026-07-01T00:00:00.000Z",
"expiresAt": "2026-10-01T00:00:00.000Z",
"status": "active",
"matches": [{ "event": "image.render" }],
"priority": 0
}
],
"attributes": { "plan": "pro", "goal": "lesson_planning" },
"recentEvents": [
{
"eventType": "llm.tokens",
"quantity": 812,
"costCents": 24,
"createdAt": "2026-08-01T09:41:03.000Z"
},
{
"eventType": "image.render",
"quantity": 1,
"costCents": 0,
"createdAt": "2026-08-01T09:12:47.000Z"
}
],
"history": [
{
"eventType": "plan_changed",
"fromPlanName": "Free",
"toPlanName": "Pro",
"occurredAt": "2026-05-14T08:02:11.000Z"
}
],
"window": {
"from": "2026-07-02T09:41:03.000Z",
"to": "2026-08-01T09:41:03.000Z"
}
}
}404 covers two different situations, indistinguishably. A user id that never existed and a user id belonging to an AI-opted-out or pending-deletion person both return the same
not_found (404) - the caller cannot tell them apart, by design.Prompt logs are never included. Neither the list nor the detail endpoint reads
event_logs - recentEvents carries event type, quantity, cost, and timestamp only, never a stored prompt or response.Errors
invalid_request(400) - out-of-range or non-numericpageorpageSize.invalid_key(401) - bad or revoked API key.requires_secret_key(403) - apk_*key was used.not_found(404) - unknown or excludeduserId(single-user endpoint only).
Related: the MCP server exposes the same two operations as
list_users and get_user - see MCP server.