---
title: "Read a page into a proposed brief"
method: POST
path: "/v1/engine/runs/propose"
tags: ["Drops"]
---

# Read a page into a proposed brief

`POST /v1/engine/runs/propose`

## Request

- Base URL: `https://aicontentdrop.com`
- URL: `https://aicontentdrop.com/v1/engine/runs/propose`
- Auth: HTTP bearer

Read one pasted product page and propose the fields a drop would start from. No drop is created and no credits move: the answer is a proposal to edit and then start from, so a wrong link leaves nothing behind. `confidence` carries a number for every field that was judged, including the ones that did not clear their threshold — a field with a number and no value means the page was read and no option won.

## Request body

- object
  - `url` string, uri, required: The page to read.

## Response `200`

Fields read from the page, for a person to confirm.

- DropProposal: Fields read from a pasted page, for a person to edit and then start a drop from. `brief` carries only the fields that cleared their threshold; `confidence` carries a number for every field that was judged, including the ones that did not clear.
  - `proposal` object, required
    - `source` 'url', required
    - `url` string, uri, required
    - `brief` DropBrief, required: What is being made, for what, how long, on which recipe. Every field is optional: a brief is filled in as it is settled.
      - `type` 'image' | 'video'
      - `goal` 'viral' | 'sales' | 'social'
      - `duration_s` 5 | 10 | 15 | 20 | 30 | 60: Running time in seconds. A still image has none.
      - `lane` 'cinematic' | 'ugc' | 'marketing'
      - `reference` object: Where the material comes from. `upload` carries its url and `template` its template id; a reference missing either is not one.
        - `kind` 'none' | 'upload' | 'template', required
        - `url` string, uri
        - `template_id` string
      - `model` object: A pinned model. Absent means the recipe's own default, revealed before anything is charged.
    - `confidence` object, required: Field name to a number between 0 and 1.
    - `brand` object
      - `name` string
      - `value_props` string[]
      - `cta` string
      - `tone` string
    - `screenshot_url` string, uri: The captured page on this application's own storage.
    - `note` string: One sentence when a field was dropped rather than proposed.

## 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).
- `422`: The page could not be read well enough to propose anything.
- `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.
- `503`: Reading pages is unavailable right now. Retry in a minute.

---

[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)
