openapi: 3.0.3
info:
  title: Audience + Events API
  description: |
    The MNTN Audience API lets you build and sync the audience segments MNTN
    targets on Connected TV. Create a segment, add identities to it, and keep
    that set current.

    The Events API accepts server-to-server conversion events under
    `/v2026/events/conversions`.

    All endpoints require API key authentication and exchange JSON over HTTPS.
  version: 0.1.0
  contact:
    name: Integrations Team
  x-logo:
    url: assets/mntn-logo.svg
    backgroundColor: '#12222F'
    altText: MNTN
servers:
  - url: https://integrations.ex.mountain.com
    description: Production
  - url: https://integrations-staging.ex.mountain.com
    description: Staging
tags:
  - name: Audience
    description: |
      Segment and identity management for the MNTN Audience integration.

      All `/v2026/audience/*` endpoints require API key authentication. The caller
      may authenticate via the `Authorization` header (Basic or Bearer) or the
      `access_key` query parameter. See the `audienceApiKey` security scheme for
      details.

      **Getting a key:** generate an Audience API key from the Integrations page
      in the MNTN platform when you connect the Audience integration.
  - name: Events
    description: |
      Server-to-server event ingestion for the MNTN Events API.

      All `/v2026/events/*` endpoints require API key authentication via the
      `audienceApiKey` security scheme (Bearer token or `access_key` query param).
