openapi: 3.1.0
info:
  title: Embedded Finance API (v1.2.0)
  version: 1.0.0
  description: API documentation for the Embedded Finance Microservice.
  contact:
    name: Eunifin Dev
    email: devteam@eunifin.com
servers:
  - url: http://localhost:8080
    description: Local development server
tags:
  - name: Transactions
    description: Transaction initiation and query endpoints.
  - name: Loan Transactions
    description: Loan lifecycle transaction endpoints.
  - name: Rail Notifications
    description: Rail notification simulation and status endpoints.
paths:
  /transactions/virtual-card:
    post:
      tags:
        - Transactions
      summary: Create a virtual card for a user
      description: |
        Creates a virtual card for a user in the embedded finance system.

        **All fields are required.**

        Example request:
        ```json
        {
          "metaData": {
            "idempotencyKey": "partnerId_uuid",
            "partnerId": "partner-id",
            "partnerUserRef": "partner-user-id"
          },
          "payload": {
            "accountId": "6c9083ce-b9d6-4415-8ad1-e32050fc8f93",
            "userId": "d650dbc9-c067-40d1-9041-6bc65db27cda",
            "name": "Sam",
            "type": 1,
            "useType": 2,
            "features": {
              "domestic": true,
              "international": false,
              "eCommerce": true,
              "atm": true,
              "pos": true,
              "contactless": true
            },
            "limits": {
              "transactionEnabled": true,
              "transaction": 75000,
              "dailyEnabled": true,
              "daily": 75000,
              "monthlyEnabled": true,
              "monthly": 75000,
              "yearlyEnabled": false,
              "yearly": 0
            }
          }
        }
        ```

        Example response:
        ```json
        {
          "transactionData": {
            "transactionId": 1,
            "transactionType": "VIRTUAL_CARD",
            "transactionStatus": "COMPLETED",
            "failedStep": null
          },
          "payload": {
            "cardId": "97c89895-372b-48ee-81c4-3230b4dbb6fd"
          }
        }
        ```
      operationId: createVirtualCard
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Request'
            example:
              metaData:
                idempotencyKey: partnerId_uuid
                partnerId: partner-id
                partnerUserRef: partner-user-id
              payload:
                accountId: 6c9083ce-b9d6-4415-8ad1-e32050fc8f93
                userId: d650dbc9-c067-40d1-9041-6bc65db27cda
                name: Sam
                type: 1
                useType: 2
      responses:
        '200':
          description: Virtual card created successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Response'
  /transactions/transfer:
    post:
      tags:
        - Transactions
      summary: Transfer money between accounts
      description: |
        Performs a payment transaction from one account to another.

        **All fields are required.**

        Example request:
        ```json
        {
          "metaData": {
            "idempotencyKey": "partnerId_uuid",
            "partnerId": "partner-id",
            "partnerUserRef": "partner-user-id"
          },
          "payload": {
            "transactionAmount": 600,
            "transactionDate": "YYYY-MM-DD",
            "paymentTypeId": 1,
            "note": "note",
            "reasonForBlock": "reasonForBlock",
            "dateFormat": "yyyy-MM-dd",
            "locale": "en",
            "accountId": "6c9083ce-b9d6-4415-8ad1-e32050fc8f93",
            "clientTxId": "23da476e-0022-434d-96f0-18ce700c291a",
            "ref": "This funds are for testing only, not for personal use Ruth",
            "ownRef": "Sending test funds to Saga",
            "accountNumber": "62000004947",
            "branchCode": "006754",
            "name": "Ruth",
            "payAndClear": true,
            "notificationEmail": "notification_email",
            "notificationName": "notification_name",
            "beneficiaryId": "beneficiary_id",
            "beneficiaryVersion": 1
          }
        }
        ```
      operationId: transfer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Request'
      responses:
        '200':
          description: Transfer initiated successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Response'
  /transactions/receive:
    post:
      tags:
        - Transactions
      summary: Receive an inbound transaction result
      description: Accepts a receive transaction request payload.
      operationId: receive
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Request'
      responses:
        '200':
          description: Receive transaction processed successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Response'
  /transactions/open-account:
    post:
      tags:
        - Transactions
      summary: Open a savings account for a user
      description: |
        Opens an account for a user in the embedded finance platform.

        **All fields are required.**

        Example request:
        ```json
        {
          "metaData": {
            "idempotencyKey": "partnerId_uuid",
            "partnerId": "partner-id",
            "partnerUserRef": "partner-user-id"
          },
          "payload": {
            "productId": 1,
            "activationDate": "YYYY-MM-DD"
          }
        }
        ```
      operationId: openAccount
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Request'
      responses:
        '200':
          description: Account opened successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Response'
  /transactions/loans/{loanId}/repay:
    post:
      tags:
        - Loan Transactions
      summary: Pay a loan
      description: |
        Makes a repayment for a loan.

        **All fields are required.**
      operationId: repayLoan
      parameters:
        - name: loanId
          in: path
          required: true
          description: Loan identifier.
          schema:
            type: integer
            format: int64
            example: 236
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Request'
      responses:
        '200':
          description: Loan repayment processed successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Response'
  /transactions/loans/{loanId}/disburse:
    post:
      tags:
        - Loan Transactions
      summary: Disburse an approved loan
      description: >
        Disburses an approved loan to the borrower. The loan must already be in
        approved status.


        **All fields are required.**
      operationId: disburseLoan
      parameters:
        - name: loanId
          in: path
          required: true
          description: Loan identifier.
          schema:
            type: integer
            format: int64
            example: 236
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Request'
      responses:
        '200':
          description: Loan disbursed successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Response'
  /transactions/loans/{loanId}/approve:
    post:
      tags:
        - Loan Transactions
      summary: Approve a loan
      description: |
        Attempts to approve a submitted loan.

        **All fields are required.**
      operationId: approveLoan
      parameters:
        - name: loanId
          in: path
          required: true
          description: Loan identifier.
          schema:
            type: integer
            format: int64
            example: 236
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Request'
      responses:
        '200':
          description: Loan approved successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Response'
  /transactions/loans/write-off:
    post:
      tags:
        - Loan Transactions
      summary: Write off a loan
      description: |
        Writes off a loan.

        **All fields are required.**
      operationId: closeLoan
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Request'
      responses:
        '200':
          description: Loan written off successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Response'
  /transactions/loans/create:
    post:
      tags:
        - Loan Transactions
      summary: Apply for a loan
      description: |
        Attempts to create and submit a loan application.

        **All fields are required.**
      operationId: createLoan
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Request'
      responses:
        '200':
          description: Loan application submitted successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Response'
  /transactions/kyc-results:
    post:
      tags:
        - Transactions
      summary: Submit KYC results
      description: Accepts KYC result payloads for processing.
      operationId: kycResults
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Request'
      responses:
        '200':
          description: KYC results processed successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Response'
  /transactions/create-client:
    post:
      tags:
        - Transactions
      summary: Create a user profile
      description: |
        Creates a client profile in the embedded finance platform.

        **All fields are required.**

        Example request:
        ```json
        {
          "metaData": {
            "idempotencyKey": "partnerId_uuid",
            "partnerId": "partner-id",
            "partnerUserRef": "partner-user-id"
          },
          "payload": {
            "email": "ronald@gmail.com",
            "name": "Ronald",
            "entityType": "personal",
            "country": "ZAF",
            "firstName": "Ronald",
            "lastName": "Commander",
            "phoneNumber": "0652345678",
            "gender": "male",
            "dateOfBirth": "YYYY-MM-DD",
            "idNumber": "6979298760776",
            "idType": "National",
            "idIssueDate": "YYYY-MM-DD",
            "city": "Jozi",
            "residency": "Soweto",
            "title": "Ms",
            "officeId": 1
          }
        }
        ```
      operationId: createClient
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Request'
      responses:
        '200':
          description: Client created successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Response'
  /rail/notifications/simulate:
    post:
      tags:
        - Rail Notifications
      summary: Simulate a rail notification
      description: Simulates receipt of a rail notification message.
      operationId: simulateNotification
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RailNotificationMessage'
      responses:
        '200':
          description: Notification simulated successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SimulateResponse'
  /transactions:
    get:
      tags:
        - Transactions
      summary: List saga transactions
      description: >-
        Returns transaction records for saga executions. The `partnerId`
        parameter is typically required by consumers, while `status` and `type`
        are optional filters.
      operationId: listTransactions
      parameters:
        - name: partnerId
          in: query
          required: false
          description: Partner identifier used to filter transactions.
          schema:
            type: string
            example: partner-id
        - name: status
          in: query
          required: false
          description: Transaction status filter.
          schema:
            type: string
            example: COMPLETED
        - name: type
          in: query
          required: false
          description: Transaction type filter.
          schema:
            type: string
            example: TRANSFER
      responses:
        '200':
          description: Transactions returned successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Response'
  /transactions/{id}:
    get:
      tags:
        - Transactions
      summary: Get a transaction by identifier
      description: Returns a transaction initiated by the partner.
      operationId: getTransaction
      parameters:
        - name: id
          in: path
          required: true
          description: Transaction identifier.
          schema:
            type: string
            example: '1'
      responses:
        '200':
          description: Transaction returned successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Response'
  /transactions/user-info:
    get:
      tags:
        - Transactions
      summary: Get user information
      description: Returns user information for the supplied request payload.
      operationId: getUserInfo
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Request'
      responses:
        '200':
          description: User information returned successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Response'
  /rail/notifications:
    get:
      tags:
        - Rail Notifications
      summary: List rail notifications
      description: Returns all stored rail notification log entries.
      operationId: getAllNotifications
      responses:
        '200':
          description: Rail notifications returned successfully.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/RailNotificationLog'
  /rail/notifications/{railTransactionId}:
    get:
      tags:
        - Rail Notifications
      summary: Get a rail notification by rail transaction identifier
      description: Returns a single rail notification log by rail transaction identifier.
      operationId: getByRailTransactionId
      parameters:
        - name: railTransactionId
          in: path
          required: true
          description: Rail transaction identifier.
          schema:
            type: string
            example: rail-tx-123
      responses:
        '200':
          description: Rail notification returned successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RailNotificationLog'
  /rail/notifications/status:
    get:
      tags:
        - Rail Notifications
      summary: Get rail notification connection status
      description: Returns the current rail notification connection status.
      operationId: getStatus
      responses:
        '200':
          description: Connection status returned successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ConnectionStatus'
