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

# Create storefront proposal

> Save a discover-products response against a buyer (operator) binding and mint a shareable proposal_code. Buyers redeem the code on discover_products in a follow-up release.



## OpenAPI

````yaml /v2/storefront-api-v2.yaml post /proposals
openapi: 3.0.0
info:
  title: Scope3 Storefront API
  version: 2.0.0
  description: |-
    REST API for partners to manage storefronts, inventory sources, and billing.

    ## Authentication

    All endpoints require a Bearer token in the Authorization header:
    ```
    Authorization: Bearer your-api-key
    ```

    ## Base URL

    `https://api.interchange.io/api/v2/storefront`

    ## For AI Agents

    AI agents can use the MCP endpoint at `/mcp/v2/storefront` with three tools:
    - `initialize`: Start an MCP session
    - `api_call`: Make REST API calls
    - `ask_about_capability`: Learn about API features
servers:
  - url: https://api.interchange.io/api/v2/storefront
    description: Production server
security: []
tags:
  - name: Account
    description: Account management, service tokens, and preferences
  - name: Storefront
    description: Manage storefront and inventory sources
  - name: Storefront Agents
    description: List and manage registered sales, signals, and outcomes agents
  - name: Storefront Activity
    description: Audit log of configuration and inventory changes on the storefront
  - name: Storefront Billing
    description: Payout bank details and billing configuration for storefronts
  - name: AI Usage
    description: Storefront AI token usage visibility by model
  - name: MCP
    description: Model Context Protocol endpoints
paths:
  /proposals:
    post:
      tags:
        - Storefront Proposals
      summary: Create storefront proposal
      description: >-
        Save a discover-products response against a buyer (operator) binding and
        mint a shareable proposal_code. Buyers redeem the code on
        discover_products in a follow-up release.
      operationId: createStorefrontProposal
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateStorefrontProposalBody'
      responses:
        '201':
          description: Create storefront proposal
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StorefrontProposal'
        '400':
          description: Bad request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
        - bearerAuth: []
