openapi: 3.1.0
info:
  title: Webhook Subscription API
  version: v3
servers:
  - url: https://api-ext-sboxmeta.partners.spotnana.com
    description: Sandbox URL
security:
  - Bearer: []
components:
  securitySchemes:
    Bearer:
      type: http
      scheme: bearer
  responses:
    BadRequest:
      description: Bad request
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    Forbidden:
      description: Forbidden
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    NotFound:
      description: The specified resource was not found.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    Unauthorized:
      description: Unauthorized
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
  schemas:
    CreateWebhookSubscriptionRequest:
      type: object
      required:
        - subscriberId
        - eventTypes
        - url
      properties:
        subscriberId:
          type: string
          format: uuid
          description: |
            UUID of the company that owns this webhook subscription.
        eventSource:
          allOf:
            - $ref: '#/components/schemas/EventSource'
          description: >
            Defines the scope of source companies whose events this subscription
            will receive. 

            If not provided, defaults to a COMPANY scope targeting the
            subscriberId.
        name:
          type: string
          description: |
            Optional human-readable display name for the subscription.
            If not provided, a default name will be assigned.
        eventTypes:
          type: array
          description: >-
            List of event types this subscription should receive. At least one
            is required.
          items:
            $ref: '#/components/schemas/WebhookEventTypeEnum'
          minItems: 1
        url:
          type: string
          format: uri
          description: >
            HTTPS endpoint that Spotnana will POST event payloads to. Must use
            the `https`

            scheme and accept `POST` requests.
        isActive:
          type: boolean
          default: true
          description: >
            Whether the subscription is active. When `false`, the subscription
            is preserved but

            incoming events will not be matched against it and no deliveries
            will be made.
        customHeaders:
          type: object
          description: >
            Additional HTTP headers to include on every webhook request sent to
            `url`. Provided

            as a map of header name to header value. Reserved headers managed by
            Spotnana

            (such as `Authorization` and `Content-Type`) will override any
            values supplied here.
          additionalProperties:
            type: string
            x-additionalPropertiesName: headerName
          example:
            X-Custom-Header: my-value
            Authorization-Extra: token123
    CreateWebhookSubscriptionResponse:
      type: object
      required:
        - id
        - createdAt
      properties:
        id:
          type: string
          format: uuid
          description: UUID of the newly created webhook subscription.
        hmacSigningSecret:
          type: string
          description: >
            Secret used to verify the HMAC-SHA256 signature on incoming webhook
            requests.

            Returned only once, at subscription creation, and cannot be
            retrieved later. Store

            it securely.
        createdAt:
          allOf:
            - $ref: '#/components/schemas/DateModel'
          description: Timestamp at which the subscription was created.
    DateModel:
      title: Date
      description: Date in ISO 8601 standard.
      type: object
      required:
        - iso8601
      properties:
        iso8601:
          type: string
          pattern: ^\d{4}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])$
          example: '2017-07-21'
    ErrorParameter:
      type: object
      title: ErrorParameter
      description: Error parameter
      properties:
        name:
          type: string
          description: Parameter name
        value:
          type: string
          description: Parameter value
    ErrorResponse:
      type: object
      properties:
        debugIdentifier:
          type: string
          description: Link to debug the error internally.
        errorMessages:
          type: array
          items:
            type: object
            properties:
              errorCode:
                type: string
                description: Error code to identify the specific errors.
              message:
                type: string
                description: Message containing details of error.
              errorParameters:
                type: array
                description: Error message parameters.
                items:
                  $ref: '#/components/schemas/ErrorParameter'
              errorDetail:
                type: string
                description: More details about the error.
    EventSource:
      type: object
      description: >
        Defines which event sources a subscription should match. Contains a list
        of scopes

        that are OR'd together — an event matches if it satisfies ANY scope.
      required:
        - scopes
      properties:
        scopes:
          type: array
          description: >
            List of scopes evaluated with OR logic. An event matches if at least
            one scope

            is satisfied.
          items:
            $ref: '#/components/schemas/EventSourceScope'
          minItems: 1
    EventSourcePredicate:
      type: object
      description: >
        A single predicate that constrains which event sources match. The
        event's value

        for the given `type` is evaluated against `values` using the
        `comparator`.
      required:
        - type
        - values
      properties:
        type:
          $ref: '#/components/schemas/EventSourceScopeType'
        values:
          type: array
          description: List of entity IDs to match against.
          items:
            type: string
            format: uuid
          minItems: 1
        comparator:
          allOf:
            - $ref: '#/components/schemas/EventSourceScopeComparator'
          description: Comparator for evaluation. Defaults to `IN`.
        valuesWithLabel:
          type: array
          description: >
            Server-resolved labels for each entry in `values`. Read-only,
            returned only

            in responses.
          items:
            $ref: '#/components/schemas/EventSourceValueWithLabel'
          readOnly: true
    EventSourceScope:
      type: object
      description: >
        A single scope consisting of one or more predicates. All predicates
        within a scope

        are AND'd together — the scope matches only when every predicate is
        satisfied.
      required:
        - predicates
      properties:
        predicates:
          type: array
          description: >-
            List of predicates that must all be satisfied for this scope to
            match.
          items:
            $ref: '#/components/schemas/EventSourcePredicate'
          minItems: 1
    EventSourceScopeComparator:
      type: string
      description: Comparator used to evaluate the predicate.
      default: IN
      enum:
        - IN
    EventSourceScopeType:
      type: string
      description: The type of event source entity.
      enum:
        - COMPANY
        - BOOKING_TMC
        - CONTRACTING_TMC
    EventSourceValueWithLabel:
      type: object
      description: An event source entity ID paired with its resolved display name.
      required:
        - id
        - name
      properties:
        id:
          type: string
          format: uuid
          description: UUID of the entity.
        name:
          type: string
          description: Display name of the entity.
    ListWebhookSubscriptionsResponse:
      type: object
      required:
        - subscriptions
        - totalCount
      properties:
        subscriptions:
          type: array
          description: Page of webhook subscriptions matching the request.
          items:
            $ref: '#/components/schemas/WebhookSubscription'
        totalCount:
          type: integer
          description: Total number of subscriptions for the subscriber, across all pages.
    UpdateWebhookSubscriptionRequest:
      type: object
      description: >
        Partial update for a webhook subscription. Only fields included in the
        request body are

        modified; omitted fields are left unchanged.
      properties:
        eventSource:
          allOf:
            - $ref: '#/components/schemas/EventSource'
          description: >
            Replacement event source scope. If provided, fully replaces the
            existing scope.
        name:
          type: string
          description: Human-readable display name for the subscription.
        eventTypes:
          type: array
          description: >
            Replacement list of event types this subscription should receive. If
            provided, must

            contain at least one entry; the new list fully replaces the existing
            one.
          items:
            $ref: '#/components/schemas/WebhookEventTypeEnum'
          minItems: 1
        isActive:
          type: boolean
          description: >
            Whether the subscription is active. When `false`, the subscription
            is preserved but

            incoming events will not be matched against it and no deliveries
            will be made.
        url:
          type: string
          format: uri
          description: >
            HTTPS endpoint that Spotnana will POST event payloads to. Must use
            the `https`

            scheme and accept `POST` requests.
        customHeaders:
          type: object
          description: >
            Replacement set of additional HTTP headers to include on every
            webhook request.

            Sending an empty map clears all existing custom headers; omitting
            the field leaves

            them unchanged. Reserved headers managed by Spotnana (such as
            `Authorization` and

            `Content-Type`) will override any values supplied here.
          additionalProperties:
            type: string
            x-additionalPropertiesName: headerName
            example:
              X-Custom-Header: my-value
              Authorization-Extra: token123
    WebhookAuthTypeEnum:
      type: string
      default: HMAC_SHA256
      enum:
        - OAUTH2
        - HMAC_SHA256
    WebhookEventTypeEnum:
      type: string
      description: Type of event the webhook subscription will receive.
      enum:
        - TRAVELER_V2
        - PNR_V3
        - TRIP_DETAILS_V3
        - PNR_APPROVAL
        - AGENT_TASK_DETAILS
        - SERVICE_CHARGE
    WebhookSubscription:
      type: object
      required:
        - id
        - subscriberId
        - eventSource
        - name
        - eventTypes
        - url
        - authType
        - isActive
      properties:
        id:
          type: string
          format: uuid
          description: UUID of the webhook subscription.
        name:
          type: string
          description: Human-readable display name for the subscription.
        eventTypes:
          type: array
          description: List of event types this subscription is configured to receive.
          items:
            $ref: '#/components/schemas/WebhookEventTypeEnum'
        subscriberId:
          type: string
          format: uuid
          description: UUID of the company that owns this webhook subscription.
        eventSource:
          allOf:
            - $ref: '#/components/schemas/EventSource'
          description: |
            Defines which event sources this subscription matches.
        url:
          type: string
          format: uri
          description: HTTPS endpoint that Spotnana POSTs event payloads to.
        customHeaders:
          type: object
          description: >
            Additional HTTP headers included on every webhook request sent to
            `url`. Reserved

            headers managed by Spotnana (such as `Authorization` and
            `Content-Type`) take

            precedence over values configured here.
          additionalProperties:
            type: string
            x-additionalPropertiesName: headerName
          example:
            X-Custom-Header: my-value
            Authorization-Extra: token123
        isActive:
          type: boolean
          description: >
            Whether the subscription is active. When `false`, the subscription
            is preserved but

            incoming events will not be matched against it and no deliveries
            will be made.
        createdBy:
          type: string
          format: uuid
          description: UUID of the user who created the subscription.
        updatedBy:
          type: string
          format: uuid
          description: UUID of the user who last updated the subscription.
        createdAt:
          allOf:
            - $ref: '#/components/schemas/DateModel'
          description: Timestamp at which the subscription was created.
        updatedAt:
          allOf:
            - $ref: '#/components/schemas/DateModel'
          description: Timestamp at which the subscription was last updated.
