---
title: "Steer a drop that is already working"
method: POST
path: "/v1/engine/runs/{id}/interject"
tags: ["Drops"]
---

# Steer a drop that is already working

`POST /v1/engine/runs/{id}/interject`

## Request

- Base URL: `https://aicontentdrop.com`
- URL: `https://aicontentdrop.com/v1/engine/runs/{id}/interject`
- Auth: HTTP bearer

Add a line to a drop that is already working, to steer the step in flight instead of waiting for it to finish. It is recorded on the transcript for the next turn to read rather than written to the drop, so it never fights the work in progress. A drop that has finished takes no more lines.

## Path parameters

- `id` string, uuid, required

## Request body

- object
  - `text` string, required: What to fold into the current step.

## Response `200`

The line was recorded.

- DropRunEnvelope: The drop after the write that was asked for.
  - `run` DropRun, required: One drop, as every caller sees it. `phase` is a property of the drop, never a place to navigate to; `revision` is bumped by every write and is what a conditional write is checked against.
    - `id` string, uuid, required
    - `title` string, required
    - `goal` string, required
    - `phase` 'intake' | 'research' | 'concept' | 'plan' | 'produce' | 'assemble' | 'distribute' | 'done', required
    - `status` 'idle' | 'running' | 'waiting_input' | 'waiting_approval' | 'failed' | 'done' | 'cancelled', required
    - `lane` 'cinematic' | 'ugc' | 'marketing' | 'null', nullable: Which recipe this drop follows. Null while the lane is still a question.
    - `approvalMode` 'confirm_each', required: confirm_each is the only mode served: the drop stops before every step that would charge credits.
    - `budgetCredits` integer, nullable, required: The credit ceiling for the whole drop, or null for none. Approving a step cannot lift it.
    - `creditsQuoted` number, required
    - `creditsSpent` number, required: Credits charged so far. Work that failed charges nothing.
    - `revision` integer, required
    - `canvasId` string, nullable, required: The board this drop builds its artifacts on, once it has one.
    - `error` string, nullable
    - `entities` DropEntities, required: Everything a drop has made, keyed by kind and then by id. An artifact enters once and is referenced afterwards, so ids stay stable for the life of the drop. Instructions sent to a producer, internal model ids and job references are not part of this projection and never appear.
      - `brief` object: The settled brief: what is being made, for what, how long, on which recipe.
      - `videos` object
      - `images` object
      - `ads` object
      - `research` object: Competitor rows read for this drop. Each carries `demo` and `analysed` so a sample row is never shown as an observed one.
      - `concepts` object: Angles, each bound to the research ids it rests on.
      - `storyboards` object
      - `boards` object: The board this drop builds on, with its link.
      - `quotes` object
    - `counters` DropCounter[], required
      - `word` 'retrieved' | 'analysed' | 'selected' | 'generated' | 'checked', required
      - `count` integer, required: The number of ids below.
      - `label` string, required: What was counted, in the words a person reads.
      - `coverage` string: How it was measured, when the word alone would overstate it.
      - `bucket` 'brief' | 'videos' | 'images' | 'ads' | 'research' | 'concepts' | 'storyboards' | 'boards' | 'quotes', required: Which bucket of this drop's artifacts the ids live in.
      - `ids` string[], required
    - `shared` boolean, required: Whether this drop currently has a share link. The address itself is returned only to the POST that minted it.
    - `createdAt` string, date-time, required
    - `updatedAt` string, date-time, required

## Other responses

- `400`: The body was rejected. `code` names the class of problem and `details` names the fields.
- `401`: Missing, malformed, revoked, or budget-exhausted API key
- `404`: No drop with that id on this account — or the whole surface is absent, which is what an account that is not enabled for drops sees. Drops are available to accounts enabled for them; on those accounts every path below answers `{"error":{"code":"not_found"}}` and nothing else, so an unlisted caller cannot tell an enabled surface from an absent one. On an enabled account, this is a drop id that does not exist or is not yours.
- `409`: The drop is not in a state that allows this. `code` says which: `RUN_BUSY` (it is working on the last message), `RUN_FINISHED`, `REVISION_CONFLICT` (it changed while your request was in flight — read it again and repeat), `TASK_NOT_AWAITING_APPROVAL`, `QUOTE_UNKNOWN` (that step has no priced quote yet), or `QUOTE_EXPIRED` (the price lapsed, so nothing was released).
- `429`: Rate limited. Read Retry-After (header) or error.retry_after_seconds (body) — they carry the same number — and wait that long. Retrying sooner extends the window rather than shortening it.
- `500`: Unexpected failure on our side. Retry once; nothing was charged.

---

[API](https://skmtc.dev/aicontentdrop/apis/ai-content-drop-api.md) · [All operations](https://skmtc.dev/aicontentdrop/apis/ai-content-drop-api/llms.txt) · [OpenAPI document](https://skmtc.dev/aicontentdrop/apis/ai-content-drop-api/revisions/75a13a8043ae?raw)
