# Copyright (c) 2026 RoundPenny. All rights reserved.

openapi: "3.0.3"
info:
  title: RoundPenny API
  version: "1.0.0"
  description: RoundPenny — Round-up micro-transaction platform API

servers:
- url: http://localhost:80
  description: Kong Gateway (local development)

paths:
  /v1/auth/register:
    post:
      summary: Register a new user
      tags: [Auth]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [email, password, name]
              properties:
                email: { type: string, format: email }
                password: { type: string, minLength: 8 }
                name: { type: string }
      responses:
        "201":
          description: User registered
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/User"
        "400": { description: Bad request }
        "409": { description: Conflict }

  /v1/auth/login:
    post:
      summary: Login with email and password
      tags: [Auth]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [email, password]
              properties:
                email: { type: string, format: email }
                password: { type: string }
      responses:
        "200":
          description: Login successful
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/LoginResponse"
        "401": { description: Invalid credentials }
        "429": { description: Account locked }

  /v1/auth/refresh:
    post:
      summary: Refresh access token
      tags: [Auth]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [refresh_token]
              properties:
                refresh_token: { type: string }
      responses:
        "200":
          description: Token refreshed
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TokenResponse"
        "401": { description: Invalid or expired refresh token }

  /v1/auth/logout:
    post:
      summary: Logout and revoke tokens
      tags: [Auth]
      security: [{ BearerAuth: [] }]
      responses:
        "204": { description: Logged out }
        "401": { description: Unauthorized }

  /v1/auth/me:
    get:
      summary: Get current user info
      tags: [Auth]
      security: [{ BearerAuth: [] }]
      responses:
        "200":
          description: Current user data
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/User"
        "401": { description: Unauthorized }

  /v1/auth/oauth/{provider}:
    post:
      summary: OAuth login with provider
      tags: [Auth]
      parameters:
      - name: provider
        in: path
        required: true
        schema: { type: string, enum: [google, github] }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [code]
              properties:
                code: { type: string }
                state: { type: string }
                redirect_uri: { type: string }
      responses:
        "200":
          description: OAuth login successful
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/LoginResponse"
        "400": { description: Bad request }

  /v1/auth/mfa/setup:
    post:
      summary: Setup MFA (generate secret)
      tags: [MFA]
      security: [{ BearerAuth: [] }]
      responses:
        "200":
          description: MFA secret generated
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/MfaSetupResponse"
        "401": { description: Unauthorized }

  /v1/auth/mfa/enable:
    post:
      summary: Enable MFA with verification code
      tags: [MFA]
      security: [{ BearerAuth: [] }]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [code]
              properties:
                code: { type: string }
      responses:
        "200":
          description: MFA enabled
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/MessageResponse"
        "400": { description: Invalid code }
        "401": { description: Unauthorized }

  /v1/auth/mfa/disable:
    post:
      summary: Disable MFA
      tags: [MFA]
      security: [{ BearerAuth: [] }]
      responses:
        "200":
          description: MFA disabled
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/MessageResponse"
        "400": { description: Bad request }
        "401": { description: Unauthorized }

  /v1/auth/mfa/verify:
    post:
      summary: Verify MFA code during login
      tags: [MFA]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [mfa_token, code]
              properties:
                mfa_token: { type: string }
                code: { type: string }
      responses:
        "200":
          description: MFA verified
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/LoginResponse"
        "401": { description: Invalid MFA code }

  /v1/auth/verify-email:
    post:
      summary: Send email verification
      tags: [Auth]
      security: [{ BearerAuth: [] }]
      responses:
        "200":
          description: Verification email sent
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/MessageResponse"
        "400": { description: Bad request }
        "401": { description: Unauthorized }

  /v1/auth/verify-email/confirm:
    post:
      summary: Confirm email verification token
      tags: [Auth]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [token]
              properties:
                token: { type: string }
      responses:
        "200":
          description: Email verified
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/MessageResponse"
        "400": { description: Invalid token }

  /v1/auth/kyc:
    post:
      summary: Submit KYC application
      tags: [KYC]
      security: [{ BearerAuth: [] }]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [full_name, document_type, document_number]
              properties:
                full_name: { type: string }
                document_type: { type: string }
                document_number: { type: string }
      responses:
        "201":
          description: KYC submitted
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/KycStatus"
        "400": { description: Bad request }
        "401": { description: Unauthorized }

  /v1/auth/kyc/status:
    get:
      summary: Get KYC application status
      tags: [KYC]
      security: [{ BearerAuth: [] }]
      responses:
        "200":
          description: KYC status
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/KycStatus"
        "401": { description: Unauthorized }
        "404": { description: No KYC submission found }

  /v1/users/me/profile:
    get:
      summary: Get user profile
      tags: [User]
      security: [{ BearerAuth: [] }]
      responses:
        "200":
          description: User profile
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/UserProfile"
        "401": { description: Unauthorized }
        "404": { description: Profile not found }
    put:
      summary: Update user profile
      tags: [User]
      security: [{ BearerAuth: [] }]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                display_name: { type: string }
                avatar_url: { type: string }
                bio: { type: string }
      responses:
        "204": { description: Profile updated }
        "400": { description: Bad request }
        "401": { description: Unauthorized }

  /v1/users/me/preferences:
    get:
      summary: Get user preferences
      tags: [User]
      security: [{ BearerAuth: [] }]
      responses:
        "200":
          description: User preferences
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/UserPreferences"
        "401": { description: Unauthorized }
        "404": { description: Preferences not found }
    put:
      summary: Update user preferences
      tags: [User]
      security: [{ BearerAuth: [] }]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                theme: { type: string }
                notifications_enabled: { type: boolean }
                locale: { type: string }
      responses:
        "200":
          description: Preferences updated
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/UserPreferences"
        "400": { description: Bad request }
        "401": { description: Unauthorized }

  /v1/merchants:
    post:
      summary: Create a merchant
      tags: [Merchant]
      security: [{ BearerAuth: [] }]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name, email]
              properties:
                name: { type: string }
                email: { type: string, format: email }
                description: { type: string }
      responses:
        "201":
          description: Merchant created
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Merchant"
        "400": { description: Bad request }
        "401": { description: Unauthorized }
    get:
      summary: List merchants
      tags: [Merchant]
      security: [{ BearerAuth: [] }]
      responses:
        "200":
          description: Merchant list
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Merchant"
        "401": { description: Unauthorized }

  /v1/merchants/search:
    get:
      summary: Search merchants
      tags: [Merchant]
      security: [{ BearerAuth: [] }]
      parameters:
      - name: q
        in: query
        required: true
        schema: { type: string }
      responses:
        "200":
          description: Search results
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Merchant"
        "400": { description: Missing query }
        "401": { description: Unauthorized }

  /v1/merchants/{id}:
    get:
      summary: Get a merchant by ID
      tags: [Merchant]
      security: [{ BearerAuth: [] }]
      parameters:
      - name: id
        in: path
        required: true
        schema: { type: string, format: uuid }
      responses:
        "200":
          description: Merchant data
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Merchant"
        "400": { description: Invalid ID }
        "401": { description: Unauthorized }
        "404": { description: Not found }
    put:
      summary: Update a merchant
      tags: [Merchant]
      security: [{ BearerAuth: [] }]
      parameters:
      - name: id
        in: path
        required: true
        schema: { type: string, format: uuid }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name: { type: string }
                email: { type: string, format: email }
                description: { type: string }
      responses:
        "200":
          description: Merchant updated
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Merchant"
        "400": { description: Bad request }
        "401": { description: Unauthorized }
        "404": { description: Not found }
    delete:
      summary: Delete a merchant
      tags: [Merchant]
      security: [{ BearerAuth: [] }]
      parameters:
      - name: id
        in: path
        required: true
        schema: { type: string, format: uuid }
      responses:
        "204": { description: Merchant deleted }
        "400": { description: Invalid ID }
        "401": { description: Unauthorized }
        "404": { description: Not found }

  /v1/transactions:
    post:
      summary: Create a transaction
      tags: [Transaction]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [user_id, amount, currency, type]
              properties:
                user_id: { type: string, format: uuid }
                amount: { type: number }
                currency: { type: string }
                type: { type: string }
                description: { type: string }
      responses:
        "201":
          description: Transaction created
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Transaction"
        "400": { description: Bad request }
    get:
      summary: List transactions by user
      tags: [Transaction]
      parameters:
      - name: user_id
        in: query
        required: true
        schema: { type: string, format: uuid }
      responses:
        "200":
          description: Transaction list
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Transaction"
        "400": { description: Bad request }
        "500": { description: Internal error }

  /v1/transactions/{id}:
    get:
      summary: Get transaction by ID
      tags: [Transaction]
      parameters:
      - name: id
        in: path
        required: true
        schema: { type: string, format: uuid }
      responses:
        "200":
          description: Transaction data
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Transaction"
        "400": { description: Invalid ID }
        "404": { description: Not found }

  /v1/transactions/webhook/{provider}:
    post:
      summary: Receive transaction webhook
      tags: [Transaction]
      parameters:
      - name: provider
        in: path
        required: true
        schema: { type: string }
      responses:
        "200":
          description: Webhook processed
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/MessageResponse"
        "400": { description: Bad request }

  /v1/wallets/me:
    get:
      summary: Get or create wallet
      tags: [Wallet]
      parameters:
      - name: user_id
        in: query
        required: true
        schema: { type: string, format: uuid }
      responses:
        "200":
          description: Wallet data
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Wallet"
        "400": { description: Bad request }

  /v1/wallets/me/transactions:
    get:
      summary: List wallet transactions
      tags: [Wallet]
      parameters:
      - name: user_id
        in: query
        required: true
        schema: { type: string, format: uuid }
      responses:
        "200":
          description: Wallet transactions
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Transaction"
        "400": { description: Bad request }

  /v1/wallets/me/withdraw:
    post:
      summary: Withdraw from wallet
      tags: [Wallet]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [user_id, amount, destination]
              properties:
                user_id: { type: string, format: uuid }
                amount: { type: number }
                destination: { type: object }
      responses:
        "200":
          description: Withdrawal initiated
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WithdrawalResponse"
        "400": { description: Bad request }

  /v1/fees/config:
    get:
      summary: Get fee configuration
      tags: [Fee]
      responses:
        "200":
          description: Fee configuration
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/FeeConfig"
        "500": { description: Internal error }

  /v1/investments/portfolios:
    get:
      summary: Get investment portfolios
      tags: [Investment]
      responses:
        "200":
          description: Portfolio data
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Portfolio"
        "500": { description: Internal error }

  /v1/payments:
    post:
      summary: Create a payment
      tags: [Payment Gateway]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [user_id, amount, currency, payment_method]
              properties:
                user_id: { type: string, format: uuid }
                amount: { type: number }
                currency: { type: string }
                payment_method: { type: string }
                description: { type: string }
                metadata: { type: object }
      responses:
        "201":
          description: Payment created
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PaymentResponse"
        "400": { description: Bad request }
    get:
      summary: List user payments
      tags: [Payment Gateway]
      parameters:
      - name: user_id
        in: query
        required: true
        schema: { type: string, format: uuid }
      responses:
        "200":
          description: Payment list
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/PaymentResponse"
        "400": { description: Bad request }

  /v1/payments/{id}:
    get:
      summary: Get payment by ID
      tags: [Payment Gateway]
      parameters:
      - name: id
        in: path
        required: true
        schema: { type: string, format: uuid }
      responses:
        "200":
          description: Payment data
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PaymentResponse"
        "400": { description: Invalid ID }
        "404": { description: Not found }

  /v1/payments/{id}/confirm:
    post:
      summary: Confirm/succeed a payment
      tags: [Payment Gateway]
      parameters:
      - name: id
        in: path
        required: true
        schema: { type: string, format: uuid }
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                stripe_payment_method_id: { type: string }
      responses:
        "200":
          description: Payment confirmed
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PaymentResponse"
        "400": { description: Bad request }
        "404": { description: Not found }

  /v1/webhooks/stripe:
    post:
      summary: Stripe webhook receiver
      tags: [Payment Gateway]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                type: { type: string }
                data: { type: object }
      responses:
        "200":
          description: Webhook processed
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/MessageResponse"
        "400": { description: Bad request }
        "404": { description: Payment not found }

  /v1/webhooks:
    post:
      summary: Create a webhook subscription
      tags: [Notification]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [user_id, url, events]
              properties:
                user_id: { type: string, format: uuid }
                url: { type: string, format: uri }
                secret: { type: string }
                events: { type: array, items: { type: string } }
                description: { type: string }
                retry_count: { type: integer }
                timeout_ms: { type: integer }
      responses:
        "201":
          description: Webhook created
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Webhook"
        "400": { description: Bad request }
    get:
      summary: List user webhooks
      tags: [Notification]
      parameters:
      - name: user_id
        in: query
        required: true
        schema: { type: string, format: uuid }
      responses:
        "200":
          description: Webhook list
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Webhook"
        "400": { description: Bad request }

  /v1/webhooks/{id}:
    get:
      summary: Get webhook by ID
      tags: [Notification]
      parameters:
      - name: id
        in: path
        required: true
        schema: { type: string, format: uuid }
      responses:
        "200":
          description: Webhook data
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Webhook"
        "400": { description: Invalid ID }
        "404": { description: Not found }
    put:
      summary: Update webhook subscription
      tags: [Notification]
      parameters:
      - name: id
        in: path
        required: true
        schema: { type: string, format: uuid }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                url: { type: string, format: uri }
                secret: { type: string }
                events: { type: array, items: { type: string } }
                is_active: { type: boolean }
                description: { type: string }
                retry_count: { type: integer }
                timeout_ms: { type: integer }
      responses:
        "200":
          description: Webhook updated
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Webhook"
        "400": { description: Bad request }
        "404": { description: Not found }
    delete:
      summary: Delete a webhook
      tags: [Notification]
      parameters:
      - name: id
        in: path
        required: true
        schema: { type: string, format: uuid }
      responses:
        "204": { description: Webhook deleted }
        "400": { description: Invalid ID }
        "404": { description: Not found }

  /v1/analytics/events:
    post:
      summary: Track an analytics event
      tags: [Analytics]
      security: [{ BearerAuth: [] }]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [type]
              properties:
                type: { type: string }
                properties: { type: object }
      responses:
        "201":
          description: Event tracked
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AnalyticsEvent"
        "400": { description: Bad request }
        "401": { description: Unauthorized }
    get:
      summary: List analytics events
      tags: [Analytics]
      parameters:
      - name: user_id
        in: query
        required: true
        schema: { type: string, format: uuid }
      responses:
        "200":
          description: Event list
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/AnalyticsEvent"
        "400": { description: Bad request }

  /v1/analytics/stats:
    get:
      summary: Get daily analytics stats
      tags: [Analytics]
      parameters:
      - name: start_date
        in: query
        required: true
        schema: { type: string, format: date }
      - name: end_date
        in: query
        required: true
        schema: { type: string, format: date }
      responses:
        "200":
          description: Daily stats
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AnalyticsStats"
        "400": { description: Bad request }

  /v1/fraud/rules:
    post:
      summary: Create a fraud rule
      tags: [Fraud]
      security: [{ BearerAuth: [] }]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name, type, config]
              properties:
                name: { type: string }
                type: { type: string }
                config: { type: object }
                enabled: { type: boolean }
                priority: { type: integer }
      responses:
        "201":
          description: Rule created
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/FraudRule"
        "400": { description: Bad request }
        "401": { description: Unauthorized }
    get:
      summary: List fraud rules
      tags: [Fraud]
      security: [{ BearerAuth: [] }]
      responses:
        "200":
          description: Rule list
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/FraudRule"
        "401": { description: Unauthorized }

  /v1/fraud/rules/{id}:
    get:
      summary: Get a fraud rule by ID
      tags: [Fraud]
      security: [{ BearerAuth: [] }]
      parameters:
      - name: id
        in: path
        required: true
        schema: { type: string, format: uuid }
      responses:
        "200":
          description: Rule data
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/FraudRule"
        "400": { description: Invalid ID }
        "401": { description: Unauthorized }
        "404": { description: Not found }
    put:
      summary: Update a fraud rule
      tags: [Fraud]
      security: [{ BearerAuth: [] }]
      parameters:
      - name: id
        in: path
        required: true
        schema: { type: string, format: uuid }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name: { type: string }
                type: { type: string }
                config: { type: object }
                enabled: { type: boolean }
                priority: { type: integer }
      responses:
        "200":
          description: Rule updated
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/FraudRule"
        "400": { description: Bad request }
        "401": { description: Unauthorized }
        "404": { description: Not found }

  /v1/fraud/alerts:
    post:
      summary: Create a fraud alert
      tags: [Fraud]
      security: [{ BearerAuth: [] }]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [rule_id, severity, message]
              properties:
                rule_id: { type: string, format: uuid }
                severity: { type: string }
                message: { type: string }
                metadata: { type: object }
      responses:
        "201":
          description: Alert created
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/FraudAlert"
        "400": { description: Bad request }
        "401": { description: Unauthorized }
    get:
      summary: List fraud alerts
      tags: [Fraud]
      security: [{ BearerAuth: [] }]
      responses:
        "200":
          description: Alert list
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/FraudAlert"
        "401": { description: Unauthorized }

  /v1/fraud/alerts/{id}:
    get:
      summary: Get a fraud alert by ID
      tags: [Fraud]
      security: [{ BearerAuth: [] }]
      parameters:
      - name: id
        in: path
        required: true
        schema: { type: string, format: uuid }
      responses:
        "200":
          description: Alert data
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/FraudAlert"
        "400": { description: Invalid ID }
        "401": { description: Unauthorized }
        "404": { description: Not found }

  /v1/fraud/alerts/{id}/status:
    put:
      summary: Update fraud alert status
      tags: [Fraud]
      security: [{ BearerAuth: [] }]
      parameters:
      - name: id
        in: path
        required: true
        schema: { type: string, format: uuid }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [status]
              properties:
                status: { type: string }
      responses:
        "200":
          description: Alert status updated
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/FraudAlert"
        "400": { description: Bad request }
        "401": { description: Unauthorized }
        "404": { description: Not found }

  /v1/fraud/users/{userId}/alerts:
    get:
      summary: Get fraud alerts by user
      tags: [Fraud]
      security: [{ BearerAuth: [] }]
      parameters:
      - name: userId
        in: path
        required: true
        schema: { type: string, format: uuid }
      responses:
        "200":
          description: User alerts
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/FraudAlert"
        "400": { description: Invalid ID }
        "401": { description: Unauthorized }

  /v1/fraud/alerts/severity/{severity}:
    get:
      summary: Get fraud alerts by severity
      tags: [Fraud]
      security: [{ BearerAuth: [] }]
      parameters:
      - name: severity
        in: path
        required: true
        schema: { type: string }
      responses:
        "200":
          description: Alerts by severity
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/FraudAlert"
        "401": { description: Unauthorized }

  # ─── Admin ───────────────────────────────────────────────────────────
  /v1/admin/login:
    post:
      summary: Admin login
      tags: [Admin]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [email, password]
              properties:
                email: { type: string }
                password: { type: string }
      responses:
        "200":
          description: Admin login successful
          content:
            application/json:
              schema:
                type: object
                properties:
                  access_token: { type: string }
                  token_type: { type: string }
                  expires_in: { type: integer }
        "401": { description: Invalid credentials }

  /v1/admin/stats:
    get:
      summary: Get admin dashboard stats
      tags: [Admin]
      security: [{ BearerAuth: [] }]
      responses:
        "200":
          description: Dashboard stats
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AdminStats"
        "401": { description: Unauthorized }

  /v1/admin/users:
    get:
      summary: List all users
      tags: [Admin]
      security: [{ BearerAuth: [] }]
      parameters:
        - { in: query, name: page, schema: { type: integer } }
        - { in: query, name: page_size, schema: { type: integer } }
      responses:
        "200":
          description: Paginated user list
          content:
            application/json:
              schema:
                type: object
                properties:
                  data: { type: array, items: { $ref: "#/components/schemas/User" } }
                  total: { type: integer }
                  page: { type: integer }

  /v1/admin/users/{id}:
    get:
      summary: Get user detail
      tags: [Admin]
      security: [{ BearerAuth: [] }]
      parameters:
        - { in: path, name: id, required: true, schema: { type: string, format: uuid } }
      responses:
        "200":
          description: User detail
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AdminUserDetail"
        "404": { description: Not found }

    put:
      summary: Update user status
      tags: [Admin]
      security: [{ BearerAuth: [] }]
      parameters:
        - { in: path, name: id, required: true, schema: { type: string, format: uuid } }
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                kyc_status: { type: string, enum: [pending, approved, rejected] }
      responses:
        "200": { description: Status updated }

  /v1/admin/merchants:
    get:
      summary: List all merchants
      tags: [Admin]
      security: [{ BearerAuth: [] }]
      parameters:
        - { in: query, name: page, schema: { type: integer } }
        - { in: query, name: page_size, schema: { type: integer } }
      responses:
        "200":
          description: Paginated merchant list
          content:
            application/json:
              schema:
                type: object
                properties:
                  data: { type: array, items: { $ref: "#/components/schemas/Merchant" } }
                  total: { type: integer }
                  page: { type: integer }

  /v1/admin/merchants/{id}:
    get:
      summary: Get merchant detail
      tags: [Admin]
      security: [{ BearerAuth: [] }]
      parameters:
        - { in: path, name: id, required: true, schema: { type: string, format: uuid } }
      responses:
        "200":
          description: Merchant detail
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Merchant"
        "404": { description: Not found }

  /v1/admin/transactions:
    get:
      summary: List all transactions
      tags: [Admin]
      security: [{ BearerAuth: [] }]
      parameters:
        - { in: query, name: page, schema: { type: integer } }
        - { in: query, name: page_size, schema: { type: integer } }
      responses:
        "200":
          description: Paginated transaction list
          content:
            application/json:
              schema:
                type: object
                properties:
                  data: { type: array, items: { $ref: "#/components/schemas/Transaction" } }
                  total: { type: integer }
                  page: { type: integer }

  /v1/admin/transactions/{id}:
    get:
      summary: Get transaction detail
      tags: [Admin]
      security: [{ BearerAuth: [] }]
      parameters:
        - { in: path, name: id, required: true, schema: { type: string, format: uuid } }
      responses:
        "200":
          description: Transaction detail
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Transaction"
        "404": { description: Not found }

  /v1/admin/fraud-alerts:
    get:
      summary: List fraud alerts
      tags: [Admin]
      security: [{ BearerAuth: [] }]
      parameters:
        - { in: query, name: page, schema: { type: integer } }
        - { in: query, name: page_size, schema: { type: integer } }
      responses:
        "200":
          description: Paginated fraud alert list
          content:
            application/json:
              schema:
                type: object
                properties:
                  data: { type: array, items: { $ref: "#/components/schemas/FraudAlert" } }
                  total: { type: integer }
                  page: { type: integer }

  /v1/admin/fraud-alerts/{id}/review:
    post:
      summary: Review a fraud alert
      tags: [Admin]
      security: [{ BearerAuth: [] }]
      parameters:
        - { in: path, name: id, required: true, schema: { type: string, format: uuid } }
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                status: { type: string, enum: [resolved, false_positive, investigated] }
      responses:
        "200": { description: Alert reviewed }

  /v1/admin/kyc-submissions:
    get:
      summary: List KYC submissions
      tags: [Admin]
      security: [{ BearerAuth: [] }]
      parameters:
        - { in: query, name: page, schema: { type: integer } }
        - { in: query, name: page_size, schema: { type: integer } }
      responses:
        "200":
          description: Paginated KYC submission list
          content:
            application/json:
              schema:
                type: object
                properties:
                  data: { type: array, items: { $ref: "#/components/schemas/KycSubmission" } }
                  total: { type: integer }
                  page: { type: integer }

  /v1/admin/kyc-submissions/{id}/review:
    post:
      summary: Review a KYC submission
      tags: [Admin]
      security: [{ BearerAuth: [] }]
      parameters:
        - { in: path, name: id, required: true, schema: { type: string, format: uuid } }
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                status: { type: string, enum: [approved, rejected] }
                rejection_reason: { type: string }
      responses:
        "200": { description: KYC reviewed }

  # ─── Email ───────────────────────────────────────────────────────────
  /v1/emails/send:
    post:
      summary: Send an email
      tags: [Email]
      security: [{ BearerAuth: [] }]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [to, subject]
              properties:
                user_id: { type: string, format: uuid }
                to: { type: string, format: email }
                subject: { type: string }
                body: { type: string }
                html: { type: string }
      responses:
        "200":
          description: Email sent
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EmailLog"
        "400": { description: Bad request }
        "401": { description: Unauthorized }

  /v1/emails:
    get:
      summary: List sent emails
      tags: [Email]
      security: [{ BearerAuth: [] }]
      parameters:
        - { in: query, name: page, schema: { type: integer } }
        - { in: query, name: page_size, schema: { type: integer } }
      responses:
        "200":
          description: Paginated email log list
          content:
            application/json:
              schema:
                type: object
                properties:
                  data: { type: array, items: { $ref: "#/components/schemas/EmailLog" } }
                  total: { type: integer }
                  page: { type: integer }

