swagger: '2.0'
info:
  title: API Documentation
  description: OTP & Tenancy APIs
  contact:
    email: support@example.com
  version: v1
host: otp.devsgraphics.com
schemes:
- http
basePath: /api
consumes:
- application/json
produces:
- application/json
securityDefinitions:
  ApiKeyAuth:
    type: apiKey
    name: X-API-KEY
    in: header
    description: Tenant API key. Paste the raw key value.
security:
- ApiKeyAuth: []
paths:
  /otp/config/:
    get:
      operationId: otp_config
      summary: Get Effective OTP Config
      description: ''
      parameters:
      - name: X-Tenant
        in: header
        description: Tenant identifier (must match your tenancy middleware expectations)
        required: true
        type: string
      responses:
        '200':
          description: ''
          schema:
            $ref: '#/definitions/EffectiveOTPConfigResponse'
      tags:
      - OTP
    parameters: []
  /otp/issue/:
    post:
      operationId: otp_issue
      summary: Issue OTP
      description: ''
      parameters:
      - name: data
        in: body
        required: true
        schema:
          $ref: '#/definitions/IssueOTP'
      - name: X-Tenant
        in: header
        description: Tenant identifier (must match your tenancy middleware expectations)
        required: true
        type: string
      responses:
        '201':
          description: ''
          schema:
            $ref: '#/definitions/IssueOTPResponse'
      tags:
      - OTP
    parameters: []
  /otp/resend/:
    post:
      operationId: otp_resend
      summary: Resend OTP
      description: ''
      parameters:
      - name: data
        in: body
        required: true
        schema:
          $ref: '#/definitions/ResendOTP'
      - name: X-Tenant
        in: header
        description: Tenant identifier (must match your tenancy middleware expectations)
        required: true
        type: string
      responses:
        '200':
          description: ''
          schema:
            $ref: '#/definitions/IssueOTPResponse'
      tags:
      - OTP
    parameters: []
  /otp/verify/:
    post:
      operationId: otp_verify
      summary: Verify OTP
      description: ''
      parameters:
      - name: data
        in: body
        required: true
        schema:
          $ref: '#/definitions/VerifyOTP'
      - name: X-Tenant
        in: header
        description: Tenant identifier (must match your tenancy middleware expectations)
        required: true
        type: string
      responses:
        '200':
          description: ''
          schema:
            $ref: '#/definitions/VerifyOTPResponse'
      tags:
      - OTP
    parameters: []
  /tenancy/branding/:
    get:
      operationId: tenancy_branding_get
      summary: Get tenant branding (safe)
      description: Branding payload used by templates/UI.
      parameters: []
      responses:
        '200':
          description: OK
          schema:
            $ref: '#/definitions/TenantBrandingResponse'
        '401':
          description: Unauthorized (missing/invalid X-API-KEY)
          schema:
            required:
            - detail
            type: object
            properties:
              detail:
                type: string
                example: Missing or invalid tenant API key.
      tags:
      - Tenancy
      security:
      - ApiKeyAuth: []
    parameters: []
  /tenancy/email-config/:
    get:
      operationId: tenancy_email_config_get
      summary: Get tenant email config summary (safe)
      description: Returns a non-secret summary (no passwords, no provider keys).
      parameters: []
      responses:
        '200':
          description: OK
          schema:
            $ref: '#/definitions/TenantEmailConfigResponse'
          examples:
            application/json:
              configured: true
              config:
                provider: SMTP
                from_email: no-reply@acme.example
                from_name: Acme Security
                reply_to: support@acme.example
                is_active: true
                updated_at: '2026-01-17T07:10:00Z'
                website_url: https://acme.example
                brand_name: Acme Org
                support_email: support@acme.example
                unsubscribe_base_url: https://acme.example/unsubscribe
              branding:
                site_name: Acme Org
                site_url: https://acme.example
                support_email: support@acme.example
                unsubscribe_base_url: https://acme.example/unsubscribe
        '401':
          description: Unauthorized (missing/invalid X-API-KEY)
          schema:
            required:
            - detail
            type: object
            properties:
              detail:
                type: string
                example: Missing or invalid tenant API key.
      tags:
      - Tenancy
      security:
      - ApiKeyAuth: []
    put:
      operationId: tenancy_email_config_put
      summary: Replace email config (TENANT_ADMIN)
      description: Same as PATCH but treated as full update by clients.
      parameters:
      - name: data
        in: body
        required: true
        schema:
          $ref: '#/definitions/TenantEmailConfigUpsert'
      responses:
        '200':
          description: OK
          schema:
            $ref: '#/definitions/TenantEmailConfigResponse'
        '401':
          description: Unauthorized (missing/invalid X-API-KEY)
          schema:
            required:
            - detail
            type: object
            properties:
              detail:
                type: string
                example: Missing or invalid tenant API key.
        '403':
          description: Forbidden (TENANT_ADMIN key required)
          schema:
            required:
            - detail
            type: object
            properties:
              detail:
                type: string
                example: Tenant admin key required.
        '400':
          description: Bad Request (validation error)
          schema:
            type: object
            additionalProperties:
              type: array
              items:
                type: string
            example:
              from_email:
              - from_email is required.
      tags:
      - Tenancy
      security:
      - ApiKeyAuth: []
    patch:
      operationId: tenancy_email_config_patch
      summary: Upsert email config (TENANT_ADMIN)
      description: |-
        Creates/updates per-tenant email configuration.

        Requires: TENANT_ADMIN API key.

        Notes:
        - If `smtp_password` is omitted/blank, existing value is preserved.
        - Secrets are never returned.
      parameters:
      - name: data
        in: body
        required: true
        schema:
          $ref: '#/definitions/TenantEmailConfigUpsert'
      responses:
        '200':
          description: OK
          schema:
            $ref: '#/definitions/TenantEmailConfigResponse'
        '401':
          description: Unauthorized (missing/invalid X-API-KEY)
          schema:
            required:
            - detail
            type: object
            properties:
              detail:
                type: string
                example: Missing or invalid tenant API key.
        '403':
          description: Forbidden (TENANT_ADMIN key required)
          schema:
            required:
            - detail
            type: object
            properties:
              detail:
                type: string
                example: Tenant admin key required.
        '400':
          description: Bad Request (validation error)
          schema:
            type: object
            additionalProperties:
              type: array
              items:
                type: string
            example:
              from_email:
              - from_email is required.
      tags:
      - Tenancy
      security:
      - ApiKeyAuth: []
    parameters: []
  /tenancy/me/:
    get:
      operationId: tenancy_me_get
      summary: Get tenant profile + branding
      description: |-
        Use this endpoint to verify your tenant key works.

        Auth: Authorize with `X-API-KEY`.
      parameters: []
      responses:
        '200':
          description: OK
          schema:
            $ref: '#/definitions/TenantMeResponse'
          examples:
            application/json:
              id: 1
              name: Acme Org
              code: acme
              is_active: true
              created_at: '2026-01-17T07:00:00Z'
              branding:
                site_name: Acme Org
                site_url: https://acme.example
                support_email: support@acme.example
                unsubscribe_base_url: https://acme.example/unsubscribe
        '401':
          description: Unauthorized (missing/invalid X-API-KEY)
          schema:
            required:
            - detail
            type: object
            properties:
              detail:
                type: string
                example: Missing or invalid tenant API key.
      tags:
      - Tenancy
      security:
      - ApiKeyAuth: []
    patch:
      operationId: tenancy_me_patch
      summary: Update tenant profile (TENANT_ADMIN)
      description: |-
        Updates tenant editable fields.

        Requires: TENANT_ADMIN API key.
      parameters:
      - name: data
        in: body
        required: true
        schema:
          $ref: '#/definitions/TenantEdit'
      responses:
        '200':
          description: Updated
          schema:
            $ref: '#/definitions/TenantPublic'
        '401':
          description: Unauthorized (missing/invalid X-API-KEY)
          schema:
            required:
            - detail
            type: object
            properties:
              detail:
                type: string
                example: Missing or invalid tenant API key.
        '403':
          description: Forbidden (TENANT_ADMIN key required)
          schema:
            required:
            - detail
            type: object
            properties:
              detail:
                type: string
                example: Tenant admin key required.
        '400':
          description: Bad Request (validation error)
          schema:
            type: object
            additionalProperties:
              type: array
              items:
                type: string
            example:
              from_email:
              - from_email is required.
      tags:
      - Tenancy
      security:
      - ApiKeyAuth: []
    parameters: []
  /tenancy/status/:
    get:
      operationId: tenancy_status_get
      summary: Check tenant readiness (safe)
      description: Simple readiness checks for UIs/health dashboards.
      parameters: []
      responses:
        '200':
          description: OK
          schema:
            $ref: '#/definitions/TenantStatusResponse'
        '401':
          description: Unauthorized (missing/invalid X-API-KEY)
          schema:
            required:
            - detail
            type: object
            properties:
              detail:
                type: string
                example: Missing or invalid tenant API key.
      tags:
      - Tenancy
      security:
      - ApiKeyAuth: []
    parameters: []
