---
title: "Keep threads already written on the AI writing tab"
method: POST
path: "/sequences/{sequence_id}/agent/training/previews/"
tags: ["sequences"]
---

# Keep threads already written on the AI writing tab

`POST /sequences/{sequence_id}/agent/training/previews/`

## Request

- Base URL: `https://api.getoneprofile.ai` (the document declares no server; this is the origin it was published from)
- URL: `https://api.getoneprofile.ai/sequences/{sequence_id}/agent/training/previews/`
- Auth: one of:
  - API key in header `X-API-Key`
  - HTTP bearer

Makes the threads already written as free previews for up to ten contacts those contacts' threads on the sequence's AI writing tab, word for word: nothing is written again, nothing is charged and no preview allowance is spent, so each contact's thread there shows the emails the previews showed and Looks good can be given on them. A step with no current preview shows as not written. The contacts join the sequence's open writing check; one already in it with the same words keeps its verdict. This never writes: the start route is what writes a thread. The answer names any kept thread written before the plain-words check that uses banned jargon or copies the business context, so it can be written again.

## Path parameters

- `sequence_id` string, uuid, required

## Request body

- SequenceTrainingAdoptSchema
  - `record_ids` string[], required: The audience rows whose threads were already written as previews, between one and ten different ones.

## Response `200`

Successful Response