components:
  schemas:
    MetaData:
      type: object
      description: Standard metadata supplied with each partner request.
      required:
        - idempotencyKey
        - partnerId
        - partnerUserRef
      properties:
        idempotencyKey:
          type: string
          description: Unique idempotency key for the request.
          example: partnerId_uuid
        partnerId:
          type: string
          description: Partner identifier.
          example: partner-id
        partnerUserRef:
          type: string
          description: Partner-side user reference.
          example: partner-user-id
    Request:
      type: object
      description: Generic request envelope.
      required:
        - metaData
        - payload
      properties:
        metaData:
          $ref: '#/components/schemas/MetaData'
        payload:
          type: object
          additionalProperties: true
          description: Operation-specific payload.
          example:
            accountId: 6c9083ce-b9d6-4415-8ad1-e32050fc8f93
    Response:
      type: object
      description: Generic response envelope.
      required:
        - transactionData
        - payload
      properties:
        transactionData:
          $ref: '#/components/schemas/TransactionData'
        payload:
          type: object
          additionalProperties: true
          description: Operation-specific response payload.
          example:
            cardId: 97c89895-372b-48ee-81c4-3230b4dbb6fd
    TransactionData:
      type: object
      description: Summary information about a saga transaction.
      required:
        - transactionId
        - transactionType
        - transactionStatus
      properties:
        transactionId:
          type: integer
          format: int64
          description: Internal transaction identifier.
          example: 1
        transactionType:
          type: string
          description: Type of transaction performed.
          example: TRANSFER
        transactionStatus:
          type: string
          description: Current transaction status.
          example: COMPLETED
        failedStep:
          type:
            - string
            - 'null'
          description: Name of the failed saga step when applicable.
          example: BANK_SUBMITTED
    Amount:
      type: object
      description: Monetary amount payload.
      required:
        - amount
        - currency
      properties:
        amount:
          type: integer
          format: int64
          description: Amount in minor units.
          example: 12500
        currency:
          type: string
          description: ISO currency code.
          example: ZAR
    DataPayload:
      type: object
      description: Rail notification data payload.
      required:
        - amount
        - timestamp
        - notification_type
        - transaction_id
        - transaction_type
        - account_id
      properties:
        amount:
          $ref: '#/components/schemas/Amount'
        timestamp:
          type: string
          format: date-time
          description: Event timestamp.
          example: '2026-03-06T08:00:00Z'
        notification_type:
          type: string
          description: Notification type received from the rail.
          example: PAYMENT
        transaction_id:
          type: string
          description: Rail transaction identifier.
          example: rail-tx-123
        transaction_type:
          type: string
          description: Rail transaction type.
          example: TRANSFER
        account_id:
          type: string
          description: Related account identifier.
          example: 6c9083ce-b9d6-4415-8ad1-e32050fc8f93
    RailNotificationMessage:
      type: object
      description: Notification event received from the rail.
      required:
        - event
        - data
      properties:
        event:
          type: string
          description: Event name.
          example: transfer.completed
        data:
          $ref: '#/components/schemas/DataPayload'
    SimulateResponse:
      type: object
      description: Result of a simulated rail notification.
      required:
        - success
        - message
        - transactionId
      properties:
        success:
          type: boolean
          description: Indicates whether the simulation succeeded.
          example: true
        message:
          type: string
          description: Simulation result message.
          example: Notification processed successfully.
        transactionId:
          type: string
          description: Transaction identifier linked to the simulation.
          example: rail-tx-123
    RailNotificationLog:
      type: object
      description: Stored rail notification log entry.
      properties:
        id:
          type: integer
          format: int64
          description: Notification log identifier.
          example: 1
        railTransactionId:
          type: string
          description: Rail transaction identifier.
          example: rail-tx-123
        partnerId:
          type: string
          description: Partner identifier.
          example: partner-id
        event:
          type: string
          description: Event name.
          example: transfer.completed
        mappedStatus:
          type: string
          description: Internal mapped status.
          example: COMPLETED
        accountId:
          type: string
          description: Related account identifier.
          example: 6c9083ce-b9d6-4415-8ad1-e32050fc8f93
        transactionType:
          type: string
          description: Transaction type.
          example: TRANSFER
        amountMinor:
          type: integer
          format: int64
          description: Amount in minor units.
          example: 60000
        currency:
          type: string
          description: Currency code.
          example: ZAR
        eventTimestamp:
          type: string
          format: date-time
          description: Event timestamp.
          example: '2026-03-06T08:00:00Z'
        status:
          type: string
          description: Notification processing status.
          example: PROCESSED
        attemptCount:
          type: integer
          format: int32
          description: Number of processing attempts.
          example: 1
        lastAttemptAt:
          type: string
          format: date-time
          description: Last processing attempt timestamp.
          example: '2026-03-06T08:00:01Z'
        nextAttemptAt:
          type:
            - string
            - 'null'
          format: date-time
          description: Next retry timestamp when applicable.
          example: '2026-03-06T08:05:00Z'
        lastError:
          type:
            - string
            - 'null'
          description: Last processing error when applicable.
          example: Timeout while acknowledging the rail message
    ConnectionStatus:
      type: object
      description: Status of the rail notification connection.
      required:
        - connected
        - status
        - serverInfo
        - subscribedSubject
        - totalNotificationsReceived
      properties:
        connected:
          type: boolean
          description: Indicates whether the notification service is connected.
          example: true
        status:
          type: string
          description: Human-readable connection status.
          example: CONNECTED
        serverInfo:
          type: string
          description: Connected server information.
          example: nats://localhost:4222
        subscribedSubject:
          type: string
          description: Subject currently subscribed to.
          example: rail.notifications
        totalNotificationsReceived:
          type: integer
          format: int64
          description: Total number of notifications received.
          example: 42
