---
title: "Accept, edit, skip, re-record or abandon the question the user is on, and receive the next one."
method: POST
path: "/v1/advance_voice_interview"
tags: ["Voice Interviews"]
---

# Accept, edit, skip, re-record or abandon the question the user is on, and receive the next one.

`POST /v1/advance_voice_interview`

## Request

- Base URL: `https://partner.mindupload.app`
- URL: `https://partner.mindupload.app/v1/advance_voice_interview`
- Auth: API key in header `X-Partner-Key`

Records what the user decided about the question they are on, and returns the next one with its audio. Set `action` to `confirm` to accept the transcript as it stands, `edit` to accept text the user changed, `skip` to move on without answering, `re_answer` to discard the recording and be given the same question again, or `abort` to end the interview and discard it. `turn_index` must be the one you were last given: it makes this call safe to retry, because a repeat of a turn that already moved on is answered with the question the interview is on instead of consuming another one. Send `client_answer_id` as well, and a retry of an answer still being saved returns `is_processing`, while one after it was saved returns the reply the first request was given. `progress` runs from 0 to 1. When `is_complete` is true there are no more questions and you can ask for the write-up.

## Request body

- object
  - `preferred_language` string, nullable: BCP-47-ish language code (e.g. 'en', 'zh-cn') for localized messages.
  - `username` string, nullable: The end-user's username.
  - `password` string, nullable: The end-user's password on first sign-in. After login/register, send the returned session token (JWT) here instead — the field accepts either, and reusing the token keeps raw passwords out of your storage.
  - `interview_session_id` string, nullable: Identifies one interview. Returned by start_voice_interview and required by every later call.
  - `turn_index` integer, nullable: Which question this call is about. Send back the one you were last given; it makes the call safe to retry.
  - `action` 'confirm' | 'prepare' | 'finish_now' | 'edit' | 'skip' | 're_answer' | 'abort', nullable: What the user did with the question: `confirm` accepts the transcript unchanged, `edit` accepts text they corrected, `skip` moves on without an answer, `re_answer` discards the recording and re-serves the same question, and `abort` ends the interview and discards it. `skip`, `re_answer` and `abort` must not carry `confirmed_text`.
  - `confirmed_text` string, nullable: The answer text the user accepted, after any correction they made.
  - `client_answer_id` string, nullable: Optional. An id your app makes for this one answer, at most 64 characters, and sends again unchanged with every retry of it. With it, a retry that arrives while the answer is still being saved returns `is_processing` instead of an error, and one that arrives after it was saved returns the reply the first request was given. Make a new one for each answer.
  - `fact_corrections` object[], nullable
  - `review_dwell_milliseconds` integer, nullable

## Response `200`

Result envelope — check the success field.

