- Authenticated routes under
/api/reputation/*— bearer-token, org-scoped, used by the in-app Reputation Studio UI and your own integrations. - Public routes under
/api/public/{survey,reviews,referral}/*— unauthenticated, CORS-enabled where appropriate, used by tokenized survey pages, the embeddable reviews widget, and the public referral capture form.
401 behavior when userId or orgId are missing.
Authentication
Authenticated routes expect the standard bearer token forwarded byapps/app:
/api/public/...) require no auth. The capability is the survey accessToken or the published profile slug, and the server resolves the owning org server-side.
Testimonials
GET /api/reputation/testimonials
List testimonials in the caller’s org. Optional query params:
| Param | Values |
|---|---|
status | PENDING, APPROVED, PUBLISHED, REJECTED |
visibility | PRIVATE, INTERNAL, PUBLIC |
agentUserId | Filter to a specific agent |
category | BUYER, SELLER, INVESTOR, … |
{ testimonials: Testimonial[] }, ordered by sortOrder asc then createdAt desc.
POST /api/reputation/testimonials
Create a testimonial manually. Body fields include agentUserId, authorPersonId, dealId, source, category, rating, headline, body, display fields, and the three permission* flags. New entries always start PENDING + PRIVATE — they must still flow through approve → publish before they are public.
GET /api/reputation/testimonials/:id
Fetch one testimonial including its syndications.
PATCH /api/reputation/testimonials/:id
Partial update. Useful for editing copy, toggling isFeatured, reordering via sortOrder, or demoting visibility back to PRIVATE after publish.
POST /api/reputation/testimonials/:id/approve
Transition PENDING → APPROVED. Records approvedByUserId and approvedAt and emits REVIEW_APPROVED. Still not public.
POST /api/reputation/testimonials/:id/publish
Transition APPROVED → PUBLISHED, set visibility = PUBLIC, stamp publishedAt, emit REVIEW_PUBLISHED, and recompute the agent’s ReputationAggregate synchronously. Requires the testimonial to already be APPROVED — the call fails closed if the testimonial is still PENDING.
See Testimonials for the lifecycle in context.
Surveys
GET /api/reputation/surveys
List surveys in the caller’s org. Optional query params: status, agentUserId.
POST /api/reputation/surveys
Issue a new survey manually. Body:
accessToken, schedules the send, and emits SURVEY_SCHEDULED. The default expiry window is 30 days from creation.
Auto-scheduled surveys (from DEAL_WON) use the same code path — they do not require a client call.
Survey templates
| Method | Path | Purpose |
|---|---|---|
GET | /api/reputation/surveys/templates | List org-scoped SurveyTemplate rows. |
POST | /api/reputation/surveys/templates | Create a template. sendDelayHours defaults to 168 (7 days). |
Referrals
GET /api/reputation/referrals
List referrals in the caller’s org. Optional query params: status, agentUserId.
POST /api/reputation/referrals
Log a referral manually. Body fields include referrerPersonId, agentUserId, channel, referredName, referredContact, notes, and optional reward tracking (rewardType, rewardStatus, rewardValue).
When public capture creates a referral instead, the server emits REFERRAL_RECEIVED and the downstream workflow turns the referral into a Person with LeadSource.REFERRAL. See Referrals.
Profile
GET /api/reputation/profile
Fetch an AgentPublicProfile. Optional ?agentUserId=<id> returns that agent’s profile; otherwise returns the profile owned by the calling user.
PUT /api/reputation/profile
Upsert the calling user’s profile (or agentUserId if provided). Edits write into draftConfig — the live public page does not change until publish.
POST /api/reputation/profile/publish
Validate draftConfig against the approved-block schema, copy it into publishedConfig, flip status to PUBLISHED, and stamp publishedAt. Body is optional { "agentUserId": "..." }; defaults to the caller’s own profile.
Aggregate
GET /api/reputation/aggregate
Read the denormalized ReputationAggregate rollup.
?agentUserId=<id>returns that agent’s aggregate (scopeAGENT).- With no
agentUserId, returns the org-wide aggregate row (scopeORG, whereagentUserIdis null).
Public endpoints
The public routes are the surfaces that don’t require auth. The capability is the surveyaccessToken or the published profile slug, and the org is resolved server-side.
GET /api/public/survey/:token
Resolve a tokenized survey, return its question schema and minimal branding (brokerage name only — never agent PII, never other surveys), mark the survey OPENED, and emit SURVEY_OPENED.
Returns a uniform 404 ({ "state": "gone" }) for unknown, expired, completed, or skipped tokens so that guessing learns nothing.
POST /api/public/survey/:token
Submit a SurveyResponse. The body is validated against the template’s Zod schema, size-capped at 64 KB, and rate-limited. On success the server persists the response, flips the survey to COMPLETED, and emits SURVEY_COMPLETED. The reputation response consumer then runs sentiment analysis and (if the client opted in and rated highly) promotes the response into a PENDING Testimonial.
GET /api/public/reviews/:agentSlug
The JSON feed the embeddable Reviews Widget and the public profile read. Returns:
- Published, public testimonials for the agent (consent-allowed public fields only — display name, location, photo).
- The agent’s
ReputationAggregate. - Minimal profile branding.
Access-Control-Allow-Origin: *) and cached at the edge for one minute. Anything other than a PUBLISHED, non-deleted profile returns a uniform 404.
Embed:
POST /api/public/referral/:agentSlug
Capture a referral from the public profile or widget CTA. Body example:
Person, creates a Referral (status: RECEIVED, channel: PUBLIC_PROFILE), and emits REFERRAL_RECEIVED so the lead re-enters the pipeline. Rate-limited; body is capped at 32 KB.
Events emitted
The reputation routes emit the following system events on the standard event bus. Workflows inapps/api consume them.
| Event | Fired when |
|---|---|
DEAL_WON | (Upstream) The reputation survey workflow listens for this to auto-schedule a survey. |
SURVEY_SCHEDULED | A new Survey is created. |
SURVEY_OPENED | The tokenized public page is opened. |
SURVEY_COMPLETED | A SurveyResponse is submitted. |
REVIEW_APPROVED | A testimonial is moved to APPROVED. |
REVIEW_PUBLISHED | A testimonial is published to the public surface. |
REFERRAL_RECEIVED | A referral is captured (public or manual). |