openapi: 3.1.0
info:
  title: Nasak Messaging API
  version: 1.0.0-alpha.2
  description: Versioned user notification, bot connection, SMS administration, and store messaging API.
servers:
  - url: https://api.nasak.ir/v1/messaging
paths:
  /live:
    get:
      operationId: getMessagingLiveness
      summary: Check messaging service liveness
      security: []
      responses:
        '200': { $ref: '#/components/responses/Success' }
  /preferences:
    get:
      operationId: getMyNotificationPreferences
      summary: Get notification preferences for the current user
      security: [{ cookieSession: [] }]
      responses:
        '200': { $ref: '#/components/responses/Success' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
    patch:
      operationId: updateMyNotificationPreferences
      summary: Update per-channel and per-event notification preferences
      security: [{ cookieSession: [] }]
      x-idempotency-exempt: true
      x-migration-note: Compatibility BFF mutation.
      requestBody: { $ref: '#/components/requestBodies/Mutation' }
      responses:
        '200': { $ref: '#/components/responses/Success' }
        '400': { $ref: '#/components/responses/BadRequest' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
  /bot-links:
    post:
      operationId: createMyBotConnectionLink
      summary: Create a short-lived bot connection link
      security: [{ cookieSession: [] }]
      x-idempotency-exempt: true
      x-migration-note: Short-lived link generation is rate-limited.
      requestBody: { $ref: '#/components/requestBodies/Mutation' }
      responses:
        '200': { $ref: '#/components/responses/Success' }
        '400': { $ref: '#/components/responses/BadRequest' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '429': { $ref: '#/components/responses/TooManyRequests' }
  /bot-connections/{method}:
    delete:
      operationId: disconnectMyBot
      summary: Disconnect a bot channel for the current user
      parameters: [{ $ref: '#/components/parameters/Method' }]
      security: [{ cookieSession: [] }]
      x-idempotency-exempt: true
      x-migration-note: Disconnect is resource-state idempotent.
      responses:
        '200': { $ref: '#/components/responses/Success' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '404': { $ref: '#/components/responses/NotFound' }
  /bot-connections/{method}/test:
    post:
      operationId: testMyBotConnection
      summary: Send a controlled test through a connected bot
      parameters: [{ $ref: '#/components/parameters/Method' }]
      security: [{ cookieSession: [] }]
      x-idempotency-exempt: true
      x-migration-note: Diagnostic send is rate-limited and audited.
      responses:
        '200': { $ref: '#/components/responses/Success' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '429': { $ref: '#/components/responses/TooManyRequests' }
  /admin/health:
    get:
      operationId: getAdminMessagingHealth
      summary: Get provider, worker, queue, and delivery health
      security: [{ cookieSession: [] }]
      responses:
        '200': { $ref: '#/components/responses/Success' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
  /admin/sms/logs:
    get:
      operationId: listAdminSmsLogs
      summary: Search detailed SMS delivery and segment logs
      security: [{ cookieSession: [] }]
      responses:
        '200': { $ref: '#/components/responses/Success' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
  /admin/sms/senders:
    get:
      operationId: listAdminSmsSenders
      summary: List configured and connected SMS senders
      security: [{ cookieSession: [] }]
      responses:
        '200': { $ref: '#/components/responses/Success' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
    patch:
      operationId: updateAdminSmsRouting
      summary: Update global SMS provider and sender routing
      security: [{ cookieSession: [] }]
      x-idempotency-exempt: true
      x-migration-note: Compatibility admin mutation with audit logging.
      requestBody: { $ref: '#/components/requestBodies/Mutation' }
      responses:
        '200': { $ref: '#/components/responses/Success' }
        '400': { $ref: '#/components/responses/BadRequest' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
  /admin/sms/test:
    post:
      operationId: sendAdminSmsTest
      summary: Send a rate-limited SMS test
      security: [{ cookieSession: [] }]
      x-idempotency-exempt: true
      x-migration-note: Diagnostic send is rate-limited, counted, and audited.
      requestBody: { $ref: '#/components/requestBodies/Mutation' }
      responses:
        '200': { $ref: '#/components/responses/Success' }
        '400': { $ref: '#/components/responses/BadRequest' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '429': { $ref: '#/components/responses/TooManyRequests' }
  /admin/shop/providers:
    get:
      operationId: listStoreSmsProviders
      summary: List safe SMS provider configuration for the current store
      security: [{ cookieSession: [] }]
      responses:
        '200': { $ref: '#/components/responses/Success' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
    post:
      operationId: createStoreSmsProvider
      summary: Create an encrypted SMS provider configuration
      security: [{ cookieSession: [] }]
      x-idempotency-exempt: true
      x-migration-note: Credentials are encrypted by the owning service and never returned.
      requestBody: { $ref: '#/components/requestBodies/Mutation' }
      responses:
        '200': { $ref: '#/components/responses/Success' }
        '201': { $ref: '#/components/responses/Success' }
        '400': { $ref: '#/components/responses/BadRequest' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
  /admin/shop/providers/{id}:
    patch:
      operationId: updateStoreSmsProvider
      summary: Update an encrypted store SMS provider
      parameters: [{ $ref: '#/components/parameters/ResourceId' }]
      security: [{ cookieSession: [] }]
      x-idempotency-exempt: true
      x-migration-note: Compatibility BFF mutation.
      requestBody: { $ref: '#/components/requestBodies/Mutation' }
      responses:
        '200': { $ref: '#/components/responses/Success' }
        '400': { $ref: '#/components/responses/BadRequest' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '404': { $ref: '#/components/responses/NotFound' }
    delete:
      operationId: removeStoreSmsProvider
      summary: Remove a store SMS provider configuration
      parameters: [{ $ref: '#/components/parameters/ResourceId' }]
      security: [{ cookieSession: [] }]
      x-idempotency-exempt: true
      x-migration-note: Compatibility BFF mutation.
      responses:
        '200': { $ref: '#/components/responses/Success' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '404': { $ref: '#/components/responses/NotFound' }
  /admin/shop/providers/{id}/test:
    post:
      operationId: testStoreSmsProvider
      summary: Test a store SMS provider and persist safe diagnostics
      parameters: [{ $ref: '#/components/parameters/ResourceId' }]
      security: [{ cookieSession: [] }]
      x-idempotency-exempt: true
      x-migration-note: Diagnostic send is rate-limited, counted, and audited.
      requestBody: { $ref: '#/components/requestBodies/Mutation' }
      responses:
        '200': { $ref: '#/components/responses/Success' }
        '400': { $ref: '#/components/responses/BadRequest' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '429': { $ref: '#/components/responses/TooManyRequests' }
  /admin/shop/campaigns:
    get:
      operationId: listStoreSmsCampaigns
      summary: List SMS campaigns for the current store
      security: [{ cookieSession: [] }]
      responses:
        '200': { $ref: '#/components/responses/Success' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
    post:
      operationId: createStoreSmsCampaign
      summary: Validate, count, and enqueue a store SMS campaign
      security: [{ cookieSession: [] }]
      x-idempotency-exempt: true
      x-migration-note: Campaign creation is audited; shared Idempotency-Key enforcement is scheduled.
      requestBody: { $ref: '#/components/requestBodies/Mutation' }
      responses:
        '200': { $ref: '#/components/responses/Success' }
        '201': { $ref: '#/components/responses/Success' }
        '400': { $ref: '#/components/responses/BadRequest' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '429': { $ref: '#/components/responses/TooManyRequests' }
  /admin/shop/recipients:
    get:
      operationId: listStoreBotRecipients
      summary: List safe bot recipients for the current store
      security: [{ cookieSession: [] }]
      responses:
        '200': { $ref: '#/components/responses/Success' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
    post:
      operationId: createStoreBotRecipient
      summary: Add a validated bot recipient to the current store
      security: [{ cookieSession: [] }]
      x-idempotency-exempt: true
      x-migration-note: Compatibility BFF mutation.
      requestBody: { $ref: '#/components/requestBodies/Mutation' }
      responses:
        '200': { $ref: '#/components/responses/Success' }
        '201': { $ref: '#/components/responses/Success' }
        '400': { $ref: '#/components/responses/BadRequest' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
components:
  securitySchemes:
    cookieSession:
      type: apiKey
      in: cookie
      name: pdf_library_session
      description: Compatibility BFF session during OIDC migration.
  parameters:
    Method:
      name: method
      in: path
      required: true
      schema: { type: string, enum: [TELEGRAM, BALE, EITAA] }
    ResourceId:
      name: id
      in: path
      required: true
      schema: { type: string, format: uuid }
  requestBodies:
    Mutation:
      required: true
      content:
        application/json:
          schema: { type: object, additionalProperties: true }
  schemas:
    Error:
      type: object
      additionalProperties: true
      required: [error]
      properties:
        error: { type: string }
  responses:
    Success:
      description: Successful tenant-scoped response.
      content:
        application/json:
          schema: { type: object, additionalProperties: true }
    BadRequest:
      description: Invalid request.
      content:
        application/json:
          schema: { $ref: '#/components/schemas/Error' }
    Unauthorized:
      description: Authentication is required.
      content:
        application/json:
          schema: { $ref: '#/components/schemas/Error' }
    Forbidden:
      description: The current principal cannot access this resource.
      content:
        application/json:
          schema: { $ref: '#/components/schemas/Error' }
    NotFound:
      description: Resource not found.
      content:
        application/json:
          schema: { $ref: '#/components/schemas/Error' }
    TooManyRequests:
      description: Rate limit exceeded.
      content:
        application/json:
          schema: { $ref: '#/components/schemas/Error' }
