MeshMesh
Analytics API

Endpoints

The Analytics and Usage API endpoints, their parameters, and response shapes

Every endpoint is GET, authenticated with a mesh_sk_ Bearer key, and wrapped in the standard { data, meta, next_cursor } envelope. All accept the shared start / end timeframe params; if omitted, they default to the last 90 days. meta.start / meta.end always reflect the window actually queried. The four /analytics/* endpoints need the analytics:read scope; /usage needs usage:read.


GET /users

Per-user analytics rows, one per user in your workspace. Cursor-paginated — follow next_cursor until it is null.

Query parameters

ParamTypeDefaultDescription
startISO datelast 90 daysStart of the timeframe.
endISO datelast 90 daysEnd of the timeframe.
cursorstringOpaque cursor from a previous next_cursor.
limitinteger (1–200)50Max rows per page.

Example response

{
  "data": [
    {
      "userId": "9c1f…",
      "email": "[email protected]",
      "name": "Ada Lovelace",
      "segment": "active",
      "firstLoginDate": "2026-03-02T09:14:00.000Z",
      "lastActivityDate": "2026-05-24T17:41:00.000Z",
      "firstTaskDate": "2026-03-02T10:01:00.000Z",
      "totalCreditsUsed": 412.5,
      "inputTokens": 1840221,
      "outputTokens": 290114,
      "agentCount": 7,
      "taskCount": 31,
      "uniqueTaskTypes": 4,
      "connectionCount": 2,
      "role": "member",
      "joinedAt": "2026-03-01T00:00:00.000Z"
    }
  ],
  "meta": { "start": "2026-03-01", "end": "2026-05-25", "has_more": true },
  "next_cursor": "MjAyNi0wMy0wMXw5YzFm"
}

segment is one of active, lapsed, or inactive. name, firstLoginDate, lastActivityDate, firstTaskDate, and role may be null.


GET /overview

Workspace totals, the user-segment distribution, and the onboarding funnel for the timeframe.

Query parameters

ParamTypeDefaultDescription
startISO datelast 90 daysStart of the timeframe.
endISO datelast 90 daysEnd of the timeframe.

Example response

{
  "data": {
    "summary": {
      "totalUsers": 48,
      "activeUsers": 31,
      "lapsedUsers": 9,
      "inactiveUsers": 8,
      "totalCreditsUsed": 12840.75,
      "avgCreditsPerUser": 267.52,
      "avgAgentsPerUser": 5.4,
      "avgTasksPerUser": 22.1
    },
    "segmentDistribution": [
      { "segment": "active", "count": 31, "percentage": 65 },
      { "segment": "lapsed", "count": 9, "percentage": 19 },
      { "segment": "inactive", "count": 8, "percentage": 17 }
    ],
    "funnel": [
      { "stage": "total", "label": "Total Users", "count": 48, "percentage": 100 },
      { "stage": "tier-0", "label": "1+ tasks", "count": 40, "percentage": 83 },
      { "stage": "tier-1", "label": "5+ tasks", "count": 28, "percentage": 58 },
      { "stage": "tier-2", "label": "10+ tasks", "count": 19, "percentage": 40 },
      { "stage": "tier-3", "label": "25+ tasks", "count": 9, "percentage": 19 },
      { "stage": "tier-4", "label": "50+ tasks", "count": 3, "percentage": 6 }
    ]
  },
  "meta": { "start": "2026-03-01", "end": "2026-05-25" },
  "next_cursor": null
}

segment is one of active, lapsed, or inactive. segmentDistribution[].percentage and funnel[].percentage are integers (rounded). Funnel stages are total (Total Users) followed by task-count tiers tier-0 (1+ tasks), tier-1 (5+), tier-2 (10+), tier-3 (25+), tier-4 (50+), and tier-5 (100+); only stages with a non-zero count are included.


GET /credits

Credit-burn timeseries plus a per-user credit leaderboard.

Query parameters

ParamTypeDefaultDescription
startISO datelast 90 daysStart of the timeframe.
endISO datelast 90 daysEnd of the timeframe.
granularityday | week | monthdayBucket size for the burn timeseries.

Example response

{
  "data": {
    "granularity": "day",
    "creditBurn": [
      { "period": "2026-05-23", "totalCredits": 218.4, "userCount": 12 },
      { "period": "2026-05-24", "totalCredits": 301.9, "userCount": 15 }
    ],
    "leaderboard": [
      { "userId": "9c1f…", "email": "[email protected]", "name": "Ada Lovelace", "totalCredits": 412.5 },
      { "userId": "3b7d…", "email": "[email protected]", "name": null, "totalCredits": 388.0 }
    ]
  },
  "meta": { "start": "2026-03-01", "end": "2026-05-25" },
  "next_cursor": null
}

leaderboard[].name may be null.


GET /engagement

Daily/weekly active-user counts, weekly cohort retention, and the weekly user-segment trend (active / lapsed / inactive).

Query parameters

ParamTypeDefaultDescription
startISO datelast 90 daysStart of the timeframe.
endISO datelast 90 daysEnd of the timeframe.

The dauWau series respects start/end. cohortRetention and segmentTrend are always computed over all-time data — they are not windowed by start/end.

Example response

{
  "data": {
    "dauWau": [
      { "date": "2026-05-23", "dau": 12, "wau": 28 },
      { "date": "2026-05-24", "dau": 15, "wau": 29 }
    ],
    "cohortRetention": [
      { "cohortWeek": "2026-03-02", "cohortSize": 11, "retention": [100, 82, 64, 55] },
      { "cohortWeek": "2026-03-09", "cohortSize": 8, "retention": [100, 75, 50] }
    ],
    "segmentTrend": [
      { "week": "2026-05-04", "active": 18, "lapsed": 4, "inactive": 2 },
      { "week": "2026-05-11", "active": 21, "lapsed": 3, "inactive": 2 }
    ]
  },
  "meta": { "start": "2026-03-01", "end": "2026-05-25" },
  "next_cursor": null
}

In cohortRetention, retention is a percentage array indexed by weeks since signup — index 0 is the signup week (always 100).

In segmentTrend, each week classifies every member who had joined by then: active (used the product that week), lapsed (active in an earlier week but not this one), or inactive (never active up to that week).


GET /usage

Raw per-call usage records for your workspace — one row per metered LLM call, including token counts, provider cost, and credits charged. Tenant-wide: rows for every user are returned, each tagged with userId / email. Cursor-paginated by (createdAt, id) — follow next_cursor until it is null.

This endpoint requires a key with the usage:read scope — separate from analytics:read, because it exposes per-call provider cost. Grant it when you mint the key.

Query parameters

ParamTypeDefaultDescription
startISO datelast 90 daysStart of the timeframe.
endISO datelast 90 daysEnd of the timeframe.
userIdstringNarrow to one user. Filtering only, not a permission.
modelstringNarrow to one model.
providerstringNarrow to one provider.
cursorstringOpaque cursor from a previous next_cursor.
limitinteger (1–200)50Max rows per page.

Example response

{
  "data": [
    {
      "tenantId": "org_9f…",
      "tenantName": "Acme Inc",
      "userId": "9c1f…",
      "email": "[email protected]",
      "model": "claude-opus-4-8",
      "provider": "anthropic",
      "promptTokens": 1840,
      "completionTokens": 290,
      "totalTokens": 2130,
      "cacheCreationInputTokens": 512,
      "cacheReadInputTokens": 1024,
      "providerCostUsd": "0.04821500",
      "creditsActual": "6.450000",
      "taskId": "22a1…",
      "createdAt": "2026-05-24T17:41:03.221Z"
    }
  ],
  "meta": { "start": "2026-03-01", "end": "2026-05-25", "has_more": true },
  "next_cursor": "MjAyNi0wNS0yNFQxNzo0MTowMy4yMjFafDIyYTE"
}

providerCostUsd and creditsActual are decimal strings (not numbers) to preserve full precision — parse them with a decimal library if you compute on them. taskId may be null for non-task calls.

The four Analytics endpoints above report consumption only — credits and tokens, never cost or markup. Per-call provider cost is available solely through GET /usage, which requires the usage:read scope.