openapi: 3.0.3
info:
  title: Flinks EFT API (V2)
  description: |
    Flinks EFT (Electronic Funds Transfer) API. **V2, session-based**.

    V2 replaces V1's endpoint-by-endpoint integration with a single session-based flow built on the
    shared `/api/v2/sessions` model. You create one session (`type = EFT`,
    `options.guarantee.enable = false`), launch the hosted Flinks Pay flow, and monitor the session
    to completion. This is the **Regular EFT path**; guarantee features are part of the GEFT product.

    ## Authentication
    All endpoints authenticate using a Bearer token obtained from the `/api/v1/authorize` endpoint
    (OAuth 2.0 Client Credentials). The session `status` endpoint requires only the `sessionId`.

    For more information, visit: https://docs.flinks.com
  version: 2.0.0
  contact:
    name: Flinks Support
    url: https://www.flinks.com/contact/sales
  termsOfService: https://www.flinks.com

tags:
  - name: Sessions
    description: Create, monitor, and manage EFT payment sessions

servers:
  - url: https://www.{baseurl}.com
    description: Flinks Pay Production
    variables:
      baseurl:
        default: "{baseurl}"
        description: The base URI for the environment (e.g. flinks)

paths:
  /api/v2/sessions:
    post:
      tags:
        - Sessions
      summary: Initiate EFT Session
      description: |
        Create a new EFT session and obtain a `sessionId` for launching the user payment flow.
        For regular EFT, set `type` to `EFT` and `options.guarantee.enable` to `false`.

        Funds settle to your client's configured bank account. `payee` is not supported for EFT.
        Requires the `RegularEft` feature to be enabled on your client (otherwise `403`).
      operationId: initiateEftSession
      parameters:
        - name: Authorization
          in: header
          required: true
          description: Bearer token received from the /authorize endpoint.
          schema:
            type: string
            pattern: "^Bearer .+"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/InitiateSessionRequest'
            example:
              referenceId: "USER12345"
              type: "EFT"
              direction: "DEBIT"
              currency: "CAD"
              amount: 100.00
              options:
                guarantee:
                  enable: false
                notificationPreferences:
                  language: "EN"
                showConsentScreen: false
              payor:
                firstName: "Sara"
                lastName: "Ahmad"
                email: "sara.ahmad@example.com"
                address:
                  addressLine1: "123 Street"
                  city: "Toronto"
                  postalCode: "M5H2N2"
                  province: "ON"
                  country: "CA"
      responses:
        "201":
          description: Session created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/InitiateSessionSetupResponse'
              example:
                sessionId: "850750a4-3021-4061-ac03-a8d873aa4179"
                referenceId: "USER12345"
        "400":
          description: Bad Request. Validation error (e.g. direction not DEBIT, missing payor fields, payee present, amount out of range)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetails'
              example:
                type: "https://tools.ietf.org/html/rfc7231#section-6.5.1"
                title: "Bad Request"
                status: 400
                detail: "Payee is not supported for EFT"
        "401":
          description: Unauthorized. Invalid or missing Bearer token
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetails'
        "403":
          description: Forbidden. Client does not have the RegularEft feature enabled
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetails'

  /api/v2/sessions/{sessionId}/cancel:
    post:
      tags:
        - Sessions
      summary: Cancel EFT Session
      description: |
        Immediately terminate an active EFT session so the user can no longer access or resume the
        flow. If the session is already in a terminal state (Completed, Cancelled, Expired), the
        request is rejected.
      operationId: cancelEftSession
      parameters:
        - name: sessionId
          in: path
          required: true
          description: The session identifier returned when the session was created.
          schema:
            type: string
            format: uuid
          example: "850750a4-3021-4061-ac03-a8d873aa4179"
        - name: Authorization
          in: header
          required: true
          description: Bearer token received from the /authorize endpoint.
          schema:
            type: string
            pattern: "^Bearer .+"
      responses:
        "200":
          description: Session cancelled successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CancelSessionSetupResponse'
              example:
                sessionId: "850750a4-3021-4061-ac03-a8d873aa4179"
                referenceId: "USER12345"
                status: "Cancelled"
                statusDetails: "EFT0501"
        "400":
          description: Bad Request. Session cannot be cancelled (already terminal)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetails'
              example:
                type: "https://tools.ietf.org/html/rfc7231#section-6.5.1"
                title: "Bad Request"
                status: 400
                detail: "Session 850750a4-3021-4061-ac03-a8d873aa4179 cannot be Cancelled"
        "401":
          description: Unauthorized. Invalid or missing Bearer token
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetails'
        "404":
          description: Session not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetails'

  /api/v2/sessions/{sessionId}/details:
    get:
      tags:
        - Sessions
      summary: Get EFT Session Details
      description: |
        Retrieve comprehensive session information including verified payor account details (once
        available). Payor account details are populated only after the session passes the
        `Initiated` stage. `payee` is always `null`. Funds settle to your configured account.
      operationId: getEftSessionDetails
      parameters:
        - name: sessionId
          in: path
          required: true
          description: The session identifier returned when the session was created.
          schema:
            type: string
            format: uuid
          example: "850750a4-3021-4061-ac03-a8d873aa4179"
        - name: Authorization
          in: header
          required: true
          description: Bearer token received from the /authorize endpoint.
          schema:
            type: string
            pattern: "^Bearer .+"
      responses:
        "200":
          description: Session details retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SessionSetupResponse'
              example:
                sessionId: "850750a4-3021-4061-ac03-a8d873aa4179"
                status: "Completed"
                step:
                  current: "Complete"
                  aggregationRequestId: "c1a2b3d4-e5f6-7890-abcd-ef1234567890"
                  padId: "d4c3b2a1-f6e5-0987-dcba-fe7654321098"
                referenceId: "USER12345"
                amount: 100.00
                type: "EFT"
                direction: "DEBIT"
                currency: "CAD"
                options:
                  guarantee:
                    enable: false
                  showConsentScreen: false
                  limits:
                    minimumAmount: 50.00
                    maximumAmount: 10000.00
                  amountModification: true
                  redirectPreferences:
                    mode: "JsEvents"
                payor:
                  email: "sara.ahmad@example.com"
                  firstName: "Sara"
                  lastName: "Ahmad"
                  account:
                    institutionCode: "003"
                    transitNumber: "12345"
                    accountNumber: "****1234"
                    accountLabel: "Checking (****1234)"
                  address:
                    addressLine1: "123 Street"
                    city: "Toronto"
                    province: "ON"
                    country: "CA"
                    postalCode: "M5H2N2"
                userDetails:
                  matchingPerformed: true
                  nameMatch: 95
                createdAt: "2026-06-04T14:30:00Z"
        "400":
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetails'
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetails'
        "404":
          description: Session not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetails'

