> ## Documentation Index
> Fetch the complete documentation index at: https://docs.semicola.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Product discovery

> Send one brief to every eligible seller, compare their proposals, refine, and stage the ones you want.

**Product discovery** turns a campaign brief into offers. Semicola sends the brief to every seller
that is eligible for the advertiser, in parallel, and collects what comes back: composed
**proposals** from sellers with a storefront agent, and **products** from sellers that answer from a
catalog.

## Request proposals

```json request_proposals theme={null}
{
  "campaignId": "cmp_01JB7P3K9Q2W5E8R1T4Y6U0I3O",
  "expectedCampaignRevision": 1,
  "evaluation": { "instructions": "Prefer premium CTV; keep display under a quarter of spend." },
  "idempotencyKey": "wrenfield-holiday-proposals-01"
}
```

The call returns immediately with an **execution**:

| Field         | Meaning                                                                              |
| ------------- | ------------------------------------------------------------------------------------ |
| `executionId` | `exe_…`. Use it to follow progress.                                                  |
| `status`      | `running`, then `complete`, `partial` (some sellers failed) or `failed`.             |
| `perSeller[]` | One entry per seller: `quoted` (proposals), `products` (catalog answer) or `failed`. |
| `summary`     | Counts: requested, quoted, with products, responded, failed and pending.             |

In the app and in MCP Apps hosts, the **Proposals** widget streams results as sellers answer, with a
progress line such as "Asked 9 sellers · 6 responded · 2 pending · 1 failed". Each seller has a bounded
time to answer; a slow seller is reported rather than holding up the rest. Only one execution runs per
buyer account at a time.

## Reading a proposal

| Field                 | Meaning                                                                             |
| --------------------- | ----------------------------------------------------------------------------------- |
| `proposalId`          | `sfp1:…`                                                                            |
| `name`, `description` | The seller's name and summary for the plan.                                         |
| `briefAlignment`      | Why the seller thinks the plan fits your brief.                                     |
| `allocations[]`       | Each product's share of budget, its role in the plan and the rationale.             |
| `totalBudgetGuidance` | Minimum, recommended and maximum spend, with currency.                              |
| `limitations[]`       | What the seller could not do. Read these before selecting.                          |
| `disposition`         | `pitch` or `counter_pitch` (the seller offers an alternative to part of the brief). |
| `expiresAt`           | After this the seller may no longer honor the pricing.                              |

## Refine

Ask one seller for a revised version without re-briefing everyone:

```json refine_proposal theme={null}
{
  "proposalId": "sfp1:larkstone:7f3c2a",
  "instructions": "Keep CTV only and shift $5,000 to audio.",
  "dropProductIds": ["larkstone-display-run-of-site"]
}
```

The seller answers with a new version and says which parts it applied, partly applied or could not
do.

## Select and stage

Staging turns a proposal into a draft media buy on the campaign. It contacts no seller and books
nothing:

```json save_media_buy theme={null}
{ "fromProposalId": "sfp1:larkstone:7f3c2a", "idempotencyKey": "wrenfield-holiday-stage-larkstone-01" }
```

You can also stage products directly with `campaignId`, `sellerId` and a `products` list of
`productId`, `pricingOptionId` and `budget`. When you are done, open **Review & go live**
(`open_campaign_receipt`) and launch as described in the [Campaign object guide](/buy/campaign#launch).
