asyncapi: '2.6.0'

info:
  title: EventZR Notification Service - Kafka Event API
  version: '1.0.0'
  description: |
    AsyncAPI specification for the **notify-svc** Kafka event channels.

    The notify-svc is the central notification orchestration service for the
    EventZR platform. It dispatches notifications across multiple channels
    (email, SMS, WhatsApp, push), manages notification templates, tracks
    delivery status, handles bounces, and records per-notification costs.

    **Event Format:** All produced events follow the [CloudEvents 1.0](https://cloudevents.io/)
    specification with JSON encoding.

    **Partitioning:** Every Kafka topic is partitioned by `tenant_id` to
    guarantee per-tenant ordering and to align with the platform's
    multi-tenant isolation model.

    **Topic Naming Convention:** `eventzr.notify.<entity>.<action>.v<N>`

    **Kafka Summary:**
    - Produced topics: 11 (delivery lifecycle, suppression, templates, preferences, cost)
    - Consumed topics: 11 (auth OTP, bookings, events, invites, tickets, wallet)

    **Service metadata:**
    - Compute: AWS Lambda (us-east-1, 1536 MB, x86_64)
    - Framework: NestJS 11.1.7
    - REST Endpoints: 83 (across 15 controllers)
    - Database: Aurora PostgreSQL Serverless v2 (TypeORM, 6 tables)
    - Cache: ElastiCache Redis 7
    - External providers routed via integration-hub-svc (SendGrid, Twilio, WhatsApp Business API)
  contact:
    name: EventZR Platform Team
    email: platform@eventzr.com
    url: https://eventzr.com
  license:
    name: Proprietary
    url: https://eventzr.com/legal/license

servers:
  kafka-staging:
    url: boot-gpm4u49z.c2.kafka-serverless.us-east-1.amazonaws.com:9098
    protocol: kafka-secure
    protocolVersion: '3.6.0'
    description: |
      Amazon MSK Serverless cluster (staging environment).
      Authentication uses AWS MSK IAM (SASL OAUTHBEARER with aws-msk-iam-sasl-signer-js).
      All traffic is TLS-encrypted.
    security:
      - saslAwsMskIam: []
    bindings:
      kafka:
        schemaRegistryUrl: ''
        schemaRegistryVendor: ''

defaultContentType: application/json

tags:
  - name: delivery-lifecycle
    description: Notification sent, delivered, read, and failed events
  - name: bounces
    description: Email/SMS bounce tracking and auto-suppression
  - name: templates
    description: Notification template creation and updates
  - name: preferences
    description: User notification preference changes
  - name: billing
    description: Notification cost tracking and billing events
  - name: auth-events
    description: Authentication events consumed from auth-svc
  - name: booking-events
    description: Booking events consumed from booking-svc
  - name: event-events
    description: Event lifecycle events consumed from event-svc
  - name: invite-events
    description: Invitation events consumed from invite-svc
  - name: ticketing-events
    description: Ticketing events consumed from ticketing-svc
  - name: wallet-events
    description: Wallet and payment events consumed from wallet-svc

# ---------------------------------------------------------------------------
# CHANNELS
# ---------------------------------------------------------------------------
channels:
  # ==========================================================================
  # DELIVERY LIFECYCLE (produced)
  # ==========================================================================

  eventzr.notify.sent.v1:
    description: |
      Published when a notification is successfully dispatched to the delivery
      provider (SendGrid, Twilio, WhatsApp Business API, Firebase Cloud Messaging).
      This does NOT mean the notification was delivered to the end user -- only
      that it was accepted by the provider.
      Consumed by: analytics-svc, audit-svc
    bindings:
      kafka:
        partitions: 12
        replicas: 3
        topicConfiguration:
          retention.ms: 604800000
          cleanup.policy:
            - delete
    publish:
      operationId: publishNotificationSent
      summary: Notification sent to provider
      tags:
        - name: delivery-lifecycle
      bindings:
        kafka:
          groupId:
            type: string
            enum:
              - analytics-svc-consumer
              - audit-svc-consumer
          clientId:
            type: string
            enum:
              - notify-svc
          bindingVersion: '0.5.0'
      message:
        $ref: '#/components/messages/NotificationSent'

  eventzr.notify.delivered.v1:
    description: |
      Published when a provider delivery receipt confirms the notification
      reached the recipient. Not all channels support delivery receipts;
      for channels without receipts this event may not be emitted.
      Consumed by: analytics-svc
    bindings:
      kafka:
        partitions: 12
        replicas: 3
        topicConfiguration:
          retention.ms: 604800000
          cleanup.policy:
            - delete
    publish:
      operationId: publishNotificationDelivered
      summary: Notification delivered to recipient
      tags:
        - name: delivery-lifecycle
      bindings:
        kafka:
          groupId:
            type: string
            enum:
              - analytics-svc-consumer
          clientId:
            type: string
            enum:
              - notify-svc
          bindingVersion: '0.5.0'
      message:
        $ref: '#/components/messages/NotificationDelivered'

  eventzr.notify.read.v1:
    description: |
      Published when a notification is confirmed as read by the recipient
      (e.g., email open tracking pixel, WhatsApp read receipt, push
      notification tap). Not all channels support read tracking.
      Consumed by: analytics-svc
    bindings:
      kafka:
        partitions: 12
        replicas: 3
        topicConfiguration:
          retention.ms: 604800000
          cleanup.policy:
            - delete
    publish:
      operationId: publishNotificationRead
      summary: Notification read by recipient
      tags:
        - name: delivery-lifecycle
      bindings:
        kafka:
          groupId:
            type: string
            enum:
              - analytics-svc-consumer
          clientId:
            type: string
            enum:
              - notify-svc
          bindingVersion: '0.5.0'
      message:
        $ref: '#/components/messages/NotificationRead'

  eventzr.notify.failed.v1:
    description: |
      Published when notification delivery fails. Includes error details and
      whether the system will automatically retry. The retry policy is
      channel-specific (e.g., 3 retries with exponential backoff for email,
      2 retries for SMS).
      Consumed by: analytics-svc, support-svc
    bindings:
      kafka:
        partitions: 12
        replicas: 3
        topicConfiguration:
          retention.ms: 604800000
          cleanup.policy:
            - delete
    publish:
      operationId: publishNotificationFailed
      summary: Notification delivery failed
      tags:
        - name: delivery-lifecycle
      bindings:
        kafka:
          groupId:
            type: string
            enum:
              - analytics-svc-consumer
              - support-svc-consumer
          clientId:
            type: string
            enum:
              - notify-svc
          bindingVersion: '0.5.0'
      message:
        $ref: '#/components/messages/NotificationFailed'

  # ==========================================================================
  # BOUNCES (produced)
  # ==========================================================================

  eventzr.notify.bounced.v1:
    description: |
      Published when a notification bounces (email hard/soft bounce, SMS
      undeliverable, WhatsApp number not registered). Hard bounces trigger
      automatic suppression of the contact address. Soft bounces are tracked
      and may trigger suppression after repeated occurrences.
      Consumed by: user-svc, analytics-svc, crm-svc
    bindings:
      kafka:
        partitions: 12
        replicas: 3
        topicConfiguration:
          retention.ms: 604800000
          cleanup.policy:
            - delete
    publish:
      operationId: publishNotificationBounced
      summary: Notification bounced
      tags:
        - name: bounces
      bindings:
        kafka:
          groupId:
            type: string
            enum:
              - user-svc-consumer
              - analytics-svc-consumer
              - crm-svc-consumer
          clientId:
            type: string
            enum:
              - notify-svc
          bindingVersion: '0.5.0'
      message:
        $ref: '#/components/messages/NotificationBounced'

  # ==========================================================================
  # TEMPLATES (produced)
  # ==========================================================================

  eventzr.notify.template.created.v1:
    description: |
      Published when a new notification template is created. Templates are
      tenant-scoped and channel-specific, supporting locale-based variants.
      Consumed by: analytics-svc
    bindings:
      kafka:
        partitions: 12
        replicas: 3
        topicConfiguration:
          retention.ms: 604800000
          cleanup.policy:
            - delete
    publish:
      operationId: publishTemplateCreated
      summary: Notification template created
      tags:
        - name: templates
      bindings:
        kafka:
          groupId:
            type: string
            enum:
              - analytics-svc-consumer
          clientId:
            type: string
            enum:
              - notify-svc
          bindingVersion: '0.5.0'
      message:
        $ref: '#/components/messages/TemplateCreated'

  eventzr.notify.template.updated.v1:
    description: |
      Published when an existing notification template is updated (content,
      subject, locale variant, or metadata changes). Template updates are
      versioned to allow rollback.
      Consumed by: analytics-svc
    bindings:
      kafka:
        partitions: 12
        replicas: 3
        topicConfiguration:
          retention.ms: 604800000
          cleanup.policy:
            - delete
    publish:
      operationId: publishTemplateUpdated
      summary: Notification template updated
      tags:
        - name: templates
      bindings:
        kafka:
          groupId:
            type: string
            enum:
              - analytics-svc-consumer
          clientId:
            type: string
            enum:
              - notify-svc
          bindingVersion: '0.5.0'
      message:
        $ref: '#/components/messages/TemplateUpdated'

  eventzr.notify.template.deleted.v1:
    description: |
      Published when a notification template is soft-deleted. The template
      record is retained for audit purposes but marked as inactive and can
      no longer be used for sending notifications.
      Consumed by: analytics-svc
    bindings:
      kafka:
        partitions: 12
        replicas: 3
        topicConfiguration:
          retention.ms: 604800000
          cleanup.policy:
            - delete
    publish:
      operationId: publishTemplateDeleted
      summary: Notification template deleted
      tags:
        - name: templates
      bindings:
        kafka:
          groupId:
            type: string
            enum:
              - analytics-svc-consumer
          clientId:
            type: string
            enum:
              - notify-svc
          bindingVersion: '0.5.0'
      message:
        $ref: '#/components/messages/TemplateDeleted'

  # ==========================================================================
  # PREFERENCES (produced)
  # ==========================================================================

  eventzr.notify.preference.updated.v1:
    description: |
      Published when a user updates their notification preferences (e.g.,
      opting out of marketing emails, switching preferred channel from email
      to WhatsApp, or muting push notifications). Preferences are tenant-scoped.
      Consumed by: analytics-svc, crm-svc
    bindings:
      kafka:
        partitions: 12
        replicas: 3
        topicConfiguration:
          retention.ms: 604800000
          cleanup.policy:
            - delete
    publish:
      operationId: publishPreferenceUpdated
      summary: User notification preferences updated
      tags:
        - name: preferences
      bindings:
        kafka:
          groupId:
            type: string
            enum:
              - analytics-svc-consumer
              - crm-svc-consumer
          clientId:
            type: string
            enum:
              - notify-svc
          bindingVersion: '0.5.0'
      message:
        $ref: '#/components/messages/PreferenceUpdated'

  # ==========================================================================
  # BILLING (produced)
  # ==========================================================================

  eventzr.notify.cost_incurred.v1:
    description: |
      Published when a notification incurs a cost from the delivery provider.
      Used by wallet-svc and analytics-svc to track notification spend per
      tenant. Costs are calculated from provider pricing (e.g., SMS segment
      count, email send cost, WhatsApp conversation pricing).
      Consumed by: wallet-svc, analytics-svc
    bindings:
      kafka:
        partitions: 12
        replicas: 3
        topicConfiguration:
          retention.ms: 604800000
          cleanup.policy:
            - delete
    publish:
      operationId: publishCostIncurred
      summary: Notification cost incurred
      tags:
        - name: billing
      bindings:
        kafka:
          groupId:
            type: string
            enum:
              - wallet-svc-consumer
              - analytics-svc-consumer
          clientId:
            type: string
            enum:
              - notify-svc
          bindingVersion: '0.5.0'
      message:
        $ref: '#/components/messages/CostIncurred'

  eventzr.notify.suppressed.v1:
    description: |
      Published when a notification is suppressed due to opt-out, hard bounce,
      suppression list match, or quiet hours. Consumed by analytics-svc and
      crm-svc for suppression tracking and compliance reporting.
      Consumed by: analytics-svc, crm-svc
    bindings:
      kafka:
        partitions: 12
        replicas: 3
        topicConfiguration:
          retention.ms: 604800000
          cleanup.policy:
            - delete
    publish:
      operationId: publishSuppressed
      summary: Notification suppressed
      tags:
        - name: suppression
      bindings:
        kafka:
          groupId:
            type: string
            enum:
              - analytics-svc-consumer
              - crm-svc-consumer
          clientId:
            type: string
            enum:
              - notify-svc
          bindingVersion: '0.5.0'
      message:
        name: Suppressed
        title: Notification Suppressed Event
        contentType: application/json
        payload:
          type: object
          properties:
            specversion:
              type: string
              const: '1.0'
            type:
              type: string
              const: com.eventzr.notify.suppressed
            source:
              type: string
            id:
              type: string
              format: uuid
            time:
              type: string
              format: date-time
            tenantid:
              type: string
              format: uuid
            data:
              type: object
              properties:
                notificationId:
                  type: string
                  format: uuid
                channel:
                  type: string
                  enum: [email, sms, whatsapp, push]
                reason:
                  type: string
                  enum: [hard_bounce, complaint, opt_out, suppression_list, quiet_hours]
                contact:
                  type: string
                suppressionType:
                  type: string

  # ==========================================================================
  # CONSUMED CHANNELS (subscribed from upstream services)
  # ==========================================================================

  # ---- auth-svc ----

  eventzr.auth.otp.requested.v1:
    description: |
      Consumed from auth-svc when a user requests an OTP. notify-svc sends
      the OTP code via the user's preferred channel (SMS, email, or WhatsApp).
      SLA: 10 seconds (CRITICAL).
      Consumer group: notify-svc-auth-consumer
    subscribe:
      operationId: consumeOtpRequested
      summary: OTP requested - send OTP notification
      tags:
        - name: auth-events
      bindings:
        kafka:
          groupId:
            type: string
            enum:
              - notify-svc-auth-consumer
          clientId:
            type: string
            enum:
              - notify-svc
          bindingVersion: '0.5.0'
      message:
        $ref: '#/components/messages/AuthOtpRequested'

  # ---- booking-svc ----

  eventzr.booking.confirmed.v1:
    description: |
      Consumed from booking-svc when a booking is confirmed. notify-svc sends
      a booking confirmation notification to the user with event details and
      booking reference.
      SLA: 1 minute (HIGH).
      Consumer group: notify-svc-booking-consumer
    subscribe:
      operationId: consumeBookingConfirmed
      summary: Booking confirmed - send confirmation notification
      tags:
        - name: booking-events
      bindings:
        kafka:
          groupId:
            type: string
            enum:
              - notify-svc-booking-consumer
          clientId:
            type: string
            enum:
              - notify-svc
          bindingVersion: '0.5.0'
      message:
        $ref: '#/components/messages/BookingConfirmed'

  eventzr.booking.checkin_time.v1:
    description: |
      Consumed from booking-svc when it is T-24h before an event check-in.
      notify-svc sends a check-in reminder notification to the user.
      SLA: 1 minute (HIGH).
      Consumer group: notify-svc-booking-consumer
    subscribe:
      operationId: consumeCheckInReminder
      summary: Check-in time approaching - send reminder notification
      tags:
        - name: booking-events
      bindings:
        kafka:
          groupId:
            type: string
            enum:
              - notify-svc-booking-consumer
          clientId:
            type: string
            enum:
              - notify-svc
          bindingVersion: '0.5.0'
      message:
        $ref: '#/components/messages/BookingCheckInTime'

  # ---- event-svc ----

  eventzr.events.published.v1:
    description: |
      Consumed from event-svc when an event is published. notify-svc sends
      notifications to followers/subscribers about the new event.
      SLA: 5 minutes (NORMAL).
      Consumer group: notify-svc-event-consumer
    subscribe:
      operationId: consumeEventPublished
      summary: Event published - notify followers
      tags:
        - name: event-events
      bindings:
        kafka:
          groupId:
            type: string
            enum:
              - notify-svc-event-consumer
          clientId:
            type: string
            enum:
              - notify-svc
          bindingVersion: '0.5.0'
      message:
        $ref: '#/components/messages/EventPublished'

  eventzr.events.updated.v1:
    description: |
      Consumed from event-svc when an event is updated (date, venue, or
      details change). notify-svc sends update notifications to ticket holders.
      SLA: 1 minute (HIGH).
      Consumer group: notify-svc-event-consumer
    subscribe:
      operationId: consumeEventUpdated
      summary: Event updated - notify ticket holders
      tags:
        - name: event-events
      bindings:
        kafka:
          groupId:
            type: string
            enum:
              - notify-svc-event-consumer
          clientId:
            type: string
            enum:
              - notify-svc
          bindingVersion: '0.5.0'
      message:
        $ref: '#/components/messages/EventUpdated'

  eventzr.events.cancelled.v1:
    description: |
      Consumed from event-svc when an event is cancelled. notify-svc sends
      cancellation notifications to all ticket holders with refund information.
      SLA: 1 minute (HIGH).
      Consumer group: notify-svc-event-consumer
    subscribe:
      operationId: consumeEventCancelled
      summary: Event cancelled - notify holders with refund info
      tags:
        - name: event-events
      bindings:
        kafka:
          groupId:
            type: string
            enum:
              - notify-svc-event-consumer
          clientId:
            type: string
            enum:
              - notify-svc
          bindingVersion: '0.5.0'
      message:
        $ref: '#/components/messages/EventCancelled'

  # ---- invite-svc ----

  eventzr.invite.sent.v1:
    description: |
      Consumed from invite-svc when an event invitation is created. notify-svc
      sends the invitation notification to the invitee.
      SLA: 5 minutes (NORMAL).
      Consumer group: notify-svc-invite-consumer
    subscribe:
      operationId: consumeInviteSent
      summary: Invitation sent - send event invitation notification
      tags:
        - name: invite-events
      bindings:
        kafka:
          groupId:
            type: string
            enum:
              - notify-svc-invite-consumer
          clientId:
            type: string
            enum:
              - notify-svc
          bindingVersion: '0.5.0'
      message:
        $ref: '#/components/messages/InviteSent'

  # ---- ticketing-svc ----

  eventzr.ticketing.ticket.purchased.v1:
    description: |
      Consumed from ticketing-svc when a ticket is purchased. notify-svc sends
      ticket confirmation with QR code to the buyer.
      SLA: 1 minute (HIGH).
      Consumer group: notify-svc-ticketing-consumer
    subscribe:
      operationId: consumeTicketPurchased
      summary: Ticket purchased - send confirmation + QR code
      tags:
        - name: ticketing-events
      bindings:
        kafka:
          groupId:
            type: string
            enum:
              - notify-svc-ticketing-consumer
          clientId:
            type: string
            enum:
              - notify-svc
          bindingVersion: '0.5.0'
      message:
        $ref: '#/components/messages/TicketPurchased'

  eventzr.ticketing.ticket.transferred.v1:
    description: |
      Consumed from ticketing-svc when a ticket is transferred between users.
      notify-svc sends transfer notifications to both the sender and recipient.
      SLA: 1 minute (HIGH).
      Consumer group: notify-svc-ticketing-consumer
    subscribe:
      operationId: consumeTicketTransferred
      summary: Ticket transferred - notify both parties
      tags:
        - name: ticketing-events
      bindings:
        kafka:
          groupId:
            type: string
            enum:
              - notify-svc-ticketing-consumer
          clientId:
            type: string
            enum:
              - notify-svc
          bindingVersion: '0.5.0'
      message:
        $ref: '#/components/messages/TicketTransferred'

  # ---- wallet-svc ----

  eventzr.wallet.transaction.completed.v1:
    description: |
      Consumed from wallet-svc when a payment transaction completes. notify-svc
      sends a payment receipt to the user.
      SLA: 1 minute (HIGH).
      Consumer group: notify-svc-wallet-consumer
    subscribe:
      operationId: consumeTransactionCompleted
      summary: Transaction completed - send payment receipt
      tags:
        - name: wallet-events
      bindings:
        kafka:
          groupId:
            type: string
            enum:
              - notify-svc-wallet-consumer
          clientId:
            type: string
            enum:
              - notify-svc
          bindingVersion: '0.5.0'
      message:
        $ref: '#/components/messages/WalletTransactionCompleted'

  eventzr.wallet.balance.low.v1:
    description: |
      Consumed from wallet-svc when a user's wallet balance drops below the
      configured threshold. notify-svc sends a low balance alert.
      SLA: 1 minute (HIGH).
      Consumer group: notify-svc-wallet-consumer
    subscribe:
      operationId: consumeLowBalance
      summary: Low balance detected - send alert notification
      tags:
        - name: wallet-events
      bindings:
        kafka:
          groupId:
            type: string
            enum:
              - notify-svc-wallet-consumer
          clientId:
            type: string
            enum:
              - notify-svc
          bindingVersion: '0.5.0'
      message:
        $ref: '#/components/messages/WalletBalanceLow'

# ---------------------------------------------------------------------------
# COMPONENTS
# ---------------------------------------------------------------------------
components:
  securitySchemes:
    saslAwsMskIam:
      type: scramSha512
      description: |
        AWS MSK IAM authentication via SASL OAUTHBEARER mechanism.
        The notify-svc Lambda uses aws-msk-iam-sasl-signer-js to generate
        short-lived tokens from the execution role's IAM credentials.

  messageTraits:
    CloudEventEnvelope:
      headers:
        type: object
        required:
          - ce_specversion
          - ce_type
          - ce_source
          - ce_id
          - ce_time
          - ce_tenantid
        properties:
          ce_specversion:
            type: string
            const: '1.0'
            description: CloudEvents specification version
          ce_type:
            type: string
            description: 'CloudEvents type (e.g., com.eventzr.notify.sent)'
          ce_source:
            type: string
            const: 'https://eventzr.com/notify-svc'
            description: CloudEvents source URI
          ce_id:
            type: string
            format: uuid
            description: Unique event identifier
          ce_time:
            type: string
            format: date-time
            description: Event timestamp (ISO 8601)
          ce_subject:
            type: string
            description: 'CloudEvents subject (e.g., notification/<notificationId>)'
          ce_datacontenttype:
            type: string
            const: application/json
          ce_tenantid:
            type: string
            format: uuid
            description: Tenant identifier (also used as Kafka partition key)
          ce_actor:
            type: string
            description: ID of the user or system that triggered the event
      bindings:
        kafka:
          key:
            type: string
            format: uuid
            description: Kafka message key is always the tenant_id
          bindingVersion: '0.5.0'

  schemas:
    # ---- Reusable CloudEvents envelope ----

    CloudEventBase:
      type: object
      description: CloudEvents 1.0 base envelope
      required:
        - specversion
        - type
        - source
        - subject
        - id
        - time
        - datacontenttype
        - tenantid
        - data
      properties:
        specversion:
          type: string
          const: '1.0'
          description: CloudEvents specification version
        type:
          type: string
          description: 'Event type in reverse-DNS notation (e.g., com.eventzr.notify.sent)'
        source:
          type: string
          const: 'https://eventzr.com/notify-svc'
          description: Identifies the context in which the event happened
        subject:
          type: string
          description: 'Subject of the event (e.g., notification/<notificationId>)'
        id:
          type: string
          format: uuid
          description: Unique event identifier (UUID v4)
        time:
          type: string
          format: date-time
          description: Timestamp of when the event occurred (ISO 8601)
        datacontenttype:
          type: string
          const: application/json
          description: Content type of the data attribute
        tenantid:
          type: string
          format: uuid
          description: Tenant identifier for multi-tenant isolation
        actor:
          type: string
          description: ID of the user or system that triggered the event
        data:
          type: object
          description: Event-specific payload

    # ---- Reusable enums ----

    NotificationChannel:
      type: string
      description: Notification delivery channel
      enum:
        - email
        - sms
        - whatsapp
        - push

    NotificationPriority:
      type: string
      description: Notification priority level
      enum:
        - normal
        - high
        - urgent
        - critical

    BounceType:
      type: string
      description: Type of bounce (hard = permanent, soft = temporary)
      enum:
        - hard
        - soft

    # ---- Delivery lifecycle payloads ----

    NotificationSentData:
      type: object
      description: Payload for the notify.sent event
      required:
        - eventId
        - timestamp
        - version
        - notificationId
        - tenantId
        - userId
        - channel
        - provider
        - sentAt
      properties:
        eventId:
          type: string
          format: uuid
          description: Unique identifier for this event instance
        timestamp:
          type: string
          format: date-time
          description: Timestamp when the event was created
        version:
          type: string
          default: v1
          description: Event schema version
        notificationId:
          type: string
          format: uuid
          description: Unique identifier of the notification
        tenantId:
          type: string
          format: uuid
          description: Tenant identifier
        userId:
          type: string
          description: Recipient user identifier
        channel:
          $ref: '#/components/schemas/NotificationChannel'
        templateId:
          type: string
          format: uuid
          nullable: true
          description: Template used to render the notification (null for ad-hoc messages)
        priority:
          $ref: '#/components/schemas/NotificationPriority'
          default: normal
        provider:
          type: string
          description: Delivery provider name (e.g., sendgrid, twilio, meta-whatsapp, fcm)
        sentAt:
          type: string
          format: date-time
          description: Timestamp when the notification was dispatched to the provider
        estimatedCostUsd:
          type: number
          nullable: true
          description: Estimated cost in USD for this notification (null if unknown at send time)

    NotificationDeliveredData:
      type: object
      description: Payload for the notify.delivered event
      required:
        - eventId
        - timestamp
        - version
        - notificationId
        - tenantId
        - userId
        - channel
        - deliveredAt
      properties:
        eventId:
          type: string
          format: uuid
          description: Unique identifier for this event instance
        timestamp:
          type: string
          format: date-time
          description: Timestamp when the event was created
        version:
          type: string
          default: v1
          description: Event schema version
        notificationId:
          type: string
          format: uuid
          description: Unique identifier of the notification
        tenantId:
          type: string
          format: uuid
          description: Tenant identifier
        userId:
          type: string
          description: Recipient user identifier
        channel:
          $ref: '#/components/schemas/NotificationChannel'
        deliveredAt:
          type: string
          format: date-time
          description: Timestamp when the provider confirmed delivery
        providerMessageId:
          type: string
          nullable: true
          description: Provider-assigned message identifier for correlation
        deliveryTimeMs:
          type: number
          nullable: true
          description: Time in milliseconds from send to confirmed delivery

    NotificationReadData:
      type: object
      description: Payload for the notify.read event
      required:
        - eventId
        - timestamp
        - version
        - notificationId
        - tenantId
        - userId
        - readAt
      properties:
        eventId:
          type: string
          format: uuid
          description: Unique identifier for this event instance
        timestamp:
          type: string
          format: date-time
          description: Timestamp when the event was created
        version:
          type: string
          default: v1
          description: Event schema version
        notificationId:
          type: string
          format: uuid
          description: Unique identifier of the notification
        tenantId:
          type: string
          format: uuid
          description: Tenant identifier
        userId:
          type: string
          description: Recipient user identifier
        readAt:
          type: string
          format: date-time
          description: Timestamp when the notification was read/opened
        channel:
          $ref: '#/components/schemas/NotificationChannel'
          nullable: true
          description: Channel on which the read was detected (null if ambiguous)

    NotificationFailedData:
      type: object
      description: Payload for the notify.failed event
      required:
        - eventId
        - timestamp
        - version
        - notificationId
        - tenantId
        - userId
        - channel
        - errorCode
        - errorMessage
        - failedAt
      properties:
        eventId:
          type: string
          format: uuid
          description: Unique identifier for this event instance
        timestamp:
          type: string
          format: date-time
          description: Timestamp when the event was created
        version:
          type: string
          default: v1
          description: Event schema version
        notificationId:
          type: string
          format: uuid
          description: Unique identifier of the notification
        tenantId:
          type: string
          format: uuid
          description: Tenant identifier
        userId:
          type: string
          description: Recipient user identifier
        channel:
          $ref: '#/components/schemas/NotificationChannel'
        errorCode:
          type: string
          description: Machine-readable error code (e.g., ERR_NOTIFY_PROVIDER_TIMEOUT, ERR_NOTIFY_INVALID_RECIPIENT)
        errorMessage:
          type: string
          description: Human-readable error description
        provider:
          type: string
          nullable: true
          description: Delivery provider that reported the failure
        retryCount:
          type: number
          default: 0
          description: Number of delivery attempts made so far
        willRetry:
          type: boolean
          default: false
          description: Whether the system will automatically retry delivery
        failedAt:
          type: string
          format: date-time
          description: Timestamp when the failure was recorded

    # ---- Bounce payloads ----

    NotificationBouncedData:
      type: object
      description: Payload for the notify.bounced event
      required:
        - eventId
        - timestamp
        - version
        - notificationId
        - tenantId
        - userId
        - channel
        - bounceType
        - contact
        - bouncedAt
      properties:
        eventId:
          type: string
          format: uuid
          description: Unique identifier for this event instance
        timestamp:
          type: string
          format: date-time
          description: Timestamp when the event was created
        version:
          type: string
          default: v1
          description: Event schema version
        notificationId:
          type: string
          format: uuid
          description: Unique identifier of the notification that bounced
        tenantId:
          type: string
          format: uuid
          description: Tenant identifier
        userId:
          type: string
          description: Intended recipient user identifier
        channel:
          $ref: '#/components/schemas/NotificationChannel'
        bounceType:
          $ref: '#/components/schemas/BounceType'
        contact:
          type: string
          description: The contact address that bounced (email address, phone number, etc.)
        provider:
          type: string
          nullable: true
          description: Delivery provider that reported the bounce
        providerMessageId:
          type: string
          nullable: true
          description: Provider-assigned message identifier for correlation
        bouncedAt:
          type: string
          format: date-time
          description: Timestamp when the bounce was detected
        autoSuppressed:
          type: boolean
          default: false
          description: Whether the contact was automatically added to the suppression list

    # ---- Template payloads ----

    TemplateCreatedData:
      type: object
      description: Payload for the notify.template.created event
      required:
        - eventId
        - timestamp
        - version
        - templateId
        - tenantId
        - templateName
        - channel
      properties:
        eventId:
          type: string
          format: uuid
          description: Unique identifier for this event instance
        timestamp:
          type: string
          format: date-time
          description: Timestamp when the event was created
        version:
          type: string
          default: v1
          description: Event schema version
        templateId:
          type: string
          format: uuid
          description: Unique identifier of the created template
        tenantId:
          type: string
          format: uuid
          description: Tenant identifier
        templateName:
          type: string
          description: Human-readable template name
        channel:
          $ref: '#/components/schemas/NotificationChannel'
        locale:
          type: string
          default: en
          description: BCP 47 locale tag for the template content
        createdBy:
          type: string
          nullable: true
          description: User or system that created the template

    TemplateUpdatedData:
      type: object
      description: Payload for the notify.template.updated event
      required:
        - eventId
        - timestamp
        - version
        - templateId
        - tenantId
        - templateName
        - channel
      properties:
        eventId:
          type: string
          format: uuid
          description: Unique identifier for this event instance
        timestamp:
          type: string
          format: date-time
          description: Timestamp when the event was created
        version:
          type: string
          default: v1
          description: Event schema version
        templateId:
          type: string
          format: uuid
          description: Unique identifier of the updated template
        tenantId:
          type: string
          format: uuid
          description: Tenant identifier
        templateName:
          type: string
          description: Human-readable template name
        channel:
          $ref: '#/components/schemas/NotificationChannel'
        changes:
          type: array
          items:
            type: string
          nullable: true
          description: List of fields that were modified (e.g., subject, body, variables)
        updatedBy:
          type: string
          nullable: true
          description: User or system that updated the template
        newVersion:
          type: number
          nullable: true
          description: New version number of the template after the update

    TemplateDeletedData:
      type: object
      description: Payload for the notify.template.deleted event
      required:
        - eventId
        - timestamp
        - version
        - templateId
        - tenantId
      properties:
        eventId:
          type: string
          format: uuid
          description: Unique identifier for this event instance
        timestamp:
          type: string
          format: date-time
          description: Timestamp when the event was created
        version:
          type: string
          default: v1
          description: Event schema version
        templateId:
          type: string
          format: uuid
          description: Unique identifier of the deleted template
        tenantId:
          type: string
          format: uuid
          description: Tenant identifier
        deletedBy:
          type: string
          nullable: true
          description: User or system that deleted the template

    # ---- Preference payloads ----

    PreferenceUpdatedData:
      type: object
      description: Payload for the notify.preference.updated event
      required:
        - eventId
        - timestamp
        - version
        - userId
        - tenantId
        - preferences
      properties:
        eventId:
          type: string
          format: uuid
          description: Unique identifier for this event instance
        timestamp:
          type: string
          format: date-time
          description: Timestamp when the event was created
        version:
          type: string
          default: v1
          description: Event schema version
        userId:
          type: string
          format: uuid
          description: User whose preferences were updated
        tenantId:
          type: string
          format: uuid
          description: Tenant identifier
        preferences:
          type: object
          description: The full updated preferences object (channel toggles, quiet hours, frequency caps, etc.)
        changedFields:
          type: array
          items:
            type: string
          nullable: true
          description: List of preference fields that were modified
        updatedBy:
          type: string
          nullable: true
          description: User or system that changed the preferences

    # ---- Cost payloads ----

    CostIncurredData:
      type: object
      description: Payload for the notify.cost_incurred event
      required:
        - eventId
        - timestamp
        - version
        - tenantId
        - channel
        - provider
        - costAmount
      properties:
        eventId:
          type: string
          format: uuid
          description: Unique identifier for this event instance
        timestamp:
          type: string
          format: date-time
          description: Timestamp when the event was created
        version:
          type: string
          default: v1
          description: Event schema version
        tenantId:
          type: string
          format: uuid
          description: Tenant identifier
        notificationId:
          type: string
          format: uuid
          nullable: true
          description: Notification that incurred the cost (null for batch/aggregated costs)
        channel:
          $ref: '#/components/schemas/NotificationChannel'
        provider:
          type: string
          description: Delivery provider that charged for the notification
        costAmount:
          type: number
          description: Cost amount in the specified currency
        currency:
          type: string
          default: USD
          description: ISO 4217 currency code
        segmentCount:
          type: number
          default: 1
          description: Number of segments (relevant for SMS where long messages split into multiple segments)
        billingCategory:
          type: string
          nullable: true
          description: Provider billing category (e.g., transactional, marketing, otp, conversation)

  # --------------------------------------------------------------------------
  # MESSAGES
  # --------------------------------------------------------------------------
  messages:
    # ---- Delivery lifecycle messages ----

    NotificationSent:
      name: NotificationSent
      title: Notification Sent
      summary: A notification was dispatched to the delivery provider
      description: |
        Published when notify-svc hands off a notification to a delivery
        provider via integration-hub-svc. The notification is in transit
        but not yet confirmed as delivered.
      contentType: application/json
      traits:
        - $ref: '#/components/messageTraits/CloudEventEnvelope'
      payload:
        allOf:
          - $ref: '#/components/schemas/CloudEventBase'
          - type: object
            properties:
              type:
                const: com.eventzr.notify.sent
              data:
                $ref: '#/components/schemas/NotificationSentData'
      examples:
        - name: EmailSentExample
          summary: Marketing email sent via SendGrid
          payload:
            specversion: '1.0'
            type: com.eventzr.notify.sent
            source: 'https://eventzr.com/notify-svc'
            subject: notification/a1b2c3d4-e5f6-7890-abcd-ef1234567890
            id: f47ac10b-58cc-4372-a567-0e02b2c3d479
            time: '2026-02-22T10:15:30.000Z'
            datacontenttype: application/json
            tenantid: 550e8400-e29b-41d4-a716-446655440000
            actor: system:notify-svc
            data:
              eventId: f47ac10b-58cc-4372-a567-0e02b2c3d479
              timestamp: '2026-02-22T10:15:30.000Z'
              version: v1
              notificationId: a1b2c3d4-e5f6-7890-abcd-ef1234567890
              tenantId: 550e8400-e29b-41d4-a716-446655440000
              userId: 6ba7b810-9dad-11d1-80b4-00c04fd430c8
              channel: email
              templateId: 9f8e7d6c-5b4a-3210-fedc-ba0987654321
              priority: normal
              provider: sendgrid
              sentAt: '2026-02-22T10:15:30.000Z'
              estimatedCostUsd: 0.0004

    NotificationDelivered:
      name: NotificationDelivered
      title: Notification Delivered
      summary: A notification was confirmed delivered to the recipient
      contentType: application/json
      traits:
        - $ref: '#/components/messageTraits/CloudEventEnvelope'
      payload:
        allOf:
          - $ref: '#/components/schemas/CloudEventBase'
          - type: object
            properties:
              type:
                const: com.eventzr.notify.delivered
              data:
                $ref: '#/components/schemas/NotificationDeliveredData'
      examples:
        - name: WhatsAppDeliveredExample
          summary: WhatsApp message confirmed delivered
          payload:
            specversion: '1.0'
            type: com.eventzr.notify.delivered
            source: 'https://eventzr.com/notify-svc'
            subject: notification/a1b2c3d4-e5f6-7890-abcd-ef1234567890
            id: d5e6f7a8-b9c0-1234-5678-90abcdef1234
            time: '2026-02-22T10:15:32.500Z'
            datacontenttype: application/json
            tenantid: 550e8400-e29b-41d4-a716-446655440000
            actor: system:notify-svc
            data:
              eventId: d5e6f7a8-b9c0-1234-5678-90abcdef1234
              timestamp: '2026-02-22T10:15:32.500Z'
              version: v1
              notificationId: a1b2c3d4-e5f6-7890-abcd-ef1234567890
              tenantId: 550e8400-e29b-41d4-a716-446655440000
              userId: 6ba7b810-9dad-11d1-80b4-00c04fd430c8
              channel: whatsapp
              deliveredAt: '2026-02-22T10:15:32.500Z'
              providerMessageId: wamid.HBgNMTIzNDU2Nzg5MDIA
              deliveryTimeMs: 2500

    NotificationRead:
      name: NotificationRead
      title: Notification Read
      summary: A notification was read/opened by the recipient
      contentType: application/json
      traits:
        - $ref: '#/components/messageTraits/CloudEventEnvelope'
      payload:
        allOf:
          - $ref: '#/components/schemas/CloudEventBase'
          - type: object
            properties:
              type:
                const: com.eventzr.notify.read
              data:
                $ref: '#/components/schemas/NotificationReadData'
      examples:
        - name: EmailReadExample
          summary: Email opened (tracking pixel)
          payload:
            specversion: '1.0'
            type: com.eventzr.notify.read
            source: 'https://eventzr.com/notify-svc'
            subject: notification/a1b2c3d4-e5f6-7890-abcd-ef1234567890
            id: 1a2b3c4d-5e6f-7890-abcd-ef1234567890
            time: '2026-02-22T10:20:45.000Z'
            datacontenttype: application/json
            tenantid: 550e8400-e29b-41d4-a716-446655440000
            actor: system:notify-svc
            data:
              eventId: 1a2b3c4d-5e6f-7890-abcd-ef1234567890
              timestamp: '2026-02-22T10:20:45.000Z'
              version: v1
              notificationId: a1b2c3d4-e5f6-7890-abcd-ef1234567890
              tenantId: 550e8400-e29b-41d4-a716-446655440000
              userId: 6ba7b810-9dad-11d1-80b4-00c04fd430c8
              readAt: '2026-02-22T10:20:45.000Z'
              channel: email

    NotificationFailed:
      name: NotificationFailed
      title: Notification Failed
      summary: Notification delivery failed
      contentType: application/json
      traits:
        - $ref: '#/components/messageTraits/CloudEventEnvelope'
      payload:
        allOf:
          - $ref: '#/components/schemas/CloudEventBase'
          - type: object
            properties:
              type:
                const: com.eventzr.notify.failed
              data:
                $ref: '#/components/schemas/NotificationFailedData'
      examples:
        - name: SmsFailedExample
          summary: SMS delivery failed due to invalid phone number
          payload:
            specversion: '1.0'
            type: com.eventzr.notify.failed
            source: 'https://eventzr.com/notify-svc'
            subject: notification/b2c3d4e5-f6a7-8901-bcde-f12345678901
            id: 2b3c4d5e-6f7a-8901-bcde-f12345678901
            time: '2026-02-22T10:16:00.000Z'
            datacontenttype: application/json
            tenantid: 550e8400-e29b-41d4-a716-446655440000
            actor: system:notify-svc
            data:
              eventId: 2b3c4d5e-6f7a-8901-bcde-f12345678901
              timestamp: '2026-02-22T10:16:00.000Z'
              version: v1
              notificationId: b2c3d4e5-f6a7-8901-bcde-f12345678901
              tenantId: 550e8400-e29b-41d4-a716-446655440000
              userId: 6ba7b810-9dad-11d1-80b4-00c04fd430c8
              channel: sms
              errorCode: ERR_NOTIFY_INVALID_RECIPIENT
              errorMessage: The phone number +1555000XXXX is not a valid mobile number
              provider: twilio
              retryCount: 0
              willRetry: false
              failedAt: '2026-02-22T10:16:00.000Z'

    # ---- Bounce messages ----

    NotificationBounced:
      name: NotificationBounced
      title: Notification Bounced
      summary: A notification bounced (hard or soft bounce)
      contentType: application/json
      traits:
        - $ref: '#/components/messageTraits/CloudEventEnvelope'
      payload:
        allOf:
          - $ref: '#/components/schemas/CloudEventBase'
          - type: object
            properties:
              type:
                const: com.eventzr.notify.bounced
              data:
                $ref: '#/components/schemas/NotificationBouncedData'
      examples:
        - name: HardBounceExample
          summary: Email hard bounce - mailbox does not exist
          payload:
            specversion: '1.0'
            type: com.eventzr.notify.bounced
            source: 'https://eventzr.com/notify-svc'
            subject: notification/c3d4e5f6-a7b8-9012-cdef-123456789012
            id: 3c4d5e6f-7a8b-9012-cdef-123456789012
            time: '2026-02-22T10:17:15.000Z'
            datacontenttype: application/json
            tenantid: 550e8400-e29b-41d4-a716-446655440000
            actor: system:notify-svc
            data:
              eventId: 3c4d5e6f-7a8b-9012-cdef-123456789012
              timestamp: '2026-02-22T10:17:15.000Z'
              version: v1
              notificationId: c3d4e5f6-a7b8-9012-cdef-123456789012
              tenantId: 550e8400-e29b-41d4-a716-446655440000
              userId: 6ba7b810-9dad-11d1-80b4-00c04fd430c8
              channel: email
              bounceType: hard
              contact: user@nonexistent-domain.example
              provider: sendgrid
              providerMessageId: sg-msg-abc123def456
              bouncedAt: '2026-02-22T10:17:15.000Z'
              autoSuppressed: true

    # ---- Template messages ----

    TemplateCreated:
      name: TemplateCreated
      title: Template Created
      summary: A new notification template was created
      contentType: application/json
      traits:
        - $ref: '#/components/messageTraits/CloudEventEnvelope'
      payload:
        allOf:
          - $ref: '#/components/schemas/CloudEventBase'
          - type: object
            properties:
              type:
                const: com.eventzr.notify.template.created
              data:
                $ref: '#/components/schemas/TemplateCreatedData'
      examples:
        - name: WhatsAppTemplateCreatedExample
          summary: New WhatsApp template created for event reminders
          payload:
            specversion: '1.0'
            type: com.eventzr.notify.template.created
            source: 'https://eventzr.com/notify-svc'
            subject: template/d4e5f6a7-b8c9-0123-def0-234567890123
            id: 4d5e6f7a-8b9c-0123-def0-234567890123
            time: '2026-02-22T09:00:00.000Z'
            datacontenttype: application/json
            tenantid: 550e8400-e29b-41d4-a716-446655440000
            actor: 7ca8b910-1dab-21d1-90b4-10c04fd430c8
            data:
              eventId: 4d5e6f7a-8b9c-0123-def0-234567890123
              timestamp: '2026-02-22T09:00:00.000Z'
              version: v1
              templateId: d4e5f6a7-b8c9-0123-def0-234567890123
              tenantId: 550e8400-e29b-41d4-a716-446655440000
              templateName: event_reminder_24h
              channel: whatsapp
              locale: en
              createdBy: 7ca8b910-1dab-21d1-90b4-10c04fd430c8

    TemplateUpdated:
      name: TemplateUpdated
      title: Template Updated
      summary: An existing notification template was updated
      contentType: application/json
      traits:
        - $ref: '#/components/messageTraits/CloudEventEnvelope'
      payload:
        allOf:
          - $ref: '#/components/schemas/CloudEventBase'
          - type: object
            properties:
              type:
                const: com.eventzr.notify.template.updated
              data:
                $ref: '#/components/schemas/TemplateUpdatedData'
      examples:
        - name: EmailTemplateUpdatedExample
          summary: Email template subject line updated
          payload:
            specversion: '1.0'
            type: com.eventzr.notify.template.updated
            source: 'https://eventzr.com/notify-svc'
            subject: template/d4e5f6a7-b8c9-0123-def0-234567890123
            id: 5e6f7a8b-9c0d-1234-ef01-345678901234
            time: '2026-02-22T11:30:00.000Z'
            datacontenttype: application/json
            tenantid: 550e8400-e29b-41d4-a716-446655440000
            actor: 7ca8b910-1dab-21d1-90b4-10c04fd430c8
            data:
              eventId: 5e6f7a8b-9c0d-1234-ef01-345678901234
              timestamp: '2026-02-22T11:30:00.000Z'
              version: v1
              templateId: d4e5f6a7-b8c9-0123-def0-234567890123
              tenantId: 550e8400-e29b-41d4-a716-446655440000
              templateName: event_reminder_24h
              channel: email
              changes:
                - subject
                - body
              updatedBy: 7ca8b910-1dab-21d1-90b4-10c04fd430c8
              newVersion: 3

    TemplateDeleted:
      name: TemplateDeleted
      title: Template Deleted
      summary: A notification template was soft-deleted
      contentType: application/json
      traits:
        - $ref: '#/components/messageTraits/CloudEventEnvelope'
      payload:
        allOf:
          - $ref: '#/components/schemas/CloudEventBase'
          - type: object
            properties:
              type:
                const: com.eventzr.notify.template.deleted
              data:
                $ref: '#/components/schemas/TemplateDeletedData'
      examples:
        - name: TemplateDeletedExample
          summary: Deprecated template soft-deleted
          payload:
            specversion: '1.0'
            type: com.eventzr.notify.template.deleted
            source: 'https://eventzr.com/notify-svc'
            subject: template/d4e5f6a7-b8c9-0123-def0-234567890123
            id: 8b9c0d1e-2f3a-4567-8901-234567890abc
            time: '2026-02-22T15:00:00.000Z'
            datacontenttype: application/json
            tenantid: 550e8400-e29b-41d4-a716-446655440000
            actor: 7ca8b910-1dab-21d1-90b4-10c04fd430c8
            data:
              eventId: 8b9c0d1e-2f3a-4567-8901-234567890abc
              timestamp: '2026-02-22T15:00:00.000Z'
              version: v1
              templateId: d4e5f6a7-b8c9-0123-def0-234567890123
              tenantId: 550e8400-e29b-41d4-a716-446655440000
              deletedBy: 7ca8b910-1dab-21d1-90b4-10c04fd430c8

    # ---- Preference messages ----

    PreferenceUpdated:
      name: PreferenceUpdated
      title: Preference Updated
      summary: A user's notification preferences were updated
      contentType: application/json
      traits:
        - $ref: '#/components/messageTraits/CloudEventEnvelope'
      payload:
        allOf:
          - $ref: '#/components/schemas/CloudEventBase'
          - type: object
            properties:
              type:
                const: com.eventzr.notify.preference.updated
              data:
                $ref: '#/components/schemas/PreferenceUpdatedData'
      examples:
        - name: PreferenceOptOutExample
          summary: User opts out of marketing emails
          payload:
            specversion: '1.0'
            type: com.eventzr.notify.preference.updated
            source: 'https://eventzr.com/notify-svc'
            subject: user/6ba7b810-9dad-11d1-80b4-00c04fd430c8
            id: 6f7a8b9c-0d1e-2345-f012-456789012345
            time: '2026-02-22T14:00:00.000Z'
            datacontenttype: application/json
            tenantid: 550e8400-e29b-41d4-a716-446655440000
            actor: 6ba7b810-9dad-11d1-80b4-00c04fd430c8
            data:
              eventId: 6f7a8b9c-0d1e-2345-f012-456789012345
              timestamp: '2026-02-22T14:00:00.000Z'
              version: v1
              userId: 6ba7b810-9dad-11d1-80b4-00c04fd430c8
              tenantId: 550e8400-e29b-41d4-a716-446655440000
              preferences:
                email:
                  marketing: false
                  transactional: true
                  security: true
                sms:
                  marketing: false
                  transactional: true
                whatsapp:
                  marketing: true
                  transactional: true
                push:
                  marketing: true
                  transactional: true
                quietHours:
                  enabled: true
                  start: '22:00'
                  end: '08:00'
                  timezone: Asia/Kolkata
              changedFields:
                - email.marketing
                - sms.marketing
              updatedBy: 6ba7b810-9dad-11d1-80b4-00c04fd430c8

    # ---- Cost messages ----

    CostIncurred:
      name: CostIncurred
      title: Cost Incurred
      summary: A notification delivery cost was incurred
      contentType: application/json
      traits:
        - $ref: '#/components/messageTraits/CloudEventEnvelope'
      payload:
        allOf:
          - $ref: '#/components/schemas/CloudEventBase'
          - type: object
            properties:
              type:
                const: com.eventzr.notify.cost_incurred
              data:
                $ref: '#/components/schemas/CostIncurredData'
      examples:
        - name: SmsCostExample
          summary: SMS cost for a 2-segment message via Twilio
          payload:
            specversion: '1.0'
            type: com.eventzr.notify.cost_incurred
            source: 'https://eventzr.com/notify-svc'
            subject: notification/a1b2c3d4-e5f6-7890-abcd-ef1234567890
            id: 7a8b9c0d-1e2f-3456-0123-567890123456
            time: '2026-02-22T10:15:31.000Z'
            datacontenttype: application/json
            tenantid: 550e8400-e29b-41d4-a716-446655440000
            actor: system:notify-svc
            data:
              eventId: 7a8b9c0d-1e2f-3456-0123-567890123456
              timestamp: '2026-02-22T10:15:31.000Z'
              version: v1
              tenantId: 550e8400-e29b-41d4-a716-446655440000
              notificationId: a1b2c3d4-e5f6-7890-abcd-ef1234567890
              channel: sms
              provider: twilio
              costAmount: 0.0158
              currency: USD
              segmentCount: 2
              billingCategory: transactional

    # ---- Consumer messages (from upstream services) ----

    AuthOtpRequested:
      name: AuthOtpRequested
      title: OTP Requested
      summary: A user requested an OTP code (consumed from auth-svc)
      contentType: application/json
      traits:
        - $ref: '#/components/messageTraits/CloudEventEnvelope'
      payload:
        type: object
        required: [userId, tenantId, channel, otpCode]
        properties:
          userId:
            type: string
            description: User requesting the OTP
          tenantId:
            type: string
            format: uuid
            description: Tenant identifier
          channel:
            $ref: '#/components/schemas/NotificationChannel'
          otpCode:
            type: string
            description: The OTP code to deliver
          expiresIn:
            type: number
            description: OTP expiry in seconds

    BookingConfirmed:
      name: BookingConfirmed
      title: Booking Confirmed
      summary: A booking was confirmed (consumed from booking-svc)
      contentType: application/json
      traits:
        - $ref: '#/components/messageTraits/CloudEventEnvelope'
      payload:
        type: object
        required: [bookingId, userId, tenantId, eventId]
        properties:
          bookingId:
            type: string
            format: uuid
            description: Unique booking identifier
          userId:
            type: string
            description: User who made the booking
          tenantId:
            type: string
            format: uuid
            description: Tenant identifier
          eventId:
            type: string
            format: uuid
            description: Event that was booked
          eventTitle:
            type: string
            description: Event title for the notification
          bookingReference:
            type: string
            description: Human-readable booking reference code

    BookingCheckInTime:
      name: BookingCheckInTime
      title: Check-In Time Approaching
      summary: T-24h check-in reminder (consumed from booking-svc)
      contentType: application/json
      traits:
        - $ref: '#/components/messageTraits/CloudEventEnvelope'
      payload:
        type: object
        required: [bookingId, userId, tenantId, eventId, checkInAt]
        properties:
          bookingId:
            type: string
            format: uuid
            description: Unique booking identifier
          userId:
            type: string
            description: User to remind
          tenantId:
            type: string
            format: uuid
            description: Tenant identifier
          eventId:
            type: string
            format: uuid
            description: Event identifier
          eventTitle:
            type: string
            description: Event title
          checkInAt:
            type: string
            format: date-time
            description: Scheduled check-in time

    EventPublished:
      name: EventPublished
      title: Event Published
      summary: A new event was published (consumed from event-svc)
      contentType: application/json
      traits:
        - $ref: '#/components/messageTraits/CloudEventEnvelope'
      payload:
        type: object
        required: [eventId, tenantId, title]
        properties:
          eventId:
            type: string
            format: uuid
            description: Published event identifier
          tenantId:
            type: string
            format: uuid
            description: Tenant identifier
          title:
            type: string
            description: Event title
          organizerId:
            type: string
            description: Event organizer identifier

    EventUpdated:
      name: EventUpdated
      title: Event Updated
      summary: An event was updated (consumed from event-svc)
      contentType: application/json
      traits:
        - $ref: '#/components/messageTraits/CloudEventEnvelope'
      payload:
        type: object
        required: [eventId, tenantId, changes]
        properties:
          eventId:
            type: string
            format: uuid
            description: Updated event identifier
          tenantId:
            type: string
            format: uuid
            description: Tenant identifier
          title:
            type: string
            description: Event title
          changes:
            type: array
            items:
              type: string
            description: List of fields that changed (e.g., date, venue, description)

    EventCancelled:
      name: EventCancelled
      title: Event Cancelled
      summary: An event was cancelled (consumed from event-svc)
      contentType: application/json
      traits:
        - $ref: '#/components/messageTraits/CloudEventEnvelope'
      payload:
        type: object
        required: [eventId, tenantId]
        properties:
          eventId:
            type: string
            format: uuid
            description: Cancelled event identifier
          tenantId:
            type: string
            format: uuid
            description: Tenant identifier
          title:
            type: string
            description: Event title
          reason:
            type: string
            description: Cancellation reason
          refundPolicy:
            type: string
            description: Refund policy details for notification content

    InviteSent:
      name: InviteSent
      title: Invite Sent
      summary: An event invitation was created (consumed from invite-svc)
      contentType: application/json
      traits:
        - $ref: '#/components/messageTraits/CloudEventEnvelope'
      payload:
        type: object
        required: [inviteId, tenantId, inviteeEmail, eventId]
        properties:
          inviteId:
            type: string
            format: uuid
            description: Unique invitation identifier
          tenantId:
            type: string
            format: uuid
            description: Tenant identifier
          inviteeEmail:
            type: string
            format: email
            description: Email of the person being invited
          inviteeUserId:
            type: string
            nullable: true
            description: User ID if the invitee is an existing platform user
          eventId:
            type: string
            format: uuid
            description: Event being invited to
          eventTitle:
            type: string
            description: Event title for the invitation message
          invitedBy:
            type: string
            description: User who sent the invitation

    TicketPurchased:
      name: TicketPurchased
      title: Ticket Purchased
      summary: A ticket was purchased (consumed from ticketing-svc)
      contentType: application/json
      traits:
        - $ref: '#/components/messageTraits/CloudEventEnvelope'
      payload:
        type: object
        required: [ticketId, userId, tenantId, eventId]
        properties:
          ticketId:
            type: string
            format: uuid
            description: Unique ticket identifier
          userId:
            type: string
            description: User who purchased the ticket
          tenantId:
            type: string
            format: uuid
            description: Tenant identifier
          eventId:
            type: string
            format: uuid
            description: Event the ticket is for
          eventTitle:
            type: string
            description: Event title
          ticketType:
            type: string
            description: Ticket tier/type name
          qrCode:
            type: string
            nullable: true
            description: QR code data for the ticket

    TicketTransferred:
      name: TicketTransferred
      title: Ticket Transferred
      summary: A ticket was transferred between users (consumed from ticketing-svc)
      contentType: application/json
      traits:
        - $ref: '#/components/messageTraits/CloudEventEnvelope'
      payload:
        type: object
        required: [ticketId, tenantId, fromUserId, toUserId]
        properties:
          ticketId:
            type: string
            format: uuid
            description: Transferred ticket identifier
          tenantId:
            type: string
            format: uuid
            description: Tenant identifier
          fromUserId:
            type: string
            description: Original ticket holder
          toUserId:
            type: string
            description: New ticket holder
          eventId:
            type: string
            format: uuid
            description: Event the ticket is for
          eventTitle:
            type: string
            description: Event title

    WalletTransactionCompleted:
      name: WalletTransactionCompleted
      title: Transaction Completed
      summary: A wallet transaction completed (consumed from wallet-svc)
      contentType: application/json
      traits:
        - $ref: '#/components/messageTraits/CloudEventEnvelope'
      payload:
        type: object
        required: [transactionId, userId, tenantId, amount, currency]
        properties:
          transactionId:
            type: string
            format: uuid
            description: Unique transaction identifier
          userId:
            type: string
            description: User whose wallet was debited/credited
          tenantId:
            type: string
            format: uuid
            description: Tenant identifier
          amount:
            type: number
            description: Transaction amount
          currency:
            type: string
            description: ISO 4217 currency code
          type:
            type: string
            description: Transaction type (credit, debit, refund)
          description:
            type: string
            nullable: true
            description: Transaction description for the receipt

    WalletBalanceLow:
      name: WalletBalanceLow
      title: Low Balance Alert
      summary: Wallet balance dropped below threshold (consumed from wallet-svc)
      contentType: application/json
      traits:
        - $ref: '#/components/messageTraits/CloudEventEnvelope'
      payload:
        type: object
        required: [userId, tenantId, currentBalance, threshold, currency]
        properties:
          userId:
            type: string
            description: User with low balance
          tenantId:
            type: string
            format: uuid
            description: Tenant identifier
          currentBalance:
            type: number
            description: Current wallet balance
          threshold:
            type: number
            description: Configured low balance threshold
          currency:
            type: string
            description: ISO 4217 currency code