security:
  - BearerAuth: []

components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: Bearer token obtained from the /api/v1/authorize endpoint.
  schemas:
    InitiateSessionRequest:
      type: object
      required:
        - type
        - direction
        - payor
        - options
      properties:
        type:
          type: string
          enum: ["EFT"]
          description: The payment rail. Must be `EFT` for this API.
          example: "EFT"
        direction:
          type: string
          enum: ["DEBIT"]
          description: Payment direction. Only `DEBIT` is supported for EFT.
          example: "DEBIT"
        currency:
          type: string
          enum: ["CAD"]
          default: "CAD"
          description: Currency code. Only `CAD` is supported (defaults to `CAD` if omitted).
          example: "CAD"
        amount:
          type: number
          format: double
          minimum: 0.01
          nullable: true
          description: |
            Payment amount, up to 2 decimal places. Optional. If omitted, the user enters the
            amount in the hosted flow. When provided, it must fall within the client's configured
            minimum/maximum EFT amount.
          example: 100.00
        referenceId:
          type: string
          maxLength: 36
          pattern: "^[a-zA-Z0-9\\-]{1,36}$"
          nullable: true
          description: |
            Your internal reference identifier (strongly recommended). 1 to 36 alphanumeric characters
            or hyphens. Flows through as the EFT cross-reference number and appears in
            reconciliation files.
          example: "USER12345"
        options:
          $ref: '#/components/schemas/SessionSetupOptionModel'
        payor:
          $ref: '#/components/schemas/PartyInfoRequest'

    PartyInfoRequest:
      type: object
      required:
        - firstName
        - lastName
        - email
      description: |
        The end user being debited. `firstName`, `lastName`, and `email` are required for regular
        EFT. `address` is optional for regular EFT (it is required only when a guarantee is enabled).
      properties:
        firstName:
          type: string
          description: Payor's first name. Used for identity matching against the bank account.
          example: "Sara"
        lastName:
          type: string
          description: Payor's last name. Used for identity matching against the bank account.
          example: "Ahmad"
        email:
          type: string
          format: email
          description: Payor's email address. Used for notifications.
          example: "sara.ahmad@example.com"
        middleName:
          type: string
          nullable: true
          description: Payor's middle name (optional).
        occupation:
          type: string
          nullable: true
          description: Payor's occupation (optional).
        birthDate:
          type: string
          nullable: true
          description: "Payor's birth date in `yy-MM-dd` format (optional)."
          example: "90-05-21"
        address:
          allOf:
            - $ref: '#/components/schemas/BaseAddressModel'
          nullable: true
          description: Payor address (optional for regular EFT). If provided, address line 1, city, province, postal code, and country are required.

    BaseAddressModel:
      type: object
      properties:
        addressLine1:
          type: string
          example: "123 Street"
        addressLine2:
          type: string
          nullable: true
        unit:
          type: string
          nullable: true
        city:
          type: string
          example: "Toronto"
        province:
          type: string
          description: 2-character provincial code (e.g. ON, QC).
          example: "ON"
        country:
          type: string
          description: 2-character ISO country code. Only `CA` is supported.
          example: "CA"
        postalCode:
          type: string
          description: Postal code, no spaces (e.g. M5H2N2).
          example: "M5H2N2"

    SessionSetupOptionModel:
      type: object
      required:
        - guarantee
      properties:
        guarantee:
          $ref: '#/components/schemas/GuaranteeOptions'
        notificationPreferences:
          $ref: '#/components/schemas/NotificationPreferencesOptions'
        showConsentScreen:
          type: boolean
          nullable: true
          description: Whether to display the Flinks consent screen.
          example: false
        limits:
          $ref: '#/components/schemas/SessionLimitsModel'
        amountModification:
          type: boolean
          description: Whether the user can modify the amount in the hosted flow.
        redirectPreferences:
          $ref: '#/components/schemas/RedirectPreferencesResponse'

    GuaranteeOptions:
      type: object
      required:
        - enable
      properties:
        enable:
          type: boolean
          description: Must be `false` for regular EFT. Set to `true` only for Guaranteed EFT (GEFT).
          example: false

    NotificationPreferencesOptions:
      type: object
      properties:
        language:
          type: string
          enum: ["EN", "FR"]
          default: "EN"
          description: Language preference for notifications.
          example: "EN"

    SessionLimitsModel:
      type: object
      properties:
        minimumAmount:
          type: number
          format: double
          nullable: true
          description: Minimum allowed payment amount.
          example: 50.00
        maximumAmount:
          type: number
          format: double
          nullable: true
          description: Maximum allowed payment amount.
          example: 10000.00

    RedirectPreferencesResponse:
      type: object
      properties:
        mode:
          $ref: '#/components/schemas/RedirectPreferencesMode'
        urlSuccess:
          type: string
          format: uri
          nullable: true
        urlExit:
          type: string
          format: uri
          nullable: true

    RedirectPreferencesMode:
      type: string
      enum:
        - JsEvents
        - RedirectUri
      description: How the hosted flow returns control when the session completes.

    InitiateSessionSetupResponse:
      type: object
      properties:
        sessionId:
          type: string
          format: uuid
          description: Unique session identifier. Use it to launch the hosted flow and monitor the session.
          example: "850750a4-3021-4061-ac03-a8d873aa4179"
        referenceId:
          type: string
          nullable: true
          description: The reference ID you supplied (if any).
          example: "USER12345"

    CancelSessionSetupResponse:
      type: object
      properties:
        sessionId:
          type: string
          format: uuid
          example: "850750a4-3021-4061-ac03-a8d873aa4179"
        referenceId:
          type: string
          nullable: true
          example: "USER12345"
        status:
          $ref: '#/components/schemas/SessionStatus'
        statusDetails:
          type: string
          nullable: true
          description: Status detail code. `EFT0501` indicates the session was cancelled by API request.
          example: "EFT0501"

    SessionSetupResponse:
      type: object
      properties:
        sessionId:
          type: string
          format: uuid
          example: "850750a4-3021-4061-ac03-a8d873aa4179"
        status:
          $ref: '#/components/schemas/SessionStatus'
        step:
          $ref: '#/components/schemas/CurrentStep'
        referenceId:
          type: string
          nullable: true
          example: "USER12345"
        amount:
          type: number
          format: double
          nullable: true
          example: 100.00
        type:
          type: string
          enum: ["EFT"]
          example: "EFT"
        direction:
          type: string
          enum: ["DEBIT"]
          example: "DEBIT"
        currency:
          type: string
          enum: ["CAD"]
          example: "CAD"
        options:
          $ref: '#/components/schemas/SessionSetupOptionModel'
        payor:
          $ref: '#/components/schemas/PartyModel'
        payee:
          allOf:
            - $ref: '#/components/schemas/PartyModel'
          nullable: true
          description: Always `null` for EFT. Funds settle to your configured account.
        userDetails:
          $ref: '#/components/schemas/UserDetails'
        schedule:
          $ref: '#/components/schemas/SessionScheduleModel'
        createdAt:
          type: string
          format: date-time
          example: "2026-06-04T14:30:00Z"

    PartyModel:
      type: object
      properties:
        email:
          type: string
          nullable: true
          example: "sara.ahmad@example.com"
        firstName:
          type: string
          nullable: true
          example: "Sara"
        lastName:
          type: string
          nullable: true
          example: "Ahmad"
        middleName:
          type: string
          nullable: true
        account:
          allOf:
            - $ref: '#/components/schemas/AccountInfoModel'
          nullable: true
          description: Verified bank account, populated after user authentication. `null` while the session is still `Initiated`.
        address:
          $ref: '#/components/schemas/BaseAddressModel'

    AccountInfoModel:
      type: object
      properties:
        institutionCode:
          type: string
          nullable: true
          example: "003"
        transitNumber:
          type: string
          nullable: true
          example: "12345"
        accountNumber:
          type: string
          nullable: true
          description: Masked, showing only the last 4 digits.
          example: "****1234"
        accountLabel:
          type: string
          nullable: true
          example: "Checking (****1234)"
        availableBalance:
          type: number
          format: double
          nullable: true

    CurrentStep:
      type: object
      properties:
        current:
          $ref: '#/components/schemas/SessionStep'
        aggregationRequestId:
          type: string
          format: uuid
          nullable: true
        padId:
          type: string
          format: uuid
          nullable: true

    UserDetails:
      type: object
      properties:
        matchingPerformed:
          type: boolean
          description: Whether identity matching was performed.
          example: true
        nameMatch:
          type: number
          format: double
          description: Name matching score (0 to 100).
          example: 95

    SessionScheduleModel:
      type: object
      properties:
        transactions:
          type: array
          nullable: true
          items:
            $ref: '#/components/schemas/SessionTransactionModel'

    SessionTransactionModel:
      type: object
      properties:
        id:
          type: string
          format: uuid
        status:
          type: string
          nullable: true

    SessionStatus:
      type: string
      enum:
        - Initiated
        - Failed
        - Cancelled
        - Expired
        - Completed
      description: Current session status.

    SessionStep:
      type: string
      enum:
        - Start
        - Consent
        - BankSelection
        - BankConnection
        - AccountSelection
        - AmountSelection
        - Review
        - Pad
        - Complete
      description: Current step in the session flow.

    ProblemDetails:
      type: object
      properties:
        type:
          type: string
          nullable: true
          example: "https://tools.ietf.org/html/rfc7231#section-6.5.1"
        title:
          type: string
          nullable: true
          example: "Bad Request"
        status:
          type: integer
          format: int32
          nullable: true
          example: 400
        detail:
          type: string
          nullable: true
        instance:
          type: string
          nullable: true
