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

# Connect your own proposal agent

> How a seller registers its own model as a proposal agent: the four proposal tasks it must answer, the brand.json entry that proves it is yours, and what changes for buyers.

A proposal agent answers buyers' proposal requests for a seller. When a seller
wants its own model to answer, instead of Chef, it connects that model to
Apostra as a proposal agent with `save_agent`.

> [!NOTE]
>
> For now, only Apostra's own accounts in the modular sales agent beta can
> register a proposal agent. Any other account, including a seller in the beta,
> that sends `kind: "proposal"` gets `FEATURE_NOT_ENABLED` with `details.reason`
> `own_proposal_agent_unavailable`, for a `dryRun: true` preview too, before
> Apostra reads the agent. For such an account, an agent that answers the four
> proposal tasks reads as a sales agent, and every other kind of agent connects
> as before. Registering your own opens to sellers later, as its own release,
> when you can choose which agent answers your buyers' proposal requests.

## What changes for buyers

Nothing yet. **Chef still answers every proposal request** until routing to a
seller's own agent is available. Connecting a proposal agent registers it and
checks it; it does not send it any buyer's request.

Choosing it is a separate setting: `save_seller` with `proposalAgent.answering`
set to `own` and the agent's id in `proposalAgent.ownAgentId`. Choosing `own` is
also open only to Apostra's own accounts for now. See
[Choose the brain that answers your buyers](https://docs.apostra.com/v3/seller-proposal-agent.md).

## What the agent must answer

Apostra reads the agent's `get_adcp_capabilities` without credentials and
connects it as a proposal agent only when:

* `supported_protocols` contains `media_buy`, and
* `media_buy.lifecycle_tools` lists all four proposal tasks:
  `request_proposals`, `refine_proposals`, `decline_proposals` and
  `accept_proposal`.

When a task is missing, the call is refused with `VALIDATION_ERROR`.
`details.reason` is `proposal_tasks_missing` and `details.missingTasks` names
each task the agent does not list. Add them to the agent and try again.

An agent that also lists `control_media_buy` reads as a sales agent that also
answers proposals, so its preview shows `kind: "sales"` with `proposal` in
`alternativeKinds`. An agent without it reads as a proposal agent, with `sales`
as the alternative. Either way, send `kind: "proposal"` to connect it as a
proposal agent.

`get_adcp_capabilities` must answer without credentials. Apostra does not
connect a proposal agent it could not read, because it cannot check the four
tasks.

## Who can connect one

For now, only Apostra's own accounts in the beta qualify (see the note above).
In such an account, a person who directly administers it, signed in as
themselves:

* in your **Seller account**, which owns the agent, or
* in your organization's **Agents account**, as for any other agent. See
  [Connect an agent in an Agents account](https://docs.apostra.com/v3/connect-an-agent.md).

Service tokens, delegated sessions and impersonation cannot connect an agent.

## Connect it

First preview what Apostra reads. Nothing is saved:

```json theme={null}
{
  "tool": "save_agent",
  "arguments": {
    "kind": "proposal",
    "agentUrl": "https://brain.northstar.example/mcp",
    "dryRun": true
  }
}
```

The preview returns the reading and `inferred.kind: "proposal"`. Then connect it
with an `idempotencyKey`, so a retry finds the first agent instead of making a
second one:

```json theme={null}
{
  "tool": "save_agent",
  "arguments": {
    "kind": "proposal",
    "agentUrl": "https://brain.northstar.example/mcp",
    "idempotencyKey": "7c1f0e2a-5b8d-4c39-9a61-2f4e8d0b1c73"
  }
}
```

You may send `displayName` to replace the name Apostra suggests. A proposal
agent has no sales mode and no first test.

## The credential Apostra presents

When Apostra calls your proposal agent, it presents a credential you enter on
the agent's page in the web app, never in chat. Do not paste a credential into
a conversation. Entering it on the agent's page is coming soon.

## Prove the agent is yours

Like every connected agent, a proposal agent is not verified as yours until
the `brand.json` on its own host lists it. AdCP's `brand.json` has no proposal
agent type, so list a proposal agent with `"type": "sales"`:

```json theme={null}
{
  "brands": [{ "id": "northstar", "names": [{ "en": "Northstar" }] }],
  "agents": [
    { "id": "northstar_brain", "type": "sales", "url": "https://brain.northstar.example/mcp" }
  ]
}
```

Everything else follows the same rules as any agent: the exact URL, the file on
the agent's own host, and a host on a domain your organization has verified.
See [Prove your agent is yours](https://docs.apostra.com/v3/connect-an-agent.md#prove-your-agent-is-yours).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.