openapi: 3.1.0
info:
  title: MaiGuard API
  version: 1.0.0
  description: |
    Real-time fraud scoring and AML monitoring API for payment platforms.
    Base URL: https://api.maiguard.com
    All paths are prefixed with /v1/.
  contact:
    name: MaiGuard Support
    url: https://maiguard.com/en/contact
  license:
    name: Proprietary
servers:
  - url: https://api.maiguard.com/v1
    description: Production

security:
  - BearerAuth: []

paths:
  /transactions/score:
    post:
      operationId: scoreTransaction
      summary: Score a transaction synchronously
      description: Returns riskScore, decision (ALLOW/REVIEW/BLOCK), and matched rules in under 200ms.
      parameters:
        - name: Idempotency-Key
          in: header
          schema:
            type: string
          description: Optional idempotency key for safe retries
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ScoreTransactionRequest'
      responses:
        '200':
          description: Scoring result
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ScoreTransactionResponse'
        '400':
          description: Validation error
        '429':
          description: Rate limit exceeded

  /transactions/batch-score:
    post:
      operationId: batchScoreTransactions
      summary: Score multiple transactions in batch
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [transactions]
              properties:
                transactions:
                  type: array
                  items:
                    $ref: '#/components/schemas/ScoreTransactionRequest'
      responses:
        '200':
          description: Synchronous batch results
        '202':
          description: Async batch accepted

  /webhooks/transactions/{path}:
    post:
      operationId: ingestWebhookTransaction
      summary: Inbound webhook transaction ingestion
      parameters:
        - name: path
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ScoreTransactionRequest'
      responses:
        '200':
          description: Accepted

  /transactions/import:
    post:
      operationId: importTransactions
      summary: Bulk file import (CSV, JSON, JSONL)
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                file:
                  type: string
                  format: binary
      responses:
        '202':
          description: Import accepted

  /customers/{customerId}/onboard:
    put:
      operationId: onboardCustomer
      summary: Onboard a customer with KYC/KYB context
      parameters:
        - name: customerId
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Customer onboarded

components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      description: API key (pk_live_... or pk_test_...)

  schemas:
    ScoreTransactionRequest:
      type: object
      required: [userId, amount, currency]
      properties:
        userId:
          type: string
          description: Stable customer ID
        amount:
          type: number
          description: Transaction amount (positive)
        currency:
          type: string
          description: ISO 4217 currency code (e.g. NGN, USD)
        occurredAt:
          type: string
          format: date-time
        ipAddress:
          type: string
        userAgent:
          type: string
        deviceId:
          type: string
        deviceSessionId:
          type: string
          description: From Browser SDK; must start with ds_
        location:
          type: object
          properties:
            latitude:
              type: number
            longitude:
              type: number
        metadata:
          type: object
          description: Business context; see payload richness tiers in API docs

    ScoreTransactionResponse:
      type: object
      properties:
        success:
          type: boolean
        data:
          type: object
          properties:
            transactionId:
              type: string
              format: uuid
            riskScore:
              type: integer
              minimum: 0
              maximum: 100
              description: Higher = riskier
            decision:
              type: string
              enum: [ALLOW, REVIEW, BLOCK]
            matchedRules:
              type: array
              items:
                type: object
                properties:
                  ruleId:
                    type: string
                  ruleName:
                    type: string
                  action:
                    type: string
            shadowEvaluation:
              type: object
              properties:
                hasShadowRules:
                  type: boolean
                shadowDecision:
                  type: string
                shadowRiskScore:
                  type: integer
