---
title: "Generate a reply draft"
method: POST
path: "/inbox-ai/threads/{thread_id}/draft/"
tags: ["inbox-ai"]
---

# Generate a reply draft

`POST /inbox-ai/threads/{thread_id}/draft/`

## 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/inbox-ai/threads/{thread_id}/draft/`
- Auth: one of:
  - API key in header `X-API-Key`
  - HTTP bearer

Write a reply to the conversation's latest message for a person to approve. A conversation from a sequence is answered by that sequence's agent, exactly as it would answer on its own; any other conversation gets a reply in the default voice, which uses one of the workspace's daily AI Assistant turns. Either way the reply waits for a person. `steer_text` is a one-line instruction for this reply. Comes back empty when nothing usable was written, rather than with filler.

## Path parameters

- `thread_id` string, uuid, required

## Request body

- GenerateDraftSchema
  - `steer_text` string, nullable

## Response `200`

Successful Response

- AiDraftReadSchema
  - `ask_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': 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.
  - `body_text` string, required
  - `confidence` 'high' | 'medium' | 'low', required: How sure the model is. Shown on the card; no band sends without a person.
  - `confidence_reason` string, nullable, required
  - `confidence_score` integer, nullable: The model's 0-100 calibration, clamped into the categorical band. Null for drafts that predate the field. Presentation only: every decision reads the categorical confidence.
  - `generated_body_text` string, required
  - `id` string, uuid, required
  - `outbound_message_id` string, uuid, nullable: The agent's message this reply came from, when a sequence's agent wrote it. Edits, ratings and the send are recorded against that message too, which is how the agent learns from them. Null on a reply written in the default voice for a conversation outside any sequence.
  - `rating` 'good' | 'bad': The human verdict on a drafted reply. Two values, not five stars: a triaging human will click a thumb, not deliberate over a scale, and "good or bad" is all a feedback loop needs.
  - `send_after` string, date-time, nullable: When a `scheduled` reply goes out on its own, unless a person discards or edits it first. Kept once the reply is sending or sent. Null on a reply that was never scheduled, and on one taken off the schedule, by a person editing it or by a check that held it back for a person (see `ask_reason`).
  - `sent_by_kind` 'person' | 'system': Who composed an outbound message: a person, or the product itself. Only meaningful outbound, and NULL on anything inbound. The distinction exists because an agent-written reply has to stay attributable after the fact: "did a human send this" is the first question asked of any send that turns out to have been wrong, and a column is the only place that answer survives.
  - `source` 'auto_drafted' | 'on_demand', required
  - `status` 'pending_approval' | 'sent' | 'discarded' | 'stale' | 'scheduled' | 'sending' | 'send_unknown' | 'send_failed', required: Where one drafted reply stands. STALE is its own terminal state rather than a flavour of DISCARDED: "the prospect wrote again before anyone answered" and "a human said no" are different facts, and only the second one says anything about draft quality. The send states past SCHEDULED exist for the same reason SEND_UNKNOWN does: once a draft can leave without a person watching, "we do not know" has to be a state of its own. Collapsing it into SEND_FAILED would have a retry send the same reply twice; collapsing it into SENT would lose a reply silently.
  - `steer_text` string, nullable, required
  - `subject` string, nullable, required
  - `thread_id` string, uuid, required

## Other responses

- `401`: Unauthorized
- `403`: Forbidden
- `404`: Not found.
- `409`: The conversation's sequence has no audience table, so its agent has nothing to write from.
- `422`: Invalid request made to the API.
- `429`: The workspace has used today's AI Assistant allowance, or the AI Assistant is paused. Only a conversation outside any sequence uses the allowance.
- `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/dc5ac3c84444?raw)
