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

# Build an agent

> Connect an external runtime, discover sellers, and build a buying loop that survives retries and human approvals.

Build the first version as a read-only client, then add one durable buying step
at a time. Your application runs the agent and stores workflow progress.
Apostra keeps the advertising objects, contacts eligible sellers, executes
supported transactions, and returns delivery.

Complete [the connection quickstart](/v3/quickstart) first. This guide describes
the application architecture; the [buyer workflow reference](/v2/setup/v3/buyer-workflows)
contains the exact current request shapes for each buying step.

## Start with seller discovery

To practise without credentials, use the [local planning exercise](/v2/guides/buyer-first-value-rehearsal).
It checks fictional data and produces a local receipt; it does not complete the
connected steps below.

1. Connect an MCP client to `/mcp/v3` and authenticate.
2. Call `get_status`; verify the intended Buyer Account before using its data.
3. Read `tools/list` and expose only the tools your prototype needs to its model.
4. Call `search` with `{"kind":"seller","limit":10}`. Follow returned cursors
   if you need the complete list.
5. Display the sellers and their returned readiness and connection information.
   Keep missing or blocked states visible.

This discovery read does not request proposals. `request_proposals` is a later
step that sends a campaign brief to the eligible seller cohort. It should run
only when the user has asked your application to start that buying workflow.

Use the structured result for IDs and readiness. A model can explain the result
but should not reconstruct qualified identifiers or extract them from prose.

### Connect a seller when the workflow needs it

Read the selected seller's connection and activation state before requesting
offers. Use `search` or `get` for existing `connection` records and the current
`save_connection` schema for the required selection, billing, authorization,
provider-account choice, or advertiser mapping. An authorization action returns
a browser URL; provider credentials do not belong in the tool arguments.

After the person completes any required browser step, re-read the seller and
connection. A listed seller is not necessarily ready for this advertiser to
buy from. The [buyer workflow](/v2/setup/v3/buyer-workflows) explains these
readiness checks before campaign authoring and proposal requests.

## Give the loop a durable owner

For a production hybrid application, keep these records outside the model's
conversation:

| Record                                                         | Why it survives a turn or process restart                                     |
| -------------------------------------------------------------- | ----------------------------------------------------------------------------- |
| Active account and advertiser IDs                              | Resumed work must stay inside the same authorized scope.                      |
| Campaign, creative, proposal, product-query, and media-buy IDs | The application can re-read current objects instead of recreating them.       |
| Revision and exact write arguments                             | A retry can distinguish an unchanged request from a new decision.             |
| Idempotency key per logical operation                          | A lost response does not justify starting the same operation with a new key.  |
| Proposal execution status and result cursor                    | Seller responses can continue across multiple calls and pages.                |
| Approval of a specific draft and its revision                  | Consent to one budget and flight must not silently authorize a changed draft. |
| Next checkpoint and retry time                                 | A worker can resume without keeping a model turn or connection open.          |

The loop is:

```mermaid theme={null}
flowchart LR
  A[Load checkpoint] --> B[Read current Apostra state]
  B --> C[Choose the next allowed step]
  C --> D{Approval required?}
  D -->|Yes| E[Record approval and resume]
  D -->|No| F[Call the typed tool]
  E --> B
  F --> G[Save result and next checkpoint]
  G --> A
```

Application code validates the model's proposed tool and arguments against the
current schema and your allowed actions. Stop a run when it needs a person,
is waiting on asynchronous work, has reached its call budget, or has no valid
next step. A scheduled worker or a supported notification can resume it later.

## Add buying steps

| Checkpoint               | Tool or action                                                             | What to persist and verify                                                                        |
| ------------------------ | -------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
| Draft                    | `save_campaign`                                                            | Campaign ID, revision, brief, flight, and budget. Creation does not launch.                       |
| Discover offers          | `request_proposals`                                                        | Original request and idempotency key, `executionId`, status, and every result page.               |
| Select and stage         | `save_media_buy`                                                           | Exact qualified proposal or product route, selected pricing, allocation, and resulting draft buy. |
| Attach approved creative | `save_creative` and the documented creative association                    | Exact asset and creative IDs, format compatibility, and review readiness.                         |
| Preview launch           | `save_campaign` with `desiredPhase: "active"`                              | Returned campaign revision and the proposed launch.                                               |
| Confirm launch           | A second `save_campaign` with `confirmLaunch: true` and `expectedRevision` | Explicit approval of that revision and the returned execution state.                              |
| Observe                  | Fresh `get`, `search`, and `get_delivery` reads                            | Current status, blockers, and reporting results.                                                  |

The launch preview and confirmation use separate idempotency keys. If the
campaign changes after approval, obtain a fresh preview and approval rather
than confirming a different draft. Content approval, seller creative review,
and launch approval are separate decisions.

### Resume a proposal request

A fresh `request_proposals` call durably schedules seller discovery. It
normally returns `running`. Persist the original campaign revision and
idempotency key before making the call, then repeat that same request until
its status is `complete`, `partial`, or `failed`.

Once terminal, follow every `page.nextCursor` using the documented continuation
arguments. One seller can span several result pages. A `partial` result is not
permission to discard failed seller outcomes, and the first page is not the
whole result.

Only one proposal execution can run per buyer across campaigns. A new key
starts a new round; it is not a polling mechanism. See
[Request proposals](/v2/setup/v3/buyer-workflows#3-request-proposals-from-eligible-sellers).

### Recover from interrupted writes

A timeout or disconnected MCP session does not prove a write failed. Preserve
the request, inspect any structured error and `partialWrite` evidence, and
re-read the affected object before retrying. Reuse an idempotency key only for
the same logical operation and unchanged arguments. Follow a tool's specific
contract where it supplies its own identity, such as the `productQueryId` used
when staging returned products.

Connections and individual tool calls have time limits and can be interrupted
by deployments. A workflow that spans creative review or seller execution must
survive reconnection. See [Client setup](/v3/client-setup) and
[Capability limits](/v2/setup/v3/limitations).

## Give independent software its own identity

An interactive assistant using a person's OAuth connection requires no
buyer-agent registration. For independently operated software, an organization
administrator can register an external buyer agent, issue its credential, and
grant exact advertiser access through
[buyer-agent management](/v2/setup/buyer-agent-credentials).

These controls require the documented direct administrator session. Where the
current catalog advertises `save_buyer_agent`, use it with the matching
`get`/`search` reads. Use the documented console or REST path for controls the
active v3 catalog does not expose. Do not assume a runtime credential can
register itself or grant its own advertiser access. Registration gives software
an identity; it does not make Apostra the hosted runtime for that software.

## Test the boundaries

Use deterministic fixtures to prove that your application handles an empty
seller list, a blocked account, a multi-page proposal result, an interrupted
write, and a changed campaign revision. Test that a proposed launch cannot
pass the application's approval checkpoint without an approval for the exact
draft.

Then use the [sandbox workflow](/v2/features/sandbox) for live transaction
verification. A seller can follow the
[no-spend own-supply recipe](/v2/setup/v3/seller-workflows#test-your-own-supply)
and the published
[Test a Sales Agent skill](https://api.interchange.io/skills/test-sales-agent/SKILL.md).
Sandbox access is scoped; it does not prove eligibility for live supply,
funding, or production launch.
