> ## 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.

# Create inventory source

> Register an external AdCP-compatible agent as an inventory source

`POST /api/v2/storefront/inventory-sources`

Creates an inventory source and registers its backing agent. Only external `AGENT` sources are created here — `MANAGED_SALES_AGENT`, `LINKED_STOREFRONT`, and `MODULAR_SOURCE` rows are created through their own provisioning and linking flows.

## Request

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST https://api.apostra.com/api/v2/storefront/inventory-sources \
    -H "Authorization: Bearer $SCOPE3_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "sourceId": "retail-network-agent",
      "name": "Retail Network Agent",
      "executionType": "AGENT",
      "type": "SALES",
      "endpointUrl": "https://agent.retail-network.example.com/mcp",
      "protocol": "MCP",
      "authenticationType": "API_KEY",
      "connectionContract": {
        "id": "external-sales-agent",
        "version": 1,
        "authenticationMethod": "bearer_token"
      },
      "auth": { "type": "bearer", "token": "<SOURCE_API_KEY>" },
      "description": "Primary external sales agent for on-site display and CTV"
    }'
  ```

  ```json JWT auth theme={null}
  {
    "name": "Retail Network Agent",
    "executionType": "AGENT",
    "type": "SALES",
    "endpointUrl": "https://agent.retail-network.example.com/mcp",
    "protocol": "MCP",
    "authenticationType": "JWT",
    "auth": {
      "type": "jwt",
      "privateKey": "<PRIVATE_KEY>",
      "issuer": "https://retail-network.example.com",
      "subject": "retail-sales",
      "keyId": "key-1",
      "scope": "agent:invoke",
      "tokenEndpointUrl": "https://auth.retail-network.example.com/oauth/token",
      "audienceUrl": "https://agent.retail-network.example.com/mcp"
    }
  }
  ```

  ```json OAuth with explicit audience theme={null}
  {
    "name": "Retail Network Agent",
    "executionType": "AGENT",
    "type": "SALES",
    "endpointUrl": "https://agent.retail-network.example.com/mcp",
    "protocol": "MCP",
    "authenticationType": "OAUTH",
    "oauthAudience": "https://platform.retail-network.example.com"
  }
  ```
</CodeGroup>

## Parameters

| Field                | Type                | Required          | Notes                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| -------------------- | ------------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `name`               | string              | Yes               | Display name (1–255 chars)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| `sourceId`           | string              | No                | Storefront-scoped ID (1–255 chars). Defaults to a slugified `name`                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| `attachToAgentId`    | string (UUID)       | No                | ID of an organization-owned Sales Agent to attach to the new Source. Creation and attachment succeed together or neither is created.                                                                                                                                                                                                                                                                                                                                                                                                             |
| `agentProductMode`   | enum                | Conditional       | Per-Source product-path choice when the Agent named by `attachToAgentId` declares `BOTH`: `WHOLESALE`, `COMPOSING`, or `BOTH`. Omit it for single-mode or undeclared Agents.                                                                                                                                                                                                                                                                                                                                                                     |
| `executionType`      | enum                | No                | Only `AGENT` is accepted here. Default `AGENT`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `type`               | enum                | Yes (for `AGENT`) | `SALES`, `SIGNAL`, `CREATIVE`, or `OUTCOME`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| `endpointUrl`        | string (uri)        | Yes (for `AGENT`) | Executable agent URL from the selected AAO `authorized_agents[].url` entry (max 2048). Do not use a publisher's `adagents.json` URL or its `authoritative_location`                                                                                                                                                                                                                                                                                                                                                                              |
| `protocol`           | enum                | Yes (for `AGENT`) | `MCP` or `A2A`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `authenticationType` | enum                | Yes (for `AGENT`) | `API_KEY`, `JWT`, `BASIC_AUTH`, `NO_AUTH`, or `OAUTH`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `connectionContract` | object              | No                | Pins a migrated setup definition by `id`, `version`, and typed `authenticationMethod`. The external sales-agent Task sends `external-sales-agent:v1`. Omit for the legacy compatibility path. An explicit unknown version or a method that conflicts with `authenticationType`/`auth` is rejected.                                                                                                                                                                                                                                               |
| `auth`               | object              | Conditional       | Required only for `JWT`. For `API_KEY` and `BASIC_AUTH` it is optional — supply credentials now, or omit them to create the source `PENDING` and add the secret later (e.g. through the secure credential form). **Omit** for `OAUTH` and `NO_AUTH`. API-key shape: `{ type: "bearer"\|"apikey"\|"api_key", token }`. Basic shape: `{ type: "basic", username, password }`. JWT shape: `{ type: "jwt", privateKey, issuer, subject, keyId, scope, tokenEndpointUrl, audienceUrl, algorithm?, environment? }` (`algorithm` is `ES256` or `RS256`) |
| `oauthAudience`      | string (public URI) | No                | Compatibility override for a newly registered `OAUTH` identity whose gateway validates a resource-specific audience but does not publish it through RFC 9728 protected-resource metadata. Apostra sends the value as both Auth0 `audience` and RFC 8707 `resource`. Omit it when protected-resource discovery supplies the resource. If the endpoint reuses an existing identity, its stored OAuth configuration is reused; update the existing source first to change the audience.                                                             |
| `description`        | string              | No                | Agent description (max 2000)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |

<Warning>
  Treat `auth.token` and JWT private keys as production secrets. They are encrypted at rest, referenced only by an opaque ref, and never echoed back — responses surface `authConfigured: true`. Never log or commit raw credentials.
</Warning>

For `external-sales-agent:v1`, use `bearer_token` with
`auth.type: "bearer"`, `basic_auth` with `auth.type: "basic"`, or `none`
without `auth`. The shared contract schema also has typed API-key, OAuth 2.0,
JWT, and platform-service-account methods for integrations that register those
methods. Authentication is a closed platform-owned set; requests cannot install
executable header or request templates.

## Response

`201 Created` with the new `InventorySourceResponse`:

```json theme={null}
{
  "id": "900123456789",
  "sourceId": "retail-network-agent",
  "name": "Retail Network Agent",
  "executionType": "AGENT",
  "status": "PENDING",
  "agentId": "agent_01HX...",
  "type": "SALES",
  "endpointUrl": "https://agent.retail-network.example.com/mcp",
  "protocol": "MCP",
  "authenticationType": "API_KEY",
  "authConfigured": true,
  "isAdapterSource": false,
  "createdAt": "2026-04-25T12:05:00Z",
  "updatedAt": "2026-04-25T12:05:00Z"
}
```

Every external `AGENT` source is created in `status: "PENDING"`, including a
`NO_AUTH` source, and proceeds through the normal registration and readiness
workflow before activation. Reachability is reported independently by source
health and connectivity checks. For a newly registered `OAUTH` identity, the
response includes `oauth.authorizationUrl` when authorization discovery and
flow storage succeed; redirect the operator there to complete consent. If the
source is created without that block, start consent with [Start agent
OAuth](/v2/storefront/agents/tasks/start-agent-oauth). Complete authorization
even when `oauthAudience` was supplied—the override selects the token resource;
it is not a credential. If the endpoint reuses an existing identity, create
reuses its OAuth configuration and does not reinitialize consent; update an
existing source first when the audience or authorization must change.

When `attachToAgentId` is supplied, Apostra creates the Source and attaches
it to that exact organization-owned Sales Agent as one operation. The response
returns the attached Agent in `agentCapabilityUid`. If the request response is
interrupted, return to that Agent's **Inventory sources** section and refresh
before sending another create request: a committed Source appears there already.
Do not blindly resubmit an ambiguous request.

If the Agent declares both product paths, `agentProductMode` records how this
Source participates: Storefront-built catalog (`WHOLESALE`), Agent-supplied
products (`COMPOSING`), or both (`BOTH`). The Agent declaration is re-read by
the server; the launch payload is only presentation guidance.

Connecting checks that the agent's `endpointUrl` is registered with the [AAO](/v2/concepts/glossary) registry. If the agent is not registered, the request is rejected with `400 VALIDATION_ERROR`. If the registry cannot be reached to perform the check, the request returns `503 SERVICE_UNAVAILABLE` — a transient connectivity problem, not a rejection of the agent, so retrying usually succeeds.

<Note>
  An `adagents.json` file identifies which agents a publisher authorizes; it is
  not an agent endpoint. When starting from a publisher domain, resolve its file
  through AAO and copy the selected agent's `authorized_agents[].url`. Do not copy
  the publisher well-known URL, AAO `hosting.resolved_url`, or the document's
  `authoritative_location` into `endpointUrl`.
</Note>

## After connection

Once connected, an external `AGENT` source can either answer buyer briefs live
on the Agent-supplied path — available on any account, including an
account with Listing + Distribution that keeps routing briefs through its own agent — or
provide cached components for the Storefront-built path, which requires a
separate Merchandising entitlement and a source that supports component caching. To support
component caching, the agent's product response must expose stable raw products:
ids, names/descriptions, pricing options, formats, publisher properties or other
inventory selectors, delivery type, and enough execution metadata to route a
selected product later. Murph reports component-cache problems separately from
live source-call failures.

<Note>
  **Registering the agent is not the same as authorizing it to sell a publisher's inventory.** This connect-time check only confirms the *agent* is registered in the AAO registry. Whether a *publisher's* [`adagents.json`](/v2/concepts/glossary) authorizes that agent to sell their inventory is a separate question, surfaced later as an advisory setup/product signal today — not at connect time. A registered agent can be connected and still be unauthorized for a given publisher's inventory.
</Note>

## Errors

* `400 VALIDATION_ERROR` — missing required field, a non-public endpoint or
  `oauthAudience`, `auth` supplied for an `OAUTH`/`NO_AUTH` agent, `auth`
  missing for a `JWT` agent, a malformed `attachToAgentId`, or the agent's
  endpoint is not registered with the AAO registry. An `adagents.json` or
  `authoritative_location` document is also rejected as `endpointUrl`. (Agent
  registration is distinct from publisher authorization — see the note above.)
* `401 UNAUTHORIZED` — missing or invalid API key.
* `403 ACCESS_DENIED` — `attachToAgentId` identifies an Agent owned by another
  organization or one the caller cannot administer.
* `404 NOT_FOUND` — `attachToAgentId` is unavailable in this organization, or
  the Agent workspace is not enabled for the account.
* `503 SERVICE_UNAVAILABLE` — the AAO registry could not be reached to verify the agent's registration. This is transient; retry the request.

See [Errors](/v2/reference/errors) for the full error contract.

## Related

<CardGroup cols={2}>
  <Card title="Inventory source tasks" href="/v2/storefront/inventory-sources/tasks" icon="list-check">
    All operations
  </Card>

  <Card title="Inventory sources overview" href="/v2/storefront/inventory-sources/overview" icon="plug">
    Concepts and lifecycle
  </Card>

  <Card title="Update inventory source" href="/v2/storefront/inventory-sources/tasks/update-inventory-source" icon="pen">
    Change fields or rotate auth
  </Card>

  <Card title="Storefront onboarding" href="/v2/setup/storefront-onboarding" icon="store">
    End-to-end seller setup
  </Card>
</CardGroup>
