Schema reference

The canonical Zod schemas live in @getsurvey/schema and are consumed by the web app, the SDK, and the MCP server. The shapes below are the inferred TypeScript types.

Survey

type Survey = {
  id: string;
  projectId: string;
  version: number;
  status: "draft" | "published" | "archived";
  title: string;
  description?: string;
  locale: string;            // BCP 47, default "en"
  questions: Question[];
  settings: { showProgressBar: boolean; allowAnonymous: boolean; thankYou?: { title: string; body?: string } };
  createdAt: string;
  updatedAt: string;
};

Question

Discriminated union on type. V1 ships eight types.

type Question =
  | { type: "short_text"; id: string; prompt: string; required: boolean; helpText?: string; maxLength?: number }
  | { type: "long_text";  id: string; prompt: string; required: boolean; helpText?: string; maxLength?: number }
  | { type: "single_select"; id: string; prompt: string; required: boolean; choices: Choice[]; randomize?: boolean }
  | { type: "multi_select";  id: string; prompt: string; required: boolean; choices: Choice[]; minSelections?: number; maxSelections?: number; randomize?: boolean }
  | { type: "likert"; id: string; prompt: string; required: boolean; scale: 3 | 5 | 7; labels?: { low: string; mid?: string; high: string } }
  | { type: "nps";    id: string; prompt: string; required: boolean; promptDetractor?: string; promptPromoter?: string }
  | { type: "star_rating"; id: string; prompt: string; required: boolean; max: 3 | 5 | 7 }
  | { type: "yes_no"; id: string; prompt: string; required: boolean; yesLabel?: string; noLabel?: string };

type Choice = { id: string; label: string; value?: string };

Response and Answer

type Answer =
  | { questionId: string; type: "short_text" | "long_text"; value: string }
  | { questionId: string; type: "single_select"; choiceId: string }
  | { questionId: string; type: "multi_select"; choiceIds: string[] }
  | { questionId: string; type: "likert"; value: number }
  | { questionId: string; type: "nps"; score: number }
  | { questionId: string; type: "star_rating"; stars: number }
  | { questionId: string; type: "yes_no"; value: boolean };

type Response = {
  id: string;
  surveyId: string;
  surveyVersionId: string;
  respondentId?: string;
  metadata?: Record<string, string>;
  startedAt: string;
  submittedAt?: string;
  answers: Answer[];
};

SurveySummary

The shape returned by summarizeResponses. Designed to drop directly into a downstream prompt.

type SurveySummary = {
  surveyId: string;
  surveyVersionId: string;
  totalResponses: number;
  completedResponses: number;
  generatedAt: string;
  questions: QuestionSummary[];
};

type QuestionSummary =
  | { type: "short_text"; ... samples: string[] }
  | { type: "long_text"; ... clusters: { theme; count; representativeQuotes }[] }
  | { type: "single_select" | "multi_select"; ... buckets: { choiceId; label; count }[] }
  | { type: "likert"; ... scale; buckets: number[]; mean }
  | { type: "nps"; ... score; promoters; passives; detractors }
  | { type: "star_rating"; ... max; buckets: number[]; mean }
  | { type: "yes_no"; ... yes; no };