UserSay/ Docs

Read UserSay from your agent

Read UserSay feedback and insights from your own AI agents.

UserSay exposes the same read-only data surface over HTTP and MCP. It is built for analysis: connect Claude, Cursor, or your own agent; let it inspect what users said and what Sarah distilled across sessions.

Tool surface

There are three tools:

ToolUse it for
get_contextList projects, then orient on one project: product context, watchlist, enabled Moments, data counts, available datasets.
query_dataSearch or list data from one dataset: feedback or insights.
get_itemOpen one result in full: a transcript or a signal with all its quotes.

query_data has two datasets:

DatasetContains
feedbackRaw sessions and transcript search hits.
insightsSignals distilled across sessions, with verbatim quotes.

The public surface is intentionally read-only. Project setup, Moment editing, and destructive operations stay in the dashboard.

Authentication

Generate an API key under Settings → Developers → API & MCP access. Keys start with us_live_.

Send the key in any of these places:

Authorization: Bearer <YOUR_USERSAY_KEY>
X-UserSay-Key: <YOUR_USERSAY_KEY>
?key=<YOUR_USERSAY_KEY>

Keys are user-scoped: they can read projects the key owner owns or has been invited to as a shared member. Rate limit is 120 calls/minute per key.

HTTP API

Base URL:

https://www.usersay.ai/api/v1

Call a tool by POSTing JSON to /api/v1/<tool>.

curl -X POST https://www.usersay.ai/api/v1/query_data \
  -H "X-UserSay-Key: <YOUR_USERSAY_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "projectSlug": "my-product",
    "dataset": "insights",
    "limit": 20
  }'

Errors return:

{ "error": "Invalid insight status", "validValues": ["active", "archived", "all"] }

MCP server

Hosted MCP URL:

https://www.usersay.ai/mcp?key=<YOUR_USERSAY_KEY>

Cursor-style config:

{
  "mcpServers": {
    "usersay": {
      "url": "https://www.usersay.ai/mcp",
      "headers": {
        "Authorization": "Bearer <YOUR_USERSAY_KEY>"
      }
    }
  }
}

The MCP server supports initialize, tools/list, and tools/call. Tool calls return both structuredContent and a text JSON fallback for older clients.

get_context

Use this first. Omit projectSlug to list accessible projects:

{}

Pass projectSlug to get project context:

{ "projectSlug": "my-product" }

Response includes:

{
  projects: Array<{
    slug: string;
    name: string;
    role: "owner" | "shared";
    productName: string | null;
    productDescription: string | null;
    installed: boolean;
  }>;
  currentProject?: {
    slug: string;
    name: string;
    productContext: string | null;
    founderLanguage: string;
    watchlist: {
      understanding: string[];
      conversion: string[];
      retention: string[];
      custom: string[];
    };
    enabledMoments: Array<{
      id: string;
      name: string;
      category: string;
      depth: "quick" | "deep";
      description: string;
    }>;
    counts: {
      sessions: number;
      terminalSessions: number;
      messages: number;
      signals: number;
    };
    datasets: Array<{ id: "feedback" | "insights" }>;
  };
}

query_data

Input:

{
  projectSlug: string;
  dataset: "feedback" | "insights";
  q?: string;
  since?: string;  // YYYY-MM-DD
  until?: string;  // YYYY-MM-DD
  kind?: string;
  status?: string;
  limit?: number;  // max 100
}

The meaning of kind and status depends on the dataset:

Datasetkindstatus
feedbackMoment id, such as cancel or a custom Moment idcompleted, abandoned, all
insightsSignal kind: problem, wish, persona, use_case, pricing, competitoractive, archived, all

Date filters are dataset-specific:

  • feedback uses terminal session completion dates in your configured timezone.
  • insights uses when the latest supporting quote was said by the user.

Examples:

{
  "projectSlug": "my-product",
  "dataset": "feedback",
  "q": "pricing refund",
  "since": "2026-07-01",
  "status": "all",
  "limit": 20
}
{
  "projectSlug": "my-product",
  "dataset": "insights",
  "kind": "problem",
  "status": "active",
  "limit": 30
}
{
  "projectSlug": "my-product",
  "dataset": "insights",
  "kind": "problem",
  "limit": 10
}

Response:

{
  project: { slug: string; name: string };
  dataset: "feedback" | "insights";
  summary: string;
  totals: Record<string, number>;
  items: Array<{
    id: string;
    type: "session" | "signal";
    title: string;
    summary: string | null;
    quote: string | null;
    occurredAt: string | null;
    status: string | null;
    kind: string | null;
    confidence?: string | null;
    dashboardUrl?: string;
    metadata?: Record<string, unknown>;
  }>;
}

get_item

Input:

{
  "projectSlug": "my-product",
  "id": "<id from query_data>"
}

get_item can return:

  • A full session transcript with insights and end-user metadata.
  • A signal with all its quotes and source session ids.

Use this in your agent prompt:

You have access to UserSay's MCP server.

Workflow:
1. Call get_context first. If there are multiple projects, ask which product to analyze.
2. Use query_data to inspect one dataset:
   - feedback: raw sessions and transcript search
   - insights: distilled signals
3. Use get_item only for the few results you need to verify with full evidence.
4. Prefer quotes and source session ids over vague summaries.
5. Do not ask UserSay to mutate project settings; this MCP surface is read-only.

Migration from the old tool list

The previous public surface exposed granular tools such as list_projects, query_sessions, get_signal, and create_moment. They were replaced by the three-tool read-only surface to reduce MCP model confusion and to make signals first-class analysis data.

Old → new:

Old toolNew path
list_projects, get_project_contextget_context
query_sessions, search_sessionsquery_data with dataset: "feedback"
get_sessionget_item
list_signals, search_signalsquery_data with dataset: "insights"
get_signalget_item

On this page