openapi: 3.0.3
info:
  title: MEMEH RTPO API
  version: 1.0.0
  description: |
    Implemented client and lifecycle-event API for the MEMEH RTPO Request-to-Pay
    orchestration platform. HTTP 202 indicates orchestration and adapter
    handoff, not final payment completion. ACSC is successful payment
    completion; a later confirmed return is represented as RETURNED.
servers:
  - url: https://memeh.sps.bsl.datahub.gov.sl
    description: Production
  - url: https://sandbox.memeh.sps.bsl.datahub.gov.sl
    description: Sandbox
tags:
  - name: Health
  - name: Aliases
  - name: Payment Requests
  - name: Lifecycle
paths:
  /health:
    get:
      tags: [Health]
      summary: Check MEMEH RTPO liveness
      operationId: getHealth
      responses:
        "200":
          description: Core is running.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
  /api/v1/aliases/resolve:
    post:
      tags: [Aliases]
      summary: Resolve payer and payee financial-address options
      description: |
        Resolves both aliases through the Central Addressing Service and returns
        browser-safe masked options with opaque IDs. Payment creation performs
        a fresh trusted resolution before accepting the selected IDs.
      operationId: resolveAlias
      security:
        - clientBearer: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ResolveAliasRequest"
      responses:
        "200":
          description: Trusted browser-safe alias result.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ResolveAliasResponse"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "415":
          $ref: "#/components/responses/UnsupportedMediaType"
        "422":
          $ref: "#/components/responses/Unprocessable"
        "429":
          $ref: "#/components/responses/RateLimited"
        "503":
          $ref: "#/components/responses/Unavailable"
  /api/v1/payment-requests:
    post:
      tags: [Payment Requests]
      summary: Create and dispatch a payment request
      description: |
        Re-resolves payer and payee aliases through the Central Addressing
        Service, verifies the submitted opaque financial-address IDs, selects
        the approved payee-participant route, builds a canonical instruction,
        and dispatches it to the participant adapter.
      operationId: createPaymentRequest
      security:
        - clientBearer: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreatePaymentRequest"
      responses:
        "202":
          description: Request entered orchestration and immediate dispatch was attempted.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CreatePaymentAccepted"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "409":
          description: Idempotency key conflicts with another logical payload.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorEnvelope"
        "415":
          $ref: "#/components/responses/UnsupportedMediaType"
        "422":
          $ref: "#/components/responses/Unprocessable"
        "429":
          $ref: "#/components/responses/RateLimited"
        "502":
          description: A trusted dependency returned an invalid response or route configuration.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorEnvelope"
        "503":
          $ref: "#/components/responses/Unavailable"
  /api/v1/payment-requests/{id}:
    parameters:
      - $ref: "#/components/parameters/RequestId"
    get:
      tags: [Payment Requests]
      summary: Get current payment-request state
      operationId: getPaymentRequest
      security:
        - clientBearer: []
      responses:
        "200":
          description: Latest known state.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PaymentRequestStatus"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "429":
          $ref: "#/components/responses/RateLimited"
  /api/v1/payment-requests/{id}/events:
    parameters:
      - $ref: "#/components/parameters/RequestId"
    get:
      tags: [Payment Requests]
      summary: Get append-only payment-request event history
      operationId: getPaymentRequestEvents
      security:
        - clientBearer: []
      responses:
        "200":
          description: Ordered lifecycle event records.
          content:
            application/json:
              schema:
                type: object
                required: [events]
                properties:
                  events:
                    type: array
                    items:
                      $ref: "#/components/schemas/StatusEvent"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "429":
          $ref: "#/components/responses/RateLimited"
