swagger: '2.0'
info:
  title: OTP Management API
  description: |-
    Endpoints to issue and verify one-time passcodes (OTP) for login and other flows.

    - POST /api/otp/request/ — issue an OTP (Email/SMS)
    - POST /api/otp/verify/  — verify an issued OTP
  contact:
    email: eomoro@krb.go.ke
  license:
    name: BSD License
  version: v1
host: aprpms.devsgraphics.com
schemes:
- http
basePath: /api/otp
consumes:
- application/json
produces:
- application/json
securityDefinitions:
  Basic:
    type: basic
security:
- Basic: []
paths:
  /request/:
    post:
      operationId: otp_request
      summary: Issue an OTP
      description: |-
        Issues a one-time passcode.

        Examples:
         - {"purpose":"LOGIN","channel":"EMAIL","username_or_email":"omorodev"}
         - {"purpose":"LOGIN","channel":"SMS","destination":"+254712345678"}

        In non-production, response may include `code` if enabled.
      parameters:
      - name: data
        in: body
        required: true
        schema:
          $ref: '#/definitions/OTPRequest'
      responses:
        '201':
          description: ''
          schema:
            $ref: '#/definitions/OTPRequestResponse'
      tags:
      - request_otp
    parameters: []
  /resend/:
    post:
      operationId: otp_resend
      summary: Resend an OTP
      description: |-
        Resend by `id`. May reissue a new code (default) or resend the same valid code, depending on admin config.

        Example: {"id":"<uuid>"}
        Response mirrors issue payload plus `action`.
      parameters:
      - name: data
        in: body
        required: true
        schema:
          $ref: '#/definitions/OTPResend'
      responses:
        '200':
          description: ''
          schema:
            $ref: '#/definitions/OTPResendResponse'
      tags:
      - resend
    parameters: []
  /verify/:
    post:
      operationId: otp_verify
      summary: Verify an OTP
      description: |-
        Verify by `id` and `code`.

        Example: {"id":"<uuid>","code":"123456"}
        Possible reasons: invalid_code | expired | too_many_attempts | inactive | not_found.
      parameters:
      - name: data
        in: body
        required: true
        schema:
          $ref: '#/definitions/OTPVerify'
      responses:
        '200':
          description: ''
          schema:
            $ref: '#/definitions/OTPVerifyResponse'
        '400':
          description: ''
          schema:
            $ref: '#/definitions/OTPVerifyResponse'
      tags:
      - verify
    parameters: []
definitions:
  OTPRequest:
    required:
    - channel
    type: object
    properties:
      purpose:
        title: Purpose
        type: string
        enum:
        - LOGIN
        - PASSWORD_RESET
        - OTHER
        default: LOGIN
      channel:
        title: Channel
        type: string
        enum:
        - SMS
        - EMAIL
      username_or_email:
        title: Username or email
        type: string
      destination:
        title: Destination
        type: string
  OTPRequestResponse:
    required:
    - id
    - purpose
    - channel
    - destination
    - status
    - expires_at
    type: object
    properties:
      id:
        title: Id
        type: string
        format: uuid
      purpose:
        title: Purpose
        type: string
        minLength: 1
      channel:
        title: Channel
        type: string
        minLength: 1
      destination:
        title: Destination
        type: string
        minLength: 1
      status:
        title: Status
        type: string
        minLength: 1
      expires_at:
        title: Expires at
        type: string
        format: date-time
      sent_at:
        title: Sent at
        type: string
        format: date-time
        x-nullable: true
      code:
        title: Code
        type: string
        minLength: 1
  OTPResend:
    required:
    - id
    type: object
    properties:
      id:
        title: Id
        description: The OTP id you want to re-send
        type: string
        format: uuid
  OTPResendResponse:
    required:
    - id
    - purpose
    - channel
    - destination
    - status
    - expires_at
    - action
    type: object
    properties:
      id:
        title: Id
        type: string
        format: uuid
      purpose:
        title: Purpose
        type: string
        minLength: 1
      channel:
        title: Channel
        type: string
        minLength: 1
      destination:
        title: Destination
        type: string
        minLength: 1
      status:
        title: Status
        type: string
        minLength: 1
      expires_at:
        title: Expires at
        type: string
        format: date-time
      sent_at:
        title: Sent at
        type: string
        format: date-time
        x-nullable: true
      action:
        title: Action
        type: string
        minLength: 1
      code:
        title: Code
        type: string
        minLength: 1
  OTPVerify:
    required:
    - id
    - code
    type: object
    properties:
      id:
        title: Id
        type: string
        format: uuid
      code:
        title: Code
        type: string
        minLength: 1
  OTPVerifyResponse:
    required:
    - ok
    - reason
    type: object
    properties:
      ok:
        title: Ok
        type: boolean
      reason:
        title: Reason
        type: string
        minLength: 1
      user_id:
        title: User id
        type: string
        minLength: 1
        x-nullable: true