components:
  schemas:
    CreateStorefrontProposalBody:
      description: Request body for creating a storefront proposal
      type: object
      properties:
        operatorId:
          description: >-
            Buyer binding for the proposal. Prefer { "domain": "brand.example"
            }. Legacy string values are accepted as domain strings, except
            customer:<id> which is decoded as { customerId }.
          example:
            domain: acme.com
          anyOf:
            - type: string
              minLength: 1
              maxLength: 255
            - $ref: '#/components/schemas/StorefrontProposalOperatorReference'
        label:
          description: Seller's internal label for the proposal
          example: Acme Q3 RFP — CTV
          type: string
          minLength: 1
          maxLength: 255
        notes:
          description: Free-form notes about the offline RFP
          type: string
          maxLength: 4000
        expiresAt:
          description: >-
            When the proposal code expires (ISO 8601). Server enforces this is
            no later than the underlying proposal.expiresAt.
          type: string
          format: date-time
          pattern: >-
            ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z))$
        discoveryId:
          description: >-
            Discovery session id from a recent discover-products call. The
            server reads the cached snapshot for this session and persists it as
            the frozen offer. The session must have been scoped to this seller
            and restricted to its storefront sales agents.
          example: disc_a1b2c3
          type: string
          minLength: 1
          maxLength: 255
        proposalId:
          description: >-
            Which proposal from the discovery snapshot to save and bind to the
            proposal code.
          example: proposal_abc123
          type: string
          minLength: 1
          maxLength: 255
      required:
        - operatorId
        - label
        - expiresAt
        - discoveryId
        - proposalId
    StorefrontProposal:
      description: A persisted storefront proposal
      type: object
      properties:
        id:
          description: Proposal row id
          type: integer
          maximum: 9007199254740991
          minimum: 1
        proposalCode:
          description: >-
            Short shareable handle. Sellers give this to buyers; buyers pass it
            to discover_products.
          example: PRP-XK4A29
          type: string
        operatorId:
          description: >-
            Encoded buyer binding retained for backwards compatibility. Use
            operatorRef for the structured form.
          type: string
        operatorRef:
          description: Structured buyer binding for redemption auth.
          allOf:
            - $ref: '#/components/schemas/StorefrontProposalOperatorReferenceOutput'
        label:
          type: string
        notes:
          nullable: true
          type: string
        status:
          description: >-
            Proposal lifecycle status. 'active': available to redeem.
            'redeemed': buyer has applied it to a media buy. 'expired': past
            TTL. 'revoked': seller withdrew.
          type: string
          enum:
            - active
            - redeemed
            - expired
            - revoked
        expiresAt:
          type: string
          format: date-time
          pattern: >-
            ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z))$
        proposalId:
          description: The protocol-level proposalId from the saved discovery snapshot
          type: string
        discoverySessionId:
          description: >-
            Discovery session id this proposal was captured from (for
            traceability)
          type: string
        snapshot:
          description: The frozen products + proposals returned to the buyer on redemption
          allOf:
            - $ref: '#/components/schemas/ProposalSnapshot'
        createdAt:
          type: string
          format: date-time
          pattern: >-
            ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z))$
        createdBy:
          type: string
        firstViewedAt:
          nullable: true
          type: string
          format: date-time
          pattern: >-
            ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z))$
        lastViewedAt:
          nullable: true
          type: string
          format: date-time
          pattern: >-
            ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z))$
        redeemedAt:
          nullable: true
          type: string
          format: date-time
          pattern: >-
            ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z))$
        redeemedInMediaBuyId:
          nullable: true
          type: string
      required:
        - id
        - proposalCode
        - operatorId
        - operatorRef
        - label
        - notes
        - status
        - expiresAt
        - proposalId
        - discoverySessionId
        - snapshot
        - createdAt
        - createdBy
        - firstViewedAt
        - lastViewedAt
        - redeemedAt
        - redeemedInMediaBuyId
      additionalProperties: false
    ErrorResponse:
      description: Standard error response
      type: object
      properties:
        data:
          type: string
          nullable: true
          enum:
            - null
        error:
          $ref: '#/components/schemas/ApiError'
      required:
        - data
        - error
      additionalProperties: false
    StorefrontProposalOperatorReference:
      description: >-
        Resolvable buyer binding for a storefront proposal. Prefer { domain }
        for brand-backed buyers; use { customerId } only as an unbranded
        fallback.
      anyOf:
        - type: object
          properties:
            domain:
              description: >-
                Buyer brand domain. The buyer must resolve to this brand domain
                when redeeming the proposal code.
              example: acme.com
              type: string
              minLength: 1
              maxLength: 255
          required:
            - domain
        - type: object
          properties:
            customerId:
              description: >-
                Buyer customer id fallback used only when the buyer does not
                have an advertiser brand domain.
              example: 123
              type: integer
              maximum: 9007199254740991
              minimum: 1
          required:
            - customerId
    StorefrontProposalOperatorReferenceOutput:
      description: >-
        Resolvable buyer binding for a storefront proposal. Prefer { domain }
        for brand-backed buyers; use { customerId } only as an unbranded
        fallback.
      anyOf:
        - type: object
          properties:
            domain:
              description: >-
                Buyer brand domain. The buyer must resolve to this brand domain
                when redeeming the proposal code.
              example: acme.com
              type: string
              minLength: 1
              maxLength: 255
          required:
            - domain
          additionalProperties: false
        - type: object
          properties:
            customerId:
              description: >-
                Buyer customer id fallback used only when the buyer does not
                have an advertiser brand domain.
              example: 123
              type: integer
              maximum: 9007199254740991
              minimum: 1
          required:
            - customerId
          additionalProperties: false
    ProposalSnapshot:
      description: >-
        Frozen products + proposals captured from the discovery session at
        compose time
      type: object
      properties:
        products:
          description: All products that were available in the discovery session
          type: array
          items:
            $ref: '#/components/schemas/Product'
        proposals:
          description: All proposals from the discovery session (including the chosen one)
          type: array
          items:
            $ref: '#/components/schemas/Proposal'
      required:
        - products
        - proposals
      additionalProperties: false
    ApiError:
      description: Structured error object
      type: object
      properties:
        code:
          description: Machine-readable error code
          type: string
        message:
          description: Human-readable error message
          type: string
        field:
          description: Field path associated with the error
          type: string
        details:
          description: Additional error context
          type: object
          additionalProperties: {}
      required:
        - code
        - message
      additionalProperties: false
    Product:
      description: Product resource for campaign inventory
      type: object
      properties:
        productId:
          description: Unique identifier for the product
          example: prod_123
          type: string
        name:
          description: Product name
          example: Premium CTV Inventory - Sports
          type: string
        channel:
          description: >-
            First canonical AdCP media channel. Use channels for the complete
            set.
          example: ctv
          type: string
        channels:
          description: Canonical AdCP media channels declared by the product
          example:
            - streaming_audio
            - podcast
          type: array
          items:
            type: string
        inventoryType:
          description: >-
            Inventory classification such as premium or run_of_site; not a media
            channel
          example: run_of_site
          type: string
        formatTypes:
          description: >-
            Canonical AdCP format kinds derived from formatOptions (never legacy
            named-format IDs)
          example:
            - video_hosted
          type: array
          items:
            type: string
        cpm:
          description: Cost per mille (CPM)
          example: 12.5
          type: number
        currency:
          description: ISO currency code for `cpm` (e.g. "USD", "ZAR")
          example: USD
          type: string
        expiresAt:
          description: >-
            When this product's pricing stops being valid (ISO 8601). Present
            only when the seller quoted an FX-converted price (a rate-of-the-day
            conversion into a currency the product is not natively priced in);
            absent for natively-priced products, which carry no expiry and cache
            freely. A cached product past this timestamp MUST be treated as
            stale — re-discover or re-quote rather than transacting on the
            expired price. Selecting or booking against an expired quote gets a
            fresh price, not the stale one.
          type: string
          format: date-time
          pattern: >-
            ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z))$
        pricingScope:
          description: >-
            Whether this product's pricing is the seller's public rate card
            ('public') or reflects a buyer-specific discount/rate ('account').
            Absent is equivalent to 'public' (a pre-3.1 seller, or a source that
            has never applied account-specific pricing). A buyer's agent should
            treat 'public' items as portable across a shared/anonymous cache and
            'account' items as private to this account — never re-serve an
            account-scoped price to another account or a public cache partition.
          type: string
          enum:
            - public
            - account
        salesAgentId:
          description: Sales agent ID
          type: string
        salesAgentName:
          description: Sales agent name
          type: string
        storefrontId:
          description: >-
            Storefront ID — the storefront this product was discovered through.
            A single sales agent may back sources across multiple storefronts;
            products are stamped per (storefront, agent) pairing so the same
            product can appear in multiple storefronts independently.
          type: string
        storefrontName:
          description: Storefront display name
          type: string
        supportedRoutingTypes:
          description: >-
            Legacy execution-compatibility values for media buys containing this
            product. This field does not determine campaign mode, BYOA, protocol
            connectivity, or settlement.
          type: array
          items:
            type: string
            enum:
              - DECISIONED
              - ROUTED
        description:
          description: Product description
          type: string
        deliveryType:
          description: Delivery type — guaranteed means fixed delivery commitment
          example: guaranteed
          type: string
          enum:
            - guaranteed
            - non_guaranteed
        briefRelevance:
          description: >-
            AI-generated explanation of why this product matches the campaign
            brief
          type: string
        productCard:
          description: Standard visual card (300x400px) for UI rendering
          allOf:
            - $ref: '#/components/schemas/ProductCardData'
        productCardDetailed:
          description: Detailed card with carousel and full specifications
          allOf:
            - $ref: '#/components/schemas/ProductCardData'
        pricingOptions:
          description: Full pricing options from the sales agent
          type: array
          items:
            $ref: '#/components/schemas/PricingOptionData'
        estimatedExposures:
          description: Estimated impressions for guaranteed products
          type: integer
          minimum: -9007199254740991
          maximum: 9007199254740991
        forecast:
          description: >-
            Structured delivery forecast with budget points and metric ranges
            (ADCP 3.15+)
          type: object
          additionalProperties: {}
        bookability:
          description: >-
            Sanitized Sales Agent cached pricing/availability guidance for
            whether the product is bookable.
          type: string
        publisherProperties:
          description: Publisher properties from ADCP (domains, property types, etc.)
          type: array
          items:
            type: object
            properties:
              publisherDomain:
                type: string
              propertyType:
                type: string
              name:
                type: string
              selectionType:
                type: string
              identifiers:
                type: array
                items:
                  type: object
                  additionalProperties: {}
            additionalProperties: false
        isSandbox:
          description: Whether this product was discovered in sandbox mode
          type: boolean
        formatOptions:
          description: >-
            AdCP 3.1 format declarations for this product. Each entry carries a
            format_kind discriminator, optional format_option_id (stable
            identifier buyers use to select a specific format via
            format_option_refs in create_media_buy), and canonical params. For
            hosted-video formats (format_kind "video_hosted"), params.containers
            / params.video_codecs / params.audio_codecs advertise the accepted
            delivery containers and codecs, so a buyer can avoid sending a
            creative that would be rejected downstream. Present only when the
            sales agent publishes v2 format declarations alongside legacy
            format_ids.
          type: array
          items:
            $ref: '#/components/schemas/ProductFormatOption'
      required:
        - productId
        - name
      additionalProperties: false
    Proposal:
      description: >-
        A recommended media plan with budget allocations across products (ADCP
        v3)
      type: object
      properties:
        proposalId:
          description: Unique identifier — used to refine or execute the proposal
          type: string
        name:
          description: Human-readable name for this media plan proposal
          type: string
        description:
          description: Strategic explanation of what the proposal achieves
          type: string
        briefAlignment:
          description: Explanation of how this proposal aligns with the brief
          type: string
        salesAgentId:
          description: Sales agent that generated this proposal
          type: string
        salesAgentName:
          description: Human-readable sales agent name
          type: string
        storefrontId:
          description: >-
            Storefront the proposal was surfaced through. The storefront is the
            buyer-facing seller identity; the underlying sales agent is internal
            routing detail.
          type: string
        storefrontName:
          description: >-
            Human-readable storefront name. Use this as the seller label on
            proposal cards.
          type: string
        supportedRoutingTypes:
          description: >-
            Legacy execution-compatibility values for media buys containing this
            proposal. This field does not determine campaign mode, BYOA,
            protocol connectivity, or settlement.
          type: array
          items:
            type: string
            enum:
              - DECISIONED
              - ROUTED
        allocations:
          description: Budget distribution across products — percentages sum to 100
          minItems: 1
          type: array
          items:
            $ref: '#/components/schemas/ProductAllocation'
        expiresAt:
          description: When the proposal expires (ISO 8601)
          type: string
        totalBudgetGuidance:
          description: Budget guidance for this proposal
          type: object
          properties:
            min:
              type: number
            recommended:
              type: number
            max:
              type: number
            currency:
              type: string
          additionalProperties: false
      required:
        - proposalId
        - name
        - allocations
      additionalProperties: false
    ProductCardData:
      description: Visual card data for rendering a product in UI
      type: object
      properties:
        formatId:
          type: object
          properties:
            agentUrl:
              type: string
            id:
              type: string
          required:
            - agentUrl
            - id
          additionalProperties: false
        manifest:
          type: object
          additionalProperties: {}
      required:
        - formatId
        - manifest
      additionalProperties: false
    PricingOptionData:
      description: Pricing option from a sales agent
      type: object
      properties:
        pricingOptionId:
          type: string
        pricingModel:
          type: string
        isFixed:
          type: boolean
        rate:
          type: number
        floorPrice:
          type: number
        fixedPrice:
          type: number
        currency:
          type: string
        priceGuidance:
          description: >-
            Cached auction guidance percentiles from the Sales Agent. These are
            estimates, not floors.
          type: object
          properties:
            floor:
              nullable: true
              type: number
            p25:
              nullable: true
              type: number
            p50:
              nullable: true
              type: number
            p75:
              nullable: true
              type: number
            p90:
              nullable: true
              type: number
          additionalProperties: false
      additionalProperties: false
    ProductFormatOption:
      description: AdCP 3.1 format declaration for a product
      type: object
      properties:
        format_kind:
          description: AdCP format kind discriminator (e.g. video_hosted, image)
          example: video_hosted
          type: string
        format_option_id:
          description: >-
            Stable identifier buyers use to select this format via
            format_option_refs in create_media_buy
          type: string
        display_name:
          description: Human-readable name for this format option
          type: string
        params:
          description: Canonical params for this format option
          allOf:
            - $ref: '#/components/schemas/ProductFormatOptionParams'
      additionalProperties: {}
    ProductAllocation:
      description: Budget allocation for a product within a proposal
      type: object
      properties:
        productId:
          description: Product ID — references a product in the sibling products array
          type: string
        allocationPercentage:
          description: Percentage of total budget allocated to this product
          type: number
          minimum: 0
          maximum: 100
        pricingOptionId:
          description: Recommended pricing option ID from the product pricing_options
          type: string
        rationale:
          description: Why this product and allocation are recommended
          type: string
        sequence:
          description: Ordering hint for multi-line-item plans (1-based)
          type: integer
          minimum: -9007199254740991
          maximum: 9007199254740991
        tags:
          description: Categorical tags (e.g., "desktop", "mobile")
          type: array
          items:
            type: string
      required:
        - productId
        - allocationPercentage
      additionalProperties: false
    ProductFormatOptionParams:
      description: >-
        Canonical format params. For hosted video, carries accepted
        containers/codecs.
      type: object
      properties:
        containers:
          description: >-
            Accepted delivery containers for hosted video. A buyer should only
            send a creative whose container is listed here.
          example:
            - mp4
          type: array
          items:
            type: string
            enum:
              - mp4
              - webm
              - mov
        video_codecs:
          description: Accepted video codecs for hosted video.
          example:
            - h264
          type: array
          items:
            type: string
            enum:
              - h264
              - h265
              - vp8
              - vp9
              - av1
              - prores
        audio_codecs:
          description: Accepted audio codecs for hosted video.
          example:
            - aac
          type: array
          items:
            type: string
            enum:
              - aac
              - mp3
              - opus
              - pcm
      additionalProperties: {}
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: API key or access token

````