openapi: 3.1.0
info:
  title: Inboxbanner GAM — Control & Partner API
  version: 1.0.0
  description: |
    Control plane and partner APIs for Inboxbanner (GAM-style newsletter ad platform).
    SSP (inventory) and DSP (demand) surfaces are separated by tags and RBAC.
servers:
  - url: http://localhost:8090
    description: IB-dashboard-backend (local)
tags:
  - name: Admin
    description: Network administration and config publish
  - name: SSP — Inventory
    description: Publisher-facing inventory APIs
  - name: DSP — Demand
    description: Advertiser-facing demand APIs
  - name: Partner — Inventory
    description: Partner automation (SSP)
  - name: Partner — Demand
    description: Partner automation (DSP)
  - name: Partner — Reporting
    description: Reporting and exports
  - name: Health
    description: Liveness

paths:
  /api/v1/health:
    get:
      tags: [Health]
      summary: Health check
      operationId: health
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HealthResponse'

  /api/v1/admin/config/publish:
    post:
      tags: [Admin]
      summary: Publish active configuration to serving plane
      operationId: publishConfig
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PublishRequest'
      responses:
        '200':
          description: Published
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublishResponse'
        '409':
          description: Concurrent publish conflict

  /api/v1/ssp/publishers:
    get:
      tags: [SSP — Inventory]
      summary: List publishers for network
      operationId: listPublishers
      responses:
        '200':
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Publisher'
    post:
      tags: [SSP — Inventory]
      summary: Create publisher
      operationId: createPublisher
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PublisherCreate'
      responses:
        '201':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Publisher'

  /api/v1/ssp/ad-units:
    get:
      tags: [SSP — Inventory]
      summary: List ad units
      operationId: listAdUnits
      responses:
        '200':
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/AdUnit'
    post:
      tags: [SSP — Inventory]
      summary: Create ad unit
      operationId: createAdUnit
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AdUnitCreate'
      responses:
        '201':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AdUnit'

  /api/v1/dsp/orders:
    get:
      tags: [DSP — Demand]
      summary: List orders
      operationId: listOrders
      responses:
        '200':
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Order'
    post:
      tags: [DSP — Demand]
      summary: Create order
      operationId: createOrder
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/OrderCreate'
      responses:
        '201':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Order'

  /api/v1/dsp/line-items:
    get:
      tags: [DSP — Demand]
      summary: List line items
      operationId: listLineItems
      responses:
        '200':
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/LineItem'
    post:
      tags: [DSP — Demand]
      summary: Create line item
      operationId: createLineItem
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/LineItemCreate'
      responses:
        '201':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LineItem'

  /api/v1/dsp/creatives:
    get:
      tags: [DSP — Demand]
      summary: List creatives
      operationId: listCreatives
      responses:
        '200':
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Creative'
    post:
      tags: [DSP — Demand]
      summary: Create creative
      operationId: createCreative
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreativeCreate'
      responses:
        '201':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Creative'

  /api/v1/partner/inventory/ad-units:
    get:
      tags: [Partner — Inventory]
      summary: Partner — list ad units
      operationId: partnerListAdUnits
      security:
        - BearerAuth: []
        - ApiKeyAuth: []
      responses:
        '200':
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/AdUnit'

  /api/v1/partner/demand/line-items:
    get:
      tags: [Partner — Demand]
      summary: Partner — list line items
      operationId: partnerListLineItems
      security:
        - BearerAuth: []
        - ApiKeyAuth: []
      responses:
        '200':
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/LineItem'

  /api/v1/partner/reports/delivery:
    get:
      tags: [Partner — Reporting]
      summary: Partner — delivery summary (stub)
      operationId: partnerDeliveryReport
      security:
        - BearerAuth: []
        - ApiKeyAuth: []
      parameters:
        - name: from
          in: query
          schema:
            type: string
            format: date
        - name: to
          in: query
          schema:
            type: string
            format: date
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DeliveryReport'

components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-IB-Api-Key

  parameters:
    IdempotencyKey:
      name: Idempotency-Key
      in: header
      required: false
      schema:
        type: string

  schemas:
    HealthResponse:
      type: object
      properties:
        status:
          type: string
          example: UP

    PublishRequest:
      type: object
      properties:
        comment:
          type: string

    PublishResponse:
      type: object
      required: [configVersion, publishedAt]
      properties:
        configVersion:
          type: string
        publishedAt:
          type: string
          format: date-time

    Publisher:
      type: object
      required: [id, networkId, name, status]
      properties:
        id:
          type: string
        networkId:
          type: string
        name:
          type: string
        status:
          type: string
          enum: [ACTIVE, PAUSED]

    PublisherCreate:
      type: object
      required: [name]
      properties:
        name:
          type: string

    AdUnit:
      type: object
      required: [id, networkId, publisherId, name, placementKey]
      properties:
        id:
          type: string
        networkId:
          type: string
        publisherId:
          type: string
        name:
          type: string
        placementKey:
          type: string
        targetingKeys:
          type: object
          additionalProperties:
            type: string

    AdUnitCreate:
      type: object
      required: [publisherId, name, placementKey]
      properties:
        publisherId:
          type: string
        name:
          type: string
        placementKey:
          type: string
        targetingKeys:
          type: object
          additionalProperties:
            type: string

    Order:
      type: object
      required: [id, networkId, advertiserId, name, status]
      properties:
        id:
          type: string
        networkId:
          type: string
        advertiserId:
          type: string
        name:
          type: string
        status:
          type: string
          enum: [DRAFT, ACTIVE, COMPLETED]

    OrderCreate:
      type: object
      required: [advertiserId, name]
      properties:
        advertiserId:
          type: string
        name:
          type: string

    LineItem:
      type: object
      required: [id, networkId, orderId, name, priority, status]
      properties:
        id:
          type: string
        networkId:
          type: string
        orderId:
          type: string
        name:
          type: string
        priority:
          type: integer
        status:
          type: string
          enum: [DRAFT, ACTIVE, PAUSED]
        budgetAmount:
          type: number
        creativeId:
          type: string

    LineItemCreate:
      type: object
      required: [orderId, name, priority]
      properties:
        orderId:
          type: string
        name:
          type: string
        priority:
          type: integer
        creativeId:
          type: string
        budgetAmount:
          type: number

    Creative:
      type: object
      required: [id, networkId, advertiserId, name, clickThroughUrl]
      properties:
        id:
          type: string
        networkId:
          type: string
        advertiserId:
          type: string
        name:
          type: string
        clickThroughUrl:
          type: string
        imageUrl:
          type: string

    CreativeCreate:
      type: object
      required: [advertiserId, name, clickThroughUrl]
      properties:
        advertiserId:
          type: string
        name:
          type: string
        clickThroughUrl:
          type: string
        imageUrl:
          type: string

    DeliveryReport:
      type: object
      properties:
        impressions:
          type: integer
        clicks:
          type: integer
        revenue:
          type: number