tags:
  - name: Webhook Subscription
    description: APIs to create, list, retrieve, and update webhook subscriptions.
paths:
  /v3/webhooks/subscriptions:
    post:
      tags:
        - Webhook Subscription
      summary: Create Webhook Subscription
      operationId: createWebhookSubscription
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateWebhookSubscriptionRequest'
      responses:
        '201':
          description: Successful Webhook Subscription Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreateWebhookSubscriptionResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
  /v3/webhooks/subscriptions/subscriber/{subscriberId}/list:
    get:
      tags:
        - Webhook Subscription
      summary: List Webhook Subscriptions
      operationId: listWebhookSubscriptions
      parameters:
        - name: subscriberId
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            default: 50
        - name: offset
          in: query
          required: false
          schema:
            type: integer
            default: 0
      responses:
        '200':
          description: Successful List Webhook Subscriptions Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListWebhookSubscriptionsResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
  /v3/webhooks/subscriptions/{subscriptionId}:
    get:
      tags:
        - Webhook Subscription
      summary: Get Webhook Subscription
      operationId: getWebhookSubscription
      parameters:
        - name: subscriptionId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: Successful Get Webhook Subscription Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WebhookSubscription'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
    patch:
      tags:
        - Webhook Subscription
      summary: Update Webhook Subscription
      operationId: updateWebhookSubscription
      parameters:
        - name: subscriptionId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateWebhookSubscriptionRequest'
      responses:
        '200':
          description: Webhook Subscription Updated Successfully
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
