REST API ↗
Core concepts

The interview journey

The whole experience is a state machine. Every UI — styled or custom — is just a switch on the current phase.

The phases

useInterview().phase is one of the following. The core advances them; you render one screen per phase.

PhaseMeaning
idleProvider mounted, nothing opened yet.
bootstrappingAuthenticating (token exchange).
readyAuthenticated, study not yet loaded.
studyFetching the study + its public config.
consentShowing consent; accept() creates the interview.
creatingInterviewCreating the interview record.
profileCollecting participant profile fields.
screenerRunning the screener question flow.
deviceCheckMic/camera preview before connecting.
connectingJoining the LiveKit room (may await screen share).
liveThe interview is running with the AI agent.
endingWrapping up the call.
processingServer-side processing after the call.
completedDone — completionToken on the payload (may be null).
screenedOutNot eligible; optional redirect URL.
studyClosedStudy not active or quota exceeded.
alreadyCompletedThis participant already finished.
abortedEnded early (declined, unload, host abort).
erroredA non-recoverable error occurred.

Reading the phase

tsx
const { phase, study, start, end } = useInterview(studyId);

switch (phase) {
  case 'consent':     return <Consent />;
  case 'screener':    return <Screener />;
  case 'deviceCheck': return <button onClick={start}>Start</button>;
  case 'live':        return <button onClick={end}>End</button>;
  case 'completed':   return <Thanks />;
  // …
}
Passing a studyId to useInterview(studyId) auto-opens the study on mount. The styled <Interview> does this for you.

Driving transitions

Most transitions are triggered by hook actions, not by you setting phase:

  • useConsent().accept() / decline() — leave consent.
  • useParticipantProfile().next() — leave profile.
  • useScreener().submit() — advance questions, then leave screener.
  • useInterview().start() — leave deviceCheckconnecting.
  • useInterview().end() — leave live.

Terminal phases

completed, screenedOut, studyClosed, alreadyCompleted, aborted, and errored are terminal. To run the journey again, remount the provider (e.g. bump a React key) for a fresh core. Recoverable errors expose useInterview().retry().