components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT

  schemas:
    PaymentResponse:
      type: object
      properties:
        id: { type: string, format: uuid, description: Payment ID }
        user_id: { type: string, format: uuid }
        transaction_id: { type: string, format: uuid, nullable: true }
        amount: { type: number, description: Payment amount }
        currency: { type: string, example: USD }
        status: { type: string, enum: [pending, completed, failed] }
        payment_method: { type: string }
        stripe_payment_intent_id: { type: string, description: Stripe PaymentIntent ID }
        client_secret: { type: string, description: Stripe client secret for front-end confirmation }
        description: { type: string }
        metadata: { type: object }
        error_message: { type: string, nullable: true }
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }

    User:
      type: object
      properties:
        id: { type: string, format: uuid }
        email: { type: string, format: email }
        full_name: { type: string }
        role: { type: string, enum: [user, admin] }
        email_verified: { type: boolean }
        kyc_status: { type: string, enum: [none, pending, verified, rejected] }
        mfa_enabled: { type: boolean }
        created_at: { type: string, format: date-time }

    LoginResponse:
      type: object
      properties:
        access_token: { type: string }
        refresh_token: { type: string }
        expires_in: { type: integer }
        user:
          $ref: "#/components/schemas/User"

    TokenResponse:
      type: object
      properties:
        access_token: { type: string }
        refresh_token: { type: string }
        expires_in: { type: integer }

    MfaSetupResponse:
      type: object
      properties:
        secret: { type: string }
        qr_code: { type: string }

    MessageResponse:
      type: object
      properties:
        message: { type: string }

    KycStatus:
      type: object
      properties:
        id: { type: string, format: uuid }
        user_id: { type: string, format: uuid }
        full_name: { type: string }
        document_type: { type: string }
        document_number: { type: string }
        status: { type: string, enum: [pending, verified, rejected] }
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }

    UserProfile:
      type: object
      properties:
        id: { type: string, format: uuid }
        user_id: { type: string, format: uuid }
        display_name: { type: string }
        avatar_url: { type: string }
        bio: { type: string }
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }

    UserPreferences:
      type: object
      properties:
        id: { type: string, format: uuid }
        user_id: { type: string, format: uuid }
        theme: { type: string }
        notifications_enabled: { type: boolean }
        locale: { type: string }
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }

    Merchant:
      type: object
      properties:
        id: { type: string, format: uuid }
        name: { type: string }
        email: { type: string, format: email }
        description: { type: string }
        status: { type: string, enum: [active, inactive, suspended] }
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }

    Transaction:
      type: object
      properties:
        id: { type: string, format: uuid }
        user_id: { type: string, format: uuid }
        amount: { type: number }
        currency: { type: string }
        type: { type: string }
        status: { type: string, enum: [pending, completed, failed, refunded] }
        description: { type: string }
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }

    Wallet:
      type: object
      properties:
        id: { type: string, format: uuid }
        user_id: { type: string, format: uuid }
        balance: { type: number }
        currency: { type: string }
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }

    WithdrawalResponse:
      type: object
      properties:
        id: { type: string, format: uuid }
        user_id: { type: string, format: uuid }
        amount: { type: number }
        destination: { type: object }
        status: { type: string }
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }

    FeeConfig:
      type: object
      properties:
        id: { type: string, format: uuid }
        name: { type: string }
        percentage: { type: number }
        flat_fee: { type: number }
        min_fee: { type: number }
        max_fee: { type: number }
        currency: { type: string }
        is_active: { type: boolean }
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }

    Portfolio:
      type: object
      properties:
        id: { type: string, format: uuid }
        user_id: { type: string, format: uuid }
        name: { type: string }
        total_value: { type: number }
        cash_balance: { type: number }
        currency: { type: string }
        holdings:
          type: array
          items:
            $ref: "#/components/schemas/PortfolioHolding"
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }

    PortfolioHolding:
      type: object
      properties:
        id: { type: string, format: uuid }
        portfolio_id: { type: string, format: uuid }
        asset: { type: string }
        quantity: { type: number }
        purchase_price: { type: number }
        current_price: { type: number }
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }

    Webhook:
      type: object
      properties:
        id: { type: string, format: uuid }
        user_id: { type: string, format: uuid }
        url: { type: string, format: uri }
        secret: { type: string }
        events:
          type: array
          items: { type: string }
        is_active: { type: boolean }
        description: { type: string }
        retry_count: { type: integer }
        timeout_ms: { type: integer }
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }

    AnalyticsEvent:
      type: object
      properties:
        id: { type: string, format: uuid }
        user_id: { type: string, format: uuid }
        type: { type: string }
        properties: { type: object }
        created_at: { type: string, format: date-time }

    AnalyticsStats:
      type: object
      properties:
        date: { type: string, format: date }
        total_events: { type: integer }
        unique_users: { type: integer }
        event_breakdown: { type: object }

    FraudRule:
      type: object
      properties:
        id: { type: string, format: uuid }
        name: { type: string }
        type: { type: string }
        config: { type: object }
        enabled: { type: boolean }
        priority: { type: integer }
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }

    FraudAlert:
      type: object
      properties:
        id: { type: string, format: uuid }
        rule_id: { type: string, format: uuid }
        user_id: { type: string, format: uuid }
        severity: { type: string }
        message: { type: string }
        metadata: { type: object }
        status: { type: string, enum: [open, investigating, resolved, dismissed] }
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }

    LedgerEntry:
      type: object
      properties:
        id: { type: string, format: uuid }
        user_id: { type: string, format: uuid }
        transaction_id: { type: string, format: uuid }
        amount: { type: number }
        balance_before: { type: number }
        balance_after: { type: number }
        type: { type: string, enum: [debit, credit] }
        description: { type: string }
        created_at: { type: string, format: date-time }

     Notification:
       type: object
       properties:
         id: { type: string, format: uuid }
         user_id: { type: string, format: uuid }
         type: { type: string }
         title: { type: string }
         body: { type: string }
         is_read: { type: boolean }
         created_at: { type: string, format: date-time }

     AdminStats:
       type: object
       properties:
         total_users: { type: integer }
         pending_kyc: { type: integer }
         active_merchants: { type: integer }
         total_transactions: { type: integer }
         open_fraud_alerts: { type: integer }
         pending_payments: { type: integer }

     AdminUserDetail:
       type: object
       properties:
         id: { type: string, format: uuid }
         email: { type: string, format: email }
         full_name: { type: string }
         phone: { type: string }
         kyc_status: { type: string }
         mfa_enabled: { type: boolean }
         role: { type: string }
         created_at: { type: string, format: date-time }
         updated_at: { type: string, format: date-time }

     KycSubmission:
       type: object
       properties:
         id: { type: string, format: uuid }
         user_id: { type: string, format: uuid }
         full_name: { type: string }
         document_type: { type: string }
         document_number: { type: string }
         status: { type: string, enum: [pending, approved, rejected] }
         rejection_reason: { type: string }
         submitted_at: { type: string, format: date-time }
         reviewed_at: { type: string, format: date-time }

     EmailLog:
       type: object
       properties:
         id: { type: string, format: uuid }
         user_id: { type: string, format: uuid }
         to_email: { type: string, format: email }
         subject: { type: string }
         body: { type: string }
         html: { type: string }
         status: { type: string, enum: [sent, failed, pending] }
         error: { type: string }
         sent_at: { type: string, format: date-time, nullable: true }
         created_at: { type: string, format: date-time }