definitions:
  EffectiveOTPConfigResponse:
    required:
    - charset
    - length
    - ttl_seconds
    - max_attempts
    - resend_cooldown_seconds
    - max_resends
    - is_active
    type: object
    properties:
      charset:
        title: Charset
        type: string
        minLength: 1
      length:
        title: Length
        type: integer
      ttl_seconds:
        title: Ttl seconds
        type: integer
      max_attempts:
        title: Max attempts
        type: integer
      resend_cooldown_seconds:
        title: Resend cooldown seconds
        type: integer
      max_resends:
        title: Max resends
        type: integer
      is_active:
        title: Is active
        type: boolean
  IssueOTP:
    required:
    - destination
    - channel
    - purpose
    type: object
    properties:
      destination:
        title: Destination
        type: string
        maxLength: 255
        minLength: 1
      channel:
        title: Channel
        type: string
        enum:
        - SMS
        - EMAIL
      purpose:
        title: Purpose
        type: string
        enum:
        - LOGIN
        - SIGNUP
        - RESET
        - VERIFY
      external_user_id:
        title: External user id
        type: string
        maxLength: 120
        x-nullable: true
      context:
        title: Context
        type: object
        additionalProperties:
          type: string
          x-nullable: true
  IssueOTPResponse:
    required:
    - otp_id
    - expires_at
    - resend_available_at
    - channel
    - purpose
    type: object
    properties:
      otp_id:
        title: Otp id
        type: string
        format: uuid
      expires_at:
        title: Expires at
        type: string
        format: date-time
      resend_available_at:
        title: Resend available at
        type: string
        format: date-time
        x-nullable: true
      channel:
        title: Channel
        type: string
        minLength: 1
      purpose:
        title: Purpose
        type: string
        minLength: 1
  ResendOTP:
    required:
    - otp_id
    type: object
    properties:
      otp_id:
        title: Otp id
        type: string
        format: uuid
  VerifyOTP:
    required:
    - otp_id
    - code
    type: object
    properties:
      otp_id:
        title: Otp id
        type: string
        format: uuid
      code:
        title: Code
        type: string
        maxLength: 32
        minLength: 1
  VerifyOTPResponse:
    required:
    - otp_id
    - verified
    - verified_at
    type: object
    properties:
      otp_id:
        title: Otp id
        type: string
        format: uuid
      verified:
        title: Verified
        type: boolean
      verified_at:
        title: Verified at
        type: string
        format: date-time
        x-nullable: true
  TenantBrandingResponse:
    required:
    - tenant
    - branding
    type: object
    properties:
      tenant:
        title: Tenant
        type: object
        additionalProperties:
          type: string
          x-nullable: true
      branding:
        title: Branding
        type: object
        additionalProperties:
          type: string
          x-nullable: true
  TenantEmailConfigSummary:
    type: object
    properties:
      provider:
        title: Provider
        type: string
        enum:
        - SMTP
        - SENDGRID
        - MAILGUN
        - SES
        readOnly: true
      from_email:
        title: From email
        type: string
        format: email
        readOnly: true
        minLength: 1
      from_name:
        title: From name
        type: string
        readOnly: true
        minLength: 1
      reply_to:
        title: Reply to
        type: string
        format: email
        readOnly: true
        minLength: 1
      is_active:
        title: Is active
        type: boolean
        readOnly: true
      updated_at:
        title: Updated at
        type: string
        format: date-time
        readOnly: true
      website_url:
        title: Website url
        type: string
        format: uri
        readOnly: true
        minLength: 1
      brand_name:
        title: Brand name
        type: string
        readOnly: true
        minLength: 1
      support_email:
        title: Support email
        type: string
        format: email
        readOnly: true
        minLength: 1
      unsubscribe_base_url:
        title: Unsubscribe base url
        type: string
        format: uri
        readOnly: true
        minLength: 1
    x-nullable: true
  Branding:
    type: object
    properties:
      site_name:
        title: Site name
        type: string
      site_url:
        title: Site url
        type: string
      support_email:
        title: Support email
        type: string
      unsubscribe_base_url:
        title: Unsubscribe base url
        type: string
  TenantEmailConfigResponse:
    required:
    - configured
    - config
    - branding
    type: object
    properties:
      configured:
        title: Configured
        type: boolean
      config:
        $ref: '#/definitions/TenantEmailConfigSummary'
      branding:
        $ref: '#/definitions/Branding'
  TenantEmailConfigUpsert:
    required:
    - from_email
    type: object
    properties:
      provider:
        title: Provider
        type: string
        enum:
        - SMTP
        - SENDGRID
        - MAILGUN
        - SES
      from_email:
        title: From email
        type: string
        format: email
        maxLength: 254
        minLength: 1
      from_name:
        title: From name
        type: string
        maxLength: 120
      reply_to:
        title: Reply to
        type: string
        format: email
        maxLength: 254
      is_active:
        title: Is active
        type: boolean
      smtp_host:
        title: Smtp host
        type: string
        maxLength: 255
      smtp_port:
        title: Smtp port
        type: integer
        maximum: 2147483647
        minimum: 0
        x-nullable: true
      smtp_username:
        title: Smtp username
        type: string
        maxLength: 255
      smtp_password:
        title: Smtp password
        type: string
      smtp_use_tls:
        title: Smtp use tls
        type: boolean
      smtp_use_ssl:
        title: Smtp use ssl
        type: boolean
      api_key:
        title: Api key
        type: string
      api_base_url:
        title: Api base url
        type: string
        maxLength: 255
      api_region:
        title: Api region
        type: string
        maxLength: 64
      website_url:
        title: Website url
        type: string
        format: uri
        maxLength: 200
      brand_name:
        title: Brand name
        type: string
        maxLength: 150
      support_email:
        title: Support email
        type: string
        format: email
        maxLength: 254
      unsubscribe_base_url:
        title: Unsubscribe base url
        type: string
        format: uri
        maxLength: 200
  TenantMeResponse:
    required:
    - id
    - name
    - code
    - is_active
    - created_at
    - branding
    type: object
    properties:
      id:
        title: Id
        type: integer
      name:
        title: Name
        type: string
        minLength: 1
      code:
        title: Code
        type: string
        minLength: 1
      is_active:
        title: Is active
        type: boolean
      created_at:
        title: Created at
        type: string
        format: date-time
      branding:
        $ref: '#/definitions/Branding'
  TenantEdit:
    required:
    - name
    type: object
    properties:
      name:
        title: Name
        type: string
        maxLength: 150
        minLength: 1
  TenantPublic:
    type: object
    properties:
      id:
        title: ID
        type: integer
        readOnly: true
      name:
        title: Name
        type: string
        readOnly: true
        minLength: 1
      code:
        title: Code
        type: string
        format: slug
        pattern: ^[-a-zA-Z0-9_]+$
        readOnly: true
        minLength: 1
      is_active:
        title: Is active
        type: boolean
        readOnly: true
      created_at:
        title: Created at
        type: string
        format: date-time
        readOnly: true
  TenantStatusResponse:
    required:
    - tenant
    - email
    type: object
    properties:
      tenant:
        title: Tenant
        type: object
        additionalProperties:
          type: string
          x-nullable: true
      email:
        title: Email
        type: object
        additionalProperties:
          type: string
          x-nullable: true