- object
  - `success` boolean: Whether the call succeeded.
  - `error_message` string, nullable: Human-readable reason when success is false.
  - `error_code` string
  - `interview_session_id` string, nullable: Identifies one interview. Returned by start_voice_interview and required by every later call.
  - `template_key` 'mind_upload_first_time' | 'memory_refresh' | 'personality_refresh' | 'matchmaking' | 'guided_reflection', nullable: Which question set to run.
  - `language` string, nullable
  - `turn_index` integer, nullable: Which question this call is about. Send back the one you were last given; it makes the call safe to retry.
  - `question_text` string, nullable: The question the user is being asked, in the interview language.
  - `question_audio_url` string, nullable: A time-limited URL for the spoken question. Play it to the user.
  - `question_audio_content_type` string, nullable: Media type of the question audio, so a player can be chosen without sniffing.
  - `progress` number, nullable: How far through the interview the user is, from 0 to 1.
  - `is_complete` boolean, nullable: True when there are no further questions and the write-up can be requested.
  - `is_resumed` boolean, nullable: True when this picked up an interview the user had already started rather than beginning a new one.
  - `is_processing` boolean, nullable: True when this request repeated, by its `client_answer_id`, an answer that is still being saved. Nothing else in the reply describes a question: wait a moment and send the same request again to receive the reply the answer was given. Absent otherwise.
  - `status` 'in_progress' | 'safety_paused' | 'completed' | 'aborted' | 'halted_for_safety', nullable: Where the interview itself stands: `in_progress` while there are questions left, `completed` once the write-up can be asked for, `aborted` when the user ended it and the transcript was discarded, and `halted_for_safety` when an answer suggested the person needed help rather than another question -- on which show `safety_message` and stop asking. The new first interview instead uses `safety_paused`: its earlier confirmed answers are kept, the triggering answer is excluded, and questions remain paused.
  - `safety_message` string, nullable: Present only when the interview stopped because an answer suggested the person needed help rather than another question. Show it, and do not continue the interview.
  - `spoken_lines` object[], nullable: Present only on an interview made of spoken lines. Every line this reply says, in the order to play them, each with its `line_id` (null for a question written for this answer), its `line_role` (`anchor`, `chaser`, `statement`, `pivot`, `acknowledgement`, `backchannel`, `waiting`, `mirror`, `closing`, `follow_up`), its `text` in the interview language, and its `audio_url` and `audio_content_type`; a line with an empty `audio_url` is shown as text. The last line is the question, which `question_text` and `question_audio_url` carry too. Skip the first line when you have already played that `line_id`.
    - `line_id` string, nullable, required
    - `line_role` string, required
    - `text` string, required
    - `audio_url` string, required
    - `audio_content_type` string, required
  - `chapter_key` string, nullable: Present only on an interview made of spoken lines. Which chapter the question is in.
  - `chapter_title` string, nullable: Present only on an interview made of spoken lines. The chapter's title, in the interview language.
  - `chapter_index` integer, nullable: Present only on an interview made of spoken lines. Where the chapter comes, counting from 0; a new value means a new chapter has begun.
  - `chapter_count` integer, nullable: Present only on an interview made of spoken lines. How many chapters it has.
  - `minutes_left_estimate` integer, nullable: Present only on an interview made of spoken lines. Roughly how many minutes of answering are left, rounded up, from how long this user's answers have taken so far; 0 once it has ended.
  - `review_mode` 'auto' | 'confirm', nullable: Present only on an interview made of spoken lines. How the user accepts the transcript of their answer to the question: `auto` lets it through after a short pause unless they touch it, and `confirm` waits for them, as for a name or a date of birth, and for every answer once they have corrected one. Null when nothing is asked.
  - `learned_facts` object[], nullable: Present only on an interview made of spoken lines. The basic facts of their life the user has told it so far, each with its `slot`, its `display_value`, its `visibility` (`shared`, `general_only`, `owner_only`) and its `certainty` (`said`, `inferred`, `needs_confirmation`). This is the owner's review snapshot. Confirmed facts become consciousness knowledge; legacy visibility labels do not control what it may disclose.
    - `slot` string, required
    - `display_value` string, required
    - `visibility` string, required
    - `certainty` string, required
  - `prepared` boolean, nullable
  - `next_turn_kind` string, nullable
  - `safety_paused` boolean, nullable
  - `answered_count` integer, nullable

## Other responses

- `400`: Invalid request payload.
- `401`: Missing or invalid partner key.
- `403`: Partner is not authorized for this operation.
- `429`: Rate limit exceeded — retry later.
- `500`: Internal server error.

## Changes

- **2026-10-19** `0371bdf78533`: 1 warning, 18 info
  - added the new `safety_paused` enum value to the `status` response property for the response status `200`
  - added the new optional request property `client_answer_id`
  - added the new optional request property `fact_corrections`
  - added the new optional request property `review_dwell_milliseconds`
  - …15 more

[Operation history](https://skmtc.dev/mindupload/apis/mind-upload-partner-api/changes/v1/advance_voice_interview/post.md)

---

[API](https://skmtc.dev/mindupload/apis/mind-upload-partner-api.md) · [All operations](https://skmtc.dev/mindupload/apis/mind-upload-partner-api/llms.txt) · [OpenAPI document](https://skmtc.dev/mindupload/apis/mind-upload-partner-api/revisions/0371bdf78533?raw)