- SequenceTrainingPreviewsReadSchema: The writing check once it keeps threads already written, and which of them to write again.
  - `session` SequenceTrainingReadSchema, required
    - `agent_id` string, uuid, required
    - `applied_version` integer, nullable, required
    - `base_version` integer, required
    - `contacts` SequenceTrainingContactReadSchema[], required
      - `context` object, required
      - `fields` SequenceTrainingContactFieldSchema[], required: The contact's own columns as the run froze them, read the way the approval queue lists a contact: each fact once, a whole-record column opened into its facts.
        - `name` string, required
        - `value` string, required
      - `label` string, required
      - `messages` SequenceTrainingMessageReadSchema[], required
        - `authored` boolean, required
        - `body` string, nullable, required
        - `conditional` string, nullable, required
        - `edited_body` string, nullable, required
        - `edited_subject` string, nullable, required
        - `error` string, nullable, required
        - `facts_used` string[], required
        - `id` string, uuid, required
        - `kind` string, required
        - `looks_good` boolean: These very words are marked Looks good, so they are what sends: by the thread's Looks good, or on their own from the Builder, which marks one email at a time.
        - `note` string, required
        - `previous_body` string, nullable, required
        - `previous_subject` string, nullable, required
        - `proposed_body` string, nullable: The words the rewrite waiting on this contact wrote.
        - `proposed_error` string, nullable: Why the rewrite could not write this message.
        - `proposed_send` SequenceTrainingSendSchema: Whether a message would leave on its own when its turn comes, and if not, why.
          - `alone` boolean, required: True when the send would let these words go without a person; false when they would wait for approval in Tasks.
          - `doubt` string, nullable: When the words themselves hold the message (the agent was not confident, knew too little, or a check found something): one sentence saying what. Null otherwise.
          - `reason` 'low_confidence' | 'findings' | 'insufficient_data' | 'policy' | 'always_ask' | 'sequence_manual' | 'step_requires_approval' | 'daily_cap' | 'unverified_sender' | 'suppressed' | 'different_sender' | 'label' | 'question' | 'consecutive_cap' | 'thread_cap' | 'hourly_cap' | 'org_daily_cap' | 'stale_inbound' | 'sequence_gone' | 'bot_question' | 'automated_counterparty' | 'kill_switch' | 'authentication' | 'language' | 'linkedin_only' | 'send_interrupted' | 'sender_switched_to_manual', required: Why a message that could have sent unattended was put in front of a person. One vocabulary for every gate between an agent writing a message and the message leaving: what the agent itself said about the draft (``LOW_CONFIDENCE``, ``FINDINGS``, ``INSUFFICIENT_DATA``, ``POLICY``), what the sender or the cadence asked for (``ALWAYS_ASK``, ``SEQUENCE_MANUAL``, ``STEP_REQUIRES_APPROVAL``), what the pacing rules refused (``DAILY_CAP``, ``CONSECUTIVE_CAP``, ``THREAD_CAP``, ``HOURLY_CAP``, ``ORG_DAILY_CAP``), what the mailbox or the thread made unsafe (``UNVERIFIED_SENDER``, ``DIFFERENT_SENDER``, ``LABEL``, ``QUESTION``, ``STALE_INBOUND``, ``SEQUENCE_GONE``), and what the counterparty turned out to be (``BOT_QUESTION``, ``AUTOMATED_COUNTERPARTY``, ``AUTHENTICATION``, ``LANGUAGE``, ``LINKEDIN_ONLY``). ``KILL_SWITCH`` is the platform switch that stops unattended sending outright, and ``SEND_INTERRUPTED`` an unattended reply whose send never got as far as a provider. ``SENDER_SWITCHED_TO_MANUAL`` is a LinkedIn step queued unasked that went back to a person because its sender switched to manual before it ran. Stored on the task so the queue can say why each row is there, and so "why did nothing send" is answerable by counting rows rather than by reading logs.
        - `proposed_subject` string, nullable: The subject the message sends with once the rewrite waiting on this contact is kept: the rewrite's own, or the subject typed on the step, which a rewrite keeps.
        - `reasoning` string, nullable, required
        - `reply_to_step_id` string, uuid, nullable, required: The step whose thread this message replies in, or null when it opens a thread of its own.
        - `send` SequenceTrainingSendSchema: Whether a message would leave on its own when its turn comes, and if not, why.
          - `alone` boolean, required: True when the send would let these words go without a person; false when they would wait for approval in Tasks.
          - `doubt` string, nullable: When the words themselves hold the message (the agent was not confident, knew too little, or a check found something): one sentence saying what. Null otherwise.
          - `reason` 'low_confidence' | 'findings' | 'insufficient_data' | 'policy' | 'always_ask' | 'sequence_manual' | 'step_requires_approval' | 'daily_cap' | 'unverified_sender' | 'suppressed' | 'different_sender' | 'label' | 'question' | 'consecutive_cap' | 'thread_cap' | 'hourly_cap' | 'org_daily_cap' | 'stale_inbound' | 'sequence_gone' | 'bot_question' | 'automated_counterparty' | 'kill_switch' | 'authentication' | 'language' | 'linkedin_only' | 'send_interrupted' | 'sender_switched_to_manual', required: Why a message that could have sent unattended was put in front of a person. One vocabulary for every gate between an agent writing a message and the message leaving: what the agent itself said about the draft (``LOW_CONFIDENCE``, ``FINDINGS``, ``INSUFFICIENT_DATA``, ``POLICY``), what the sender or the cadence asked for (``ALWAYS_ASK``, ``SEQUENCE_MANUAL``, ``STEP_REQUIRES_APPROVAL``), what the pacing rules refused (``DAILY_CAP``, ``CONSECUTIVE_CAP``, ``THREAD_CAP``, ``HOURLY_CAP``, ``ORG_DAILY_CAP``), what the mailbox or the thread made unsafe (``UNVERIFIED_SENDER``, ``DIFFERENT_SENDER``, ``LABEL``, ``QUESTION``, ``STALE_INBOUND``, ``SEQUENCE_GONE``), and what the counterparty turned out to be (``BOT_QUESTION``, ``AUTOMATED_COUNTERPARTY``, ``AUTHENTICATION``, ``LANGUAGE``, ``LINKEDIN_ONLY``). ``KILL_SWITCH`` is the platform switch that stops unattended sending outright, and ``SEND_INTERRUPTED`` an unattended reply whose send never got as far as a provider. ``SENDER_SWITCHED_TO_MANUAL`` is a LinkedIn step queued unasked that went back to a person because its sender switched to manual before it ran. Stored on the task so the queue can say why each row is there, and so "why did nothing send" is answerable by counting rows rather than by reading logs.
        - `steps` AiStep[], required
          - `action` string, required: What kind of move this was, e.g. `read_table`, `plan`, `write_column`.
          - `detail` string: The step's input: the instruction, the column it read, the query it ran.
          - `duration_ms` integer, nullable: Wall clock for the work this step describes, never an estimate.
          - `observation` string: One line on what came back. The half that makes a step worth reading.
          - `outcome` string: `completed`, `failed`, `refused` or `stopped`. Clients must tolerate new tokens.
          - `thought` string, nullable: The model's stated reasoning for choosing this step. Set by the agent loop; the assistant surfaces leave it null, and the renderer simply omits the rung.
        - `subject` string, nullable, required
        - `timing` string, required
        - `title` string, required
      - `note` string, required
      - `notes` SequenceTrainingNoteReadSchema[]: Every note given on this thread, oldest first.
        - `note` string, required
        - `state` 'pending' | 'applied' | 'discarded' | 'settled', required: Where one note stands: being answered, learned, thrown away, or answered with no change.
      - `notice` string, nullable: The agent's answer to a note that needed no change to its instructions, in its own sentence: usually a note about this contact's own facts.
      - `profile_mismatch` string, nullable: What the contact's LinkedIn profile says that their row does not, usually a job change the row has not caught up with, as one sentence: 'LinkedIn says Operations Leader at Chamber Media; the row says Sealed.' Null when they agree or no profile was read.
      - `record_id` string, uuid, required
      - `sender_profile_id` string, uuid, nullable: The sender these messages were written as, when the run chose one: where a message held because this sender always asks is changed.
      - `verdict` 'good' | 'bad' | 'skipped', required: Only an explicit review counts as feedback.
    - `created_at` string, date-time, required
    - `error` string, nullable, required
    - `id` string, uuid, required
    - `note_waiting` boolean: A note was given while another contact was being written: its rewrite is worked out as soon as that write lands.
    - `progress` SequenceTrainingProgressSchema, required: How training on this sequence is going, counted across the run.
      - `fixed` integer, required: Lessons kept in this run.
      - `in_a_row` integer, required: Contacts given Looks good, with no note, since the last note.
      - `lessons` string[], required: Each lesson kept, in the agent's own sentence, oldest first.
      - `ready` boolean, required: Whether in_a_row has reached ready_after.
      - `ready_after` integer, required: How many in a row make the agent ready to send on its own.
      - `reviewed` integer, required: Contacts given Looks good or a note in this run.
    - `proposal` ContactTrainingProposal, required: The session's candidate prompt update, kept pending until applied.
      - `changes` ContactPromptChange[]
        - `current` string, required
        - `proposed` string, required
        - `rationale` string, required
        - `slot_key` string, required
      - `made_at` integer
      - `record_id` string, uuid, nullable
      - `round_ids` string[]
      - `summary` string, required
    - `reviewed_ids` string[]: Every contact given Looks good or a note in this run, including ones that left the run to make room.
    - `revision` integer, required
    - `status` 'running' | 'reviewing' | 'proposing' | 'proposed' | 'completed' | 'abandoned', required: A session's phase, also used to resume its review screen.
    - `steps` AiStep[]
      - `action` string, required: What kind of move this was, e.g. `read_table`, `plan`, `write_column`.
      - `detail` string: The step's input: the instruction, the column it read, the query it ran.
      - `duration_ms` integer, nullable: Wall clock for the work this step describes, never an estimate.
      - `observation` string: One line on what came back. The half that makes a step worth reading.
      - `outcome` string: `completed`, `failed`, `refused` or `stopped`. Clients must tolerate new tokens.
      - `thought` string, nullable: The model's stated reasoning for choosing this step. Set by the agent loop; the assistant surfaces leave it null, and the renderer simply omits the rung.
  - `write_again` string[], required: Contacts whose kept thread was written before the plain-words check and uses jargon the writing rules forbid or a business context sentence word for word. Writing them again (the step preview with fresh) replaces those words; the AI writing tab shows the thread as it is meanwhile.

## Other responses

- `401`: Unauthorized
- `403`: Forbidden
- `404`: Sequence, audience contact, or session not found
- `409`: Sequence, agent, or training revision changed
- `422`: Invalid selection, feedback, or training action
- `500`: Internal server error.
- `502`: Bad gateway error.
- `503`: Service unavailable.

---

[API](https://skmtc.dev/getoneprofile/apis/api-reference-oneprofile.md) · [All operations](https://skmtc.dev/getoneprofile/apis/api-reference-oneprofile/llms.txt) · [OpenAPI document](https://skmtc.dev/getoneprofile/apis/api-reference-oneprofile/revisions/4a6bd71e3f02?raw)