paths:
  /v2026/events/conversions:
    post:
      tags:
        - Events
      operationId: ingestEventsConversions
      summary: Ingest conversion events
      description: |
        Accepts conversion / in-app events (e.g. purchases, sign-ups,
        installs) server-to-server. Accepts either a single `conversion`
        object or a batch `conversions` array.

        The body is forwarded as-is to Pub/Sub; structural field validation
        happens downstream.
      security:
        - audienceApiKey: []
      parameters:
        - $ref: '#/components/parameters/AccessKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/IngestConversionsRequest'
      responses:
        '202':
          description: Event(s) accepted and queued for processing
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AcceptedResponse'
              example:
                status: accepted
        '400':
          description: Bad request — missing Content-Type, invalid JSON, or missing conversion/conversions key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AudienceErrorResponse'
        '401':
          description: Missing or invalid API key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AudienceErrorResponse'
        '503':
          description: Pub/Sub publish failed, retry with backoff
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
  /v2026/audience/segments:
    get:
      tags:
        - Audience
      operationId: listAudienceSegments
      summary: List audience segments
      description: |
        Returns a paginated list of audience segments for the authenticated
        connection.

        When the `id` query parameter is present, the handler retrieves a
        single segment by ID (query-only alternate for
        GET /v2026/audience/segments/{segment_id}). The response is still a
        `ListSegmentsResponse` with a single-element `segments` array.
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |
            curl "https://integrations.ex.mountain.com/v2026/audience/segments?limit=50" \
              -H "Authorization: Bearer $MNTN_API_KEY"
        - lang: Python
          label: Python
          source: |
            import requests

            resp = requests.get(
                "https://integrations.ex.mountain.com/v2026/audience/segments",
                headers={"Authorization": f"Bearer {MNTN_API_KEY}"},
                params={"limit": 50},
            )
            resp.raise_for_status()
            segments = resp.json()["segments"]
        - lang: JavaScript
          label: JavaScript
          source: |
            const res = await fetch(
              "https://integrations.ex.mountain.com/v2026/audience/segments?limit=50",
              { headers: { Authorization: `Bearer ${MNTN_API_KEY}` } },
            );
            const { segments } = await res.json();
      security:
        - audienceApiKey: []
      parameters:
        - $ref: '#/components/parameters/AccessKey'
        - name: id
          in: query
          description: |
            When provided, retrieve a single segment by ID instead of listing.
            This is the query-only alternate for `GET /v2026/audience/segments/{segment_id}`.
            Mutually exclusive with `after`, `limit`, and `order`.
          schema:
            type: string
        - name: after
          in: query
          description: |
            Pagination cursor. After sorting by `order`, return results whose
            sort field value is strictly greater than `after` (for ascending
            order). Must have the same type as the order field.
          schema:
            type: string
        - name: limit
          in: query
          description: Maximum number of segments to return (page size).
          schema:
            type: integer
            minimum: 1
            maximum: 500
            default: 50
        - name: order
          in: query
          description: Sort field and direction.
          schema:
            type: string
            enum:
              - id:asc
              - name:asc
            default: name:asc
      responses:
        '200':
          description: A list of audience segments (or a single segment when `id` is provided)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListSegmentsResponse'
        '400':
          description: Invalid query parameters
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AudienceErrorResponse'
        '401':
          description: Missing or invalid API key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AudienceErrorResponse'
        '404':
          description: Segment not found (single-segment mode only)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AudienceErrorResponse'
        '501':
          description: Audience endpoints not enabled
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
    post:
      tags:
        - Audience
      operationId: createAudienceSegment
      summary: Create an audience segment
      description: |
        Creates a new audience segment for the authenticated connection. If
        `segment.id` is provided, the segment is created under that key;
        otherwise a new randomly-generated ID is assigned.
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |
            curl -X POST "https://integrations.ex.mountain.com/v2026/audience/segments" \
              -H "Authorization: Bearer $MNTN_API_KEY" \
              -H "Content-Type: application/json" \
              -d '{"segment":{"name":"High-Value Customers"}}'
        - lang: Python
          label: Python
          source: |
            import requests

            resp = requests.post(
                "https://integrations.ex.mountain.com/v2026/audience/segments",
                headers={"Authorization": f"Bearer {MNTN_API_KEY}"},
                json={"segment": {"name": "High-Value Customers"}},
            )
            resp.raise_for_status()
            segment = resp.json()["segment"]
        - lang: JavaScript
          label: JavaScript
          source: |
            const res = await fetch(
              "https://integrations.ex.mountain.com/v2026/audience/segments",
              {
                method: "POST",
                headers: {
                  Authorization: `Bearer ${MNTN_API_KEY}`,
                  "Content-Type": "application/json",
                },
                body: JSON.stringify({ segment: { name: "High-Value Customers" } }),
              },
            );
            const { segment } = await res.json();
      security:
        - audienceApiKey: []
      parameters:
        - $ref: '#/components/parameters/AccessKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateSegmentRequest'
            examples:
              named:
                summary: Named segment (auto-assigned ID)
                value:
                  segment:
                    name: High-Value Customers
              withId:
                summary: Caller-assigned ID and source
                value:
                  segment:
                    id: high-value-customers
                    name: High-Value Customers
                    source: crm-export
      responses:
        '201':
          description: Segment created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SegmentResponse'
        '400':
          description: Invalid request body
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AudienceErrorResponse'
        '401':
          description: Missing or invalid API key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AudienceErrorResponse'
        '409':
          description: A segment with the provided ID already exists
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AudienceErrorResponse'
        '501':
          description: Audience endpoints not enabled
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
  /v2026/audience/segments/{segment_id}:
    get:
      tags:
        - Audience
      operationId: getAudienceSegment
      summary: Get an audience segment
      description: |
        Retrieve the representational state of a single audience segment.

        The segment ID may be passed as a path parameter or as the `id` query
        parameter on `GET /v2026/audience/segments`. When the path parameter
        is the literal `.`, the handler reads `id` from the query string instead.
      security:
        - audienceApiKey: []
      parameters:
        - $ref: '#/components/parameters/SegmentID'
        - $ref: '#/components/parameters/AccessKey'
      responses:
        '200':
          description: The requested segment
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SegmentResponse'
        '401':
          description: Missing or invalid API key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AudienceErrorResponse'
        '404':
          description: Segment not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AudienceErrorResponse'
        '501':
          description: Audience endpoints not enabled
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
    put:
      tags:
        - Audience
      operationId: upsertAudienceSegment
      summary: Upsert an audience segment
      description: |
        Creates or replaces an audience segment by ID.

        The segment ID may be passed as a path parameter or as the `id` query
        parameter (e.g. `PUT /v2026/audience/segments?id={segment_id}`). When
        the path parameter is the literal `.`, the handler reads `id` from the
        query string instead. Path and query must not both be provided.
      security:
        - audienceApiKey: []
      parameters:
        - $ref: '#/components/parameters/SegmentID'
        - $ref: '#/components/parameters/AccessKey'
        - name: id
          in: query
          description: |
            Segment ID via query parameter (query-only alternate form).
            Mutually exclusive with the `segment_id` path parameter; provide
            one or the other, not both. When using this form, set the path
            segment to the literal `.`.
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpsertSegmentRequest'
      responses:
        '200':
          description: Existing segment updated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SegmentResponse'
        '201':
          description: New segment created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SegmentResponse'
        '400':
          description: Invalid request body
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AudienceErrorResponse'
        '401':
          description: Missing or invalid API key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AudienceErrorResponse'
        '501':
          description: Audience endpoints not enabled
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
    patch:
      tags:
        - Audience
      operationId: updateAudienceSegment
      summary: Update an audience segment
      description: |
        Partially updates an existing audience segment by ID.

        The segment ID may be passed as a path parameter or as the `id` query
        parameter (e.g. `PATCH /v2026/audience/segments?id={segment_id}`). When
        the path parameter is the literal `.`, the handler reads `id` from the
        query string instead. Path and query must not both be provided.
      security:
        - audienceApiKey: []
      parameters:
        - $ref: '#/components/parameters/SegmentID'
        - $ref: '#/components/parameters/AccessKey'
        - name: id
          in: query
          description: |
            Segment ID via query parameter (query-only alternate form).
            Mutually exclusive with the `segment_id` path parameter; provide
            one or the other, not both. When using this form, set the path
            segment to the literal `.`.
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateSegmentRequest'
      responses:
        '200':
          description: Segment updated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SegmentResponse'
        '400':
          description: Invalid request body
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AudienceErrorResponse'
        '401':
          description: Missing or invalid API key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AudienceErrorResponse'
        '404':
          description: Segment not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AudienceErrorResponse'
        '501':
          description: Audience endpoints not enabled
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
    delete:
      tags:
        - Audience
      operationId: deleteAudienceSegment
      summary: Delete an audience segment
      description: |
        Deletes an audience segment by ID.

        The segment ID may be passed as a path parameter or as the `id` query
        parameter (e.g. `DELETE /v2026/audience/segments?id={segment_id}`). When
        the path parameter is the literal `.`, the handler reads `id` from the
        query string instead. Path and query must not both be provided.
      security:
        - audienceApiKey: []
      parameters:
        - $ref: '#/components/parameters/SegmentID'
        - $ref: '#/components/parameters/AccessKey'
        - name: id
          in: query
          description: |
            Segment ID via query parameter (query-only alternate form).
            Mutually exclusive with the `segment_id` path parameter; provide
            one or the other, not both. When using this form, set the path
            segment to the literal `.`.
          schema:
            type: string
      responses:
        '200':
          description: Segment deleted
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DeleteSegmentResponse'
        '401':
          description: Missing or invalid API key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AudienceErrorResponse'
        '404':
          description: Segment not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AudienceErrorResponse'
        '501':
          description: Audience endpoints not enabled
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
  /v2026/audience/segments/{segment_id}/identities:
    post:
      tags:
        - Audience
      operationId: addAudienceIdentities
      summary: Add identities to a segment
      description: |
        Creates or updates one or more identities in the specified audience
        segment. Identities are processed asynchronously.

        Accepts either a single `identity` object or a batch `identities` array.

        The segment ID may be passed as a path parameter or as the `segment_id`
        query parameter (e.g. `POST /v2026/audience/segments/./identities?segment_id={id}`).
        When the path parameter is the literal `.`, the handler reads `segment_id`
        from the query string instead. Path and query must not both be provided.
      security:
        - audienceApiKey: []
      parameters:
        - $ref: '#/components/parameters/SegmentID'
        - $ref: '#/components/parameters/AccessKey'
        - $ref: '#/components/parameters/OkParam'
        - name: segment_id
          in: query
          description: |
            Segment ID via query parameter (query-only alternate form).
            Mutually exclusive with the `segment_id` path parameter; provide
            one or the other, not both. When using this form, set the path
            segment to the literal `.`.
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AddIdentitiesRequest'
            examples:
              single:
                summary: Single identity (array identifiers)
                value:
                  identity:
                    id: user_123
                    identifiers:
                      - kind: email
                        value: someone@example.com
              batch:
                summary: Batch of identities
                value:
                  identities:
                    - id: user_123
                      identifiers:
                        - kind: email
                          value: someone@example.com
                    - id: user_456
                      identifiers:
                        - kind: email_sha256
                          value: 836f82db99121b3481011f16b49dfa5fbc714a0d1b1b9f784a1ebbbf5b39577f
              objectIdentifiers:
                summary: Single identity (object identifiers, one per kind)
                value:
                  identity:
                    id: user_123
                    identifiers:
                      email: someone@example.com
                      phone: '+15555550100'
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |
            curl -X POST "https://integrations.ex.mountain.com/v2026/audience/segments/high-value-customers/identities" \
              -H "Authorization: Bearer $MNTN_API_KEY" \
              -H "Content-Type: application/json" \
              -d '{"identity":{"id":"user_123","identifiers":[{"kind":"email","value":"someone@example.com"}]}}'
        - lang: Python
          label: Python
          source: |
            import requests

            resp = requests.post(
                "https://integrations.ex.mountain.com/v2026/audience/segments/high-value-customers/identities",
                headers={"Authorization": f"Bearer {MNTN_API_KEY}"},
                json={"identity": {"id": "user_123", "identifiers": [
                    {"kind": "email", "value": "someone@example.com"},
                ]}},
            )
            resp.raise_for_status()
        - lang: JavaScript
          label: JavaScript
          source: |
            await fetch(
              "https://integrations.ex.mountain.com/v2026/audience/segments/high-value-customers/identities",
              {
                method: "POST",
                headers: {
                  Authorization: `Bearer ${MNTN_API_KEY}`,
                  "Content-Type": "application/json",
                },
                body: JSON.stringify({
                  identity: {
                    id: "user_123",
                    identifiers: [{ kind: "email", value: "someone@example.com" }],
                  },
                }),
              },
            );
      responses:
        '202':
          description: Identities accepted for asynchronous processing
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EmptyResponse'
        '400':
          description: Invalid request body
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AudienceErrorResponse'
        '401':
          description: Missing or invalid API key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AudienceErrorResponse'
        '404':
          description: Segment not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AudienceErrorResponse'
        '501':
          description: Audience endpoints not enabled
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
  /v2026/audience/segments/{segment_id}/identities/{identity_id}:
    put:
      tags:
        - Audience
      operationId: upsertAudienceIdentity
      summary: Upsert a single identity in a segment
      description: |
        Creates or replaces a single identity in the specified audience segment.
        The identity is processed asynchronously.

        The segment ID and identity ID may each be passed as path parameters or
        as query parameters (e.g.
        `PUT /v2026/audience/segments/./identities?id={identity_id}&segment_id={segment_id}`).
        When a path parameter is the literal `.`, the handler reads the
        corresponding query parameter instead. Path and query must not both be
        provided for the same parameter.
      security:
        - audienceApiKey: []
      parameters:
        - $ref: '#/components/parameters/SegmentID'
        - $ref: '#/components/parameters/IdentityID'
        - $ref: '#/components/parameters/AccessKey'
        - $ref: '#/components/parameters/OkParam'
        - name: segment_id
          in: query
          description: |
            Segment ID via query parameter (query-only alternate form).
            Mutually exclusive with the `segment_id` path parameter.
          schema:
            type: string
        - name: id
          in: query
          description: |
            Identity ID via query parameter (query-only alternate form).
            Mutually exclusive with the `identity_id` path parameter.
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpsertIdentityRequest'
            examples:
              arrayForm:
                summary: Array identifiers
                value:
                  identity:
                    identifiers:
                      - kind: email
                        value: someone@example.com
                      - kind: phone
                        value: '+15555550100'
              objectForm:
                summary: Object identifiers (one per kind)
                value:
                  identity:
                    source: crm-export
                    identifiers:
                      email: someone@example.com
                      phone: '+15555550100'
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |
            curl -X PUT "https://integrations.ex.mountain.com/v2026/audience/segments/high-value-customers/identities/user_123" \
              -H "Authorization: Bearer $MNTN_API_KEY" \
              -H "Content-Type: application/json" \
              -d '{"identity":{"identifiers":[{"kind":"email","value":"someone@example.com"}]}}'
        - lang: Python
          label: Python
          source: |
            import requests

            resp = requests.put(
                "https://integrations.ex.mountain.com/v2026/audience/segments/high-value-customers/identities/user_123",
                headers={"Authorization": f"Bearer {MNTN_API_KEY}"},
                json={"identity": {"identifiers": [
                    {"kind": "email", "value": "someone@example.com"},
                ]}},
            )
            resp.raise_for_status()
        - lang: JavaScript
          label: JavaScript
          source: |
            await fetch(
              "https://integrations.ex.mountain.com/v2026/audience/segments/high-value-customers/identities/user_123",
              {
                method: "PUT",
                headers: {
                  Authorization: `Bearer ${MNTN_API_KEY}`,
                  "Content-Type": "application/json",
                },
                body: JSON.stringify({
                  identity: {
                    identifiers: [{ kind: "email", value: "someone@example.com" }],
                  },
                }),
              },
            );
      responses:
        '202':
          description: Identity accepted for asynchronous processing
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EmptyResponse'
        '400':
          description: Invalid request body
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AudienceErrorResponse'
        '401':
          description: Missing or invalid API key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AudienceErrorResponse'
        '404':
          description: Segment not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AudienceErrorResponse'
        '501':
          description: Audience endpoints not enabled
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
    delete:
      tags:
        - Audience
      operationId: deleteAudienceIdentities
      summary: Remove identities from a segment
      description: |
        Removes one or more identities from the specified audience segment.
        The operation is asynchronous and always succeeds regardless of whether
        the identities currently exist.

        The `identity_id` path parameter accepts a single ID or a
        comma-separated list of IDs (URL-encode the comma as `%2C`), e.g.
        `DELETE /v2026/audience/segments/{segment_id}/identities/user-001%2Cuser-002`.

        As an alternate form, pass the literal `.` in the `identity_id` path
        position and provide comma-separated IDs via `?id=a,b,c` (e.g.
        `DELETE /v2026/audience/segments/{segment_id}/identities/.?id=user-001,user-002`).

        The segment ID may likewise be passed as a query parameter by using
        `.` in the `segment_id` path position (e.g.
        `DELETE /v2026/audience/segments/./identities/.?id={ids}&segment_id={segment_id}`).
        When a path parameter is the literal `.`, the handler reads the
        corresponding query parameter instead. Path and query must not both be
        provided for the same parameter.
      security:
        - audienceApiKey: []
      parameters:
        - $ref: '#/components/parameters/SegmentID'
        - name: identity_id
          in: path
          required: true
          description: |
            One or more identity IDs. Accepts a single ID or a comma-separated
            list (URL-encode the comma as `%2C`), e.g. `user-001%2Cuser-002`.
            Use the literal `.` to provide the IDs via the `id` query parameter
            instead.
          style: simple
          explode: false
          schema:
            type: array
            items:
              type: string
        - $ref: '#/components/parameters/AccessKey'
        - $ref: '#/components/parameters/OkParam'
        - name: segment_id
          in: query
          description: |
            Segment ID via query parameter (query-only alternate form).
            Mutually exclusive with the `segment_id` path parameter.
          schema:
            type: string
        - name: id
          in: query
          description: |
            Comma-separated identity IDs via query parameter (query-only
            alternate form). Mutually exclusive with the `identity_id` path
            parameter.
          schema:
            type: string
      responses:
        '202':
          description: Identity removal accepted for asynchronous processing
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EmptyResponse'
        '400':
          description: Invalid request parameters
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AudienceErrorResponse'
        '401':
          description: Missing or invalid API key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AudienceErrorResponse'
        '404':
          description: Segment not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AudienceErrorResponse'
        '501':
          description: Audience endpoints not enabled
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
components:
  parameters:
    SegmentID:
      name: segment_id
      in: path
      required: true
      description: |
        Unique segment identifier. Use the literal `.` when providing the
        segment ID via query parameter instead.
      schema:
        type: string
        pattern: ^(\.|[a-zA-Z0-9][a-zA-Z0-9\-_]+)$
        example: high-value-customers
    IdentityID:
      name: identity_id
      in: path
      required: true
      description: |
        Unique identity identifier (single scalar). Use the literal `.` when
        providing the identity ID via the `id` query parameter instead.
      schema:
        type: string
    AccessKey:
      name: access_key
      in: query
      description: |
        API key for authentication. This is an alternative to the
        `Authorization` header. Not encouraged due to the increased likelihood
        of the key being logged or cached along with the URL.
      schema:
        type: string
    OkParam:
      name: ok
      in: query
      description: |
        When set to `200`, the endpoint responds with HTTP 200 instead of the
        default 202. Used for compatibility with callers that are hard-coded
        to expect status 200.
      schema:
        type: integer
        enum:
          - 200
  securitySchemes:
    audienceApiKey:
      type: http
      scheme: bearer
      description: |
        All `/v2026/audience/*` endpoints require an MNTN Audience API key
        provided via HTTP Bearer authentication:

        `Authorization: Bearer {api_key}`

        Generate a key from the Integrations page in the MNTN platform when you
        connect the Audience integration.

        Authentication is validated against Orca's secret store. The handler
        extracts the caller's advertiser ID, connection ID, and integration key
        from the resolved secret.
  schemas:
    AcceptedResponse:
      type: object
      description: Returned when the webhook has been successfully accepted and queued.
      properties:
        status:
          type: string
          description: Always `"accepted"`
          example: accepted
    ErrorResponse:
      type: object
      description: Returned when the request is invalid or an internal error occurs.
      properties:
        error:
          type: string
          description: Human-readable error message
          example: 'request body has an error: doesn''t match schema'
    EmptyResponse:
      type: object
      description: Empty JSON response body (`{}`).
    AudienceError:
      type: object
      description: Structured error detail for audience endpoints.
      required:
        - code
        - detail
      properties:
        code:
          type: string
          description: Machine-readable error code
          example: SegmentNotFound
        detail:
          type: string
          description: Human-readable error description
          example: An audience segment with the provided ID does not exist
        subject:
          type: string
          description: The field or entity that caused the error
          example: url.segment_id
    AudienceErrorResponse:
      type: object
      description: |
        Error response envelope for audience endpoints. The error detail is
        nested under the `error` key.
      required:
        - error
      properties:
        error:
          $ref: '#/components/schemas/AudienceError'
    TimeCreated:
      type: object
      description: Timestamp in dual format.
      properties:
        unix:
          type: integer
          format: int64
          description: Unix epoch timestamp in seconds
          example: 1711209600
        rfc3339:
          type: string
          description: RFC 3339 formatted timestamp
          example: '2025-03-23T12:00:00Z'
    AudienceSegment:
      type: object
      description: An audience segment.
      properties:
        id:
          type: string
          description: Unique segment identifier
          example: my-segment-01
        name:
          type: string
          description: Display name for the segment
          example: High-Value Customers
        time_created:
          $ref: '#/components/schemas/TimeCreated'
    SegmentResponse:
      type: object
      description: Single segment response envelope.
      properties:
        segment:
          $ref: '#/components/schemas/AudienceSegment'
    DeleteSegmentResponse:
      type: object
      description: Response after deleting a segment.
      required:
        - segment
      properties:
        segment:
          type: object
          description: Always `null` after deletion.
          nullable: true
          example: null
    ListSegmentsResponse:
      type: object
      description: Paginated list of audience segments.
      properties:
        slice:
          type: object
          description: Mirrors the pagination query parameters that were received.
          properties:
            after:
              description: The `after` cursor value from the request.
            limit:
              type: integer
              description: The `limit` value from the request.
            order:
              type: string
              description: The `order` value from the request.
        segments:
          type: array
          items:
            $ref: '#/components/schemas/AudienceSegment'
    CreateSegmentRequest:
      type: object
      description: Request body for creating a new audience segment.
      required:
        - segment
      properties:
        segment:
          type: object
          required:
            - name
          properties:
            id:
              type: string
              description: |
                Optional caller-assigned segment ID. If omitted, a new ID is
                auto-generated.
              pattern: ^[a-zA-Z0-9][a-zA-Z0-9\-_]+$
              example: high-value-customers
            name:
              type: string
              description: Display name for the segment.
            source:
              type: string
              description: Optional source identifier for lineage tracking.
    UpsertSegmentRequest:
      type: object
      description: Request body for upserting (create or replace) an audience segment.
      required:
        - segment
      properties:
        segment:
          type: object
          required:
            - name
          properties:
            name:
              type: string
              description: Display name for the segment.
            source:
              type: string
              description: Optional source identifier for lineage tracking.
    UpdateSegmentRequest:
      type: object
      description: Request body for partially updating an audience segment (PATCH).
      required:
        - segment
      properties:
        segment:
          type: object
          properties:
            name:
              type: string
              description: Display name for the segment.
    SourceTime:
      type: object
      description: |
        Source event timestamp. Provide exactly one of `unix` or `rfc3339`.
      properties:
        unix:
          type: integer
          format: int64
          description: Unix epoch timestamp in seconds
        rfc3339:
          type: string
          description: RFC 3339 formatted timestamp (e.g. `2025-03-23T12:00:00Z`)
    Identifier:
      type: object
      description: |
        A single signal identifier targeting an audience member. The `kind`
        specifies the token type (e.g. `ipv4`, `email`, `phone`, `maid`).
      required:
        - kind
        - value
      properties:
        kind:
          type: string
          description: |
            Identifier type. First-class kinds: `ipv4`, `email`,
            `email_sha256`, `phone`, `phone_sha256`. Also accepted:
            `ipv4_sha256`, `ipv6`, `ipv6_sha256`, `maid`, `ipx` (mixed/unknown
            IP version, normalized to `ipv4` or `ipv6` before it reaches
            downstream schemas).

            `ipv4`, `ipv6`, and `ipx` values are validated. A malformed
            value, or one in the unspecified, loopback, private, or multicast
            ranges (plus the IPv4 broadcast address), is dropped without
            error, and an identity left with no usable identifiers is not
            published.
          example: email
        value:
          type: string
          description: The identifier value
          example: someone@example.com
    IdentityInput:
      type: object
      description: |
        A single identity to add to an audience segment. Used in both the
        single-identity (`identity`) and batch (`identities`) request forms.
      required:
        - id
        - identifiers
      properties:
        id:
          type: string
          description: Unique identity identifier
          example: user_123
        source:
          type: string
          description: Optional source identifier for lineage tracking
        source_time:
          $ref: '#/components/schemas/SourceTime'
        identifiers:
          description: |
            One or more signal identifiers for this audience member. Must be
            non-empty.

            **Primary form (array):** `[{"kind": "email", "value": "a@b.com"}, ...]`

            **Alternate form (object):** `{"email": "a@b.com", ...}` (limited
            to one identifier per kind).

            Both forms are accepted. Validation is performed by the handler.
    AddIdentitiesRequest:
      type: object
      description: |
        Request body for adding identities to a segment. Provide either a
        single `identity` object or a batch `identities` array, but not both.
      properties:
        identity:
          $ref: '#/components/schemas/IdentityInput'
        identities:
          type: array
          description: |
            Batch of identities. No limit on item count; total request body
            size is limited (2 MiB maximum, 1 MiB recommended).
          items:
            $ref: '#/components/schemas/IdentityInput'
          minItems: 1
    EventSourceTime:
      type: object
      description: |
        Source event timestamp. Provide exactly one of `unix` or `rfc3339`.
      properties:
        unix:
          type: number
          format: double
          description: |
            Unix epoch timestamp in seconds. Fractional values are accepted
            for sub-second precision (e.g. `1780963227.123`).
        rfc3339:
          type: string
          description: RFC 3339 formatted timestamp (e.g. `2025-03-23T12:00:00Z`)
    IngestConversionsRequest:
      type: object
      description: |
        Request body for conversion events. Provide either a single
        `conversion` object or a batch `conversions` array, but not both.
      properties:
        conversion:
          $ref: '#/components/schemas/ConversionEvent'
        conversions:
          type: array
          description: Batch of conversion events.
          items:
            $ref: '#/components/schemas/ConversionEvent'
          minItems: 1
    ConversionEvent:
      type: object
      description: A single conversion / in-app event.
      required:
        - event_kind
        - identity
        - source_time
      additionalProperties: true
      properties:
        event_id:
          type: string
          description: Optional client-supplied event ID for dedup/idempotency.
        event_kind:
          type: string
          description: |
            Free-form event name (maps to the partner's event name, e.g.
            Singular's `event_name`). Keep to 128 printable-ASCII characters
            or fewer; the value is currently forwarded downstream as-is,
            without server-side normalization. Callers in regulated
            industries, such as healthcare, are responsible for ensuring no
            PHI is sent in this field.
          example: Start Trial
        identity:
          type: object
          required:
            - identifiers
          additionalProperties: true
          properties:
            identifiers:
              type: array
              minItems: 1
              items:
                $ref: '#/components/schemas/Identifier'
        order:
          type: object
          description: Optional order/purchase detail.
          additionalProperties: true
          properties:
            order_id:
              type: string
            amount:
              type: number
              format: double
            currency:
              type: string
              description: ISO 4217 currency code (e.g. `USD`).
        source_time:
          $ref: '#/components/schemas/EventSourceTime'
    UpsertIdentityRequest:
      type: object
      description: |
        Request body for upserting a single identity. The identity ID is
        provided via the path or query parameter, not in the body.
      properties:
        identity:
          type: object
          required:
            - identifiers
          properties:
            source:
              type: string
              description: Optional source identifier for lineage tracking
            source_time:
              $ref: '#/components/schemas/SourceTime'
            identifiers:
              description: |
                One or more signal identifiers. Must be non-empty.

                **Primary form (array):** `[{"kind": "email", "value": "a@b.com"}, ...]`

                **Alternate form (object):** `{"email": "a@b.com", ...}` (limited
                to one identifier per kind).

                Both forms are accepted. Validation is performed by the handler.
