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

NameTypeDescription
sortoptionallast_seen | first_seen | events_30d | cost_30d | lifetime_events | userDefaults to last_seen.
diroptionalasc | descDefaults to desc.
pageoptionalnumber1-based page number. Defaults to 1.
pageSizeoptionalnumber1 to 100. Defaults to 25.
planIdoptionalstringFilter 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.
i
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-numeric page or pageSize.
  • invalid_key (401) - bad or revoked API key.
  • requires_secret_key (403) - a pk_* key was used.
  • not_found (404) - unknown or excluded userId (single-user endpoint only).
i
Related: the MCP server exposes the same two operations as list_users and get_user - see MCP server.