components:
  securitySchemes:
    clientBearer:
      type: http
      scheme: bearer
      bearerFormat: API key
      description: MEMEH_CORE_API_KEY
  parameters:
    RequestId:
      name: id
      in: path
      required: true
      description: MEMEH RTPO request UUID returned by payment creation.
      schema:
        type: string
        format: uuid
  schemas:
    ResolveAliasRequest:
      type: object
      required: [payer_alias, payee_alias, amount, currency, reference]
      properties:
        payer_alias:
          type: string
        payee_alias:
          type: string
        amount:
          type: string
          example: "250.00"
        currency:
          type: string
          example: SLE
        reference:
          type: string
    FinancialAddressSummary:
      type: object
      required: [id, label, masked, default, servicer_id, servicer_id_type, status]
      properties:
        id:
          type: string
        label:
          type: string
        masked:
          type: string
        default:
          type: boolean
        servicer_id:
          type: string
        servicer_id_type:
          type: string
        status:
          type: string
    ResolvedPartySummary:
      type: object
      required: [alias, alias_type, status, finaddresses]
      properties:
        alias:
          type: string
        alias_type:
          type: string
        status:
          type: string
        finaddresses:
          type: array
          items:
            $ref: "#/components/schemas/FinancialAddressSummary"
    ResolveAliasResponse:
      type: object
      required: [verified, resolution_id, source, payer, payee]
      properties:
        verified:
          type: boolean
        resolution_id:
          type: string
        source:
          type: string
        expires_at:
          type: string
          format: date-time
        payer:
          $ref: "#/components/schemas/ResolvedPartySummary"
        payee:
          $ref: "#/components/schemas/ResolvedPartySummary"
    CreatePaymentRequest:
      type: object
      required:
        - idempotency_key
        - resolution_id
        - payer_finaddress_id
        - payee_finaddress_id
        - payer_alias
        - payee_alias
        - merchant_id
        - amount
        - currency
        - reference
      properties:
        idempotency_key:
          type: string
        resolution_id:
          type: string
          description: Opaque resolution ID returned by the required resolve call.
        payer_finaddress_id:
          type: string
          description: Opaque active payer option selected from payer.finaddresses.
        payee_finaddress_id:
          type: string
          description: Opaque approved merchant option selected from payee.finaddresses.
        payer_alias:
          type: string
        payee_alias:
          type: string
        merchant_id:
          type: string
        amount:
          type: string
          example: "250.00"
        currency:
          type: string
          example: SLE
        reference:
          type: string
        description:
          type: string
    CreatePaymentAccepted:
      type: object
      required: [request_id, status, normalized_aliases, inferred_types, dispatch]
      properties:
        request_id:
          type: string
          format: uuid
        status:
          $ref: "#/components/schemas/LifecycleStatus"
        normalized_aliases:
          type: object
          additionalProperties:
            type: string
        inferred_types:
          type: object
          additionalProperties:
            type: string
        dispatch:
          type: object
          required: [status]
          properties:
            status:
              type: string
            http_status:
              type: integer
    PaymentRequestStatus:
      type: object
      required: [request_id, status, amount, currency, reference, created_at, updated_at]
      properties:
        request_id:
          type: string
          format: uuid
        status:
          $ref: "#/components/schemas/LifecycleStatus"
        amount:
          type: string
        currency:
          type: string
        reference:
          type: string
        resolution_id:
          type: string
        participant:
          type: string
        dispatch_http_status:
          type: integer
        dispatch_message:
          type: string
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
    StatusEvent:
      type: object
      required: [id, request_id, event_type, status, created_at]
      properties:
        id:
          type: string
        request_id:
          type: string
        instruction_id:
          type: string
        event_type:
          type: string
        status:
          $ref: "#/components/schemas/LifecycleStatus"
        message:
          type: string
        created_at:
          type: string
          format: date-time
    LifecycleStatus:
      type: string
      enum:
        - RECEIVED
        - ROUTABLE
        - DISPATCHED
        - PDNG
        - RCVD
        - ACSP
        - ACSC
        - RETURNED
        - RJCT
        - CANC
        - FAILED
    ErrorEnvelope:
      type: object
      required: [error]
      properties:
        error:
          type: object
          required: [code, message]
          properties:
            code:
              type: string
            message:
              type: string
  responses:
    BadRequest:
      description: Request body or identifier is invalid.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorEnvelope"
    Unauthorized:
      description: Authentication is missing or invalid.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorEnvelope"
    NotFound:
      description: Alias or payment request was not found.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorEnvelope"
    UnsupportedMediaType:
      description: Content-Type must be application/json.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorEnvelope"
    Unprocessable:
      description: The request failed business validation or lifecycle processing.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorEnvelope"
    RateLimited:
      description: Too many requests.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorEnvelope"
    Unavailable:
      description: A required trusted dependency is unavailable.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorEnvelope"
