Deal reaching the won stage, not from a manual blast — and clients respond on a tokenized public page that requires no login.
When surveys send
When a deal transitions to won, Winnerr emits aDEAL_WON system event. The reputation survey workflow listens for that event and:
- Looks up the active
SurveyTemplatematching the trigger (DEAL_WON). - Creates a
Surveyaddressed to the buyer or sellerPersonon the deal. - Generates a unique
accessTokenfor the public response page. - Schedules the send for
now + sendDelayHours(default 168 hours / 7 days after close).
Person + Deal pair from the Reputation Studio UI or via the reputation API.
Survey templates
ASurveyTemplate is your org-authored, reusable questionnaire. Each template carries:
| Field | Purpose |
|---|---|
name | Internal label shown in the template list. |
surveyType | NPS, CSAT, STAR, or CUSTOM. |
schema | JSON question definitions (validated with Zod), modeled on PortalForm.fields. |
triggerEvent | The system event that auto-schedules the survey, e.g. DEAL_WON. |
sendDelayHours | Delay from the trigger to first send. Defaults to 168 (7 days). |
channel | EMAIL or SMS. |
settings | Reminder cadence, branding overrides, expiry window. |
isActive | Inactive templates are not used by the auto-scheduler. |
Reminder ladder
By default, an unanswered survey triggers two reminder emails:- +3 days after the initial send.
- +7 days after the initial send.
Survey.reminderCount field tracks how many reminders have gone out. Surveys expire after expiresAt (default 30 days from creation), at which point reminders stop and the survey can no longer be answered.
The reminder copy is rendered from the same React Email templates as the initial request, with a softer “we’d still love to hear from you” tone.
Branded email
Survey emails (initial + reminders) are rendered through React Email and pull identity from the agent’s Brand Kit: logo, colors, brokerage info, compliance footer, and social links. The recipient sees:- The agent’s headshot and name.
- A one-tap CTA that opens the tokenized survey page.
- Brokerage info and compliance disclaimers in the footer.
The public response page
The survey link in the email opens an unauthenticated, tokenized page:- Resolves the survey strictly by
accessToken, server-side. - Returns the question schema plus minimal branding (brokerage name only — never agent PII, never other surveys).
- Marks the survey
OPENEDand emitsSURVEY_OPENED. - Returns a uniform
404for unknown, expired, completed, or skipped tokens so that guessing learns nothing.
SurveyResponse, flips the survey to COMPLETED, and emits SURVEY_COMPLETED. The response body is size-capped (64 KB) and rate-limited.
See the full request and response shapes in the public reputation endpoints.
From response to testimonial
When the response comes in, the reputation response consumer:- Stores the answers (
npsScore,csatScore,starRating, free text) onSurveyResponse. - Runs AI sentiment analysis and writes the score back to
SurveyResponse.sentiment. - If the client opted in (
testimonialOptIn) and the rating is high enough, promotes the response into aTestimonialrow with statusPENDINGand visibilityPRIVATE. - Captures the consent snapshot (use name, use photo, public) onto the testimonial.
Manual sends
To send a survey outside of the auto-trigger,POST /api/reputation/surveys with a templateId, recipientPersonId, agentUserId, and optional dealId. The endpoint generates a fresh accessToken, schedules the send, and emits the same downstream events as the auto-flow.
Survey lifecycle
| Status | Meaning |
|---|---|
SCHEDULED | Created and waiting for scheduledFor. |
SENT | Email or SMS dispatched. |
OPENED | Recipient opened the tokenized page. |
COMPLETED | A valid SurveyResponse was submitted. |
EXPIRED | Reached expiresAt without a response. |
BOUNCED | Delivery failed. |
SKIPPED | Manually cancelled. |
Related
- Testimonials — what happens after a high-rated response comes in.
- Reputation API — surveys — authenticated CRUD.
- Public survey endpoint — token-based public access.