openapi: 3.0.3
info:
  title: PA+ SaaS Operations API
  version: 1.0.0
  description: |
    Customer-facing API for managing cases.
    Only available to SaaS customers.
    Unauthorized or invalid access returns standard HTTP errors.
  x-infinx-audience: EXTERNAL
  x-repository-url: https://bitbucket.org/rcmplatform/patient_access_plus_integration

servers:
  - url: https://testipa.infinx.com/papopsmanager/v2
  - url: https://ipas.infinx.com/papopsmanager/v2

tags:
  - name: Authentication
    description: Endpoints for authentication (OAuth token generation)
  - name: SaaS Cases
    description: SaaS Operations API endpoints

x-tagGroups:
  - name: Authentication
    tags:
      - Authentication
  - name: SaaS Cases
    tags:
      - SaaS Cases

paths:
  /papusersrvc/oauth/token:
    post:
      tags:
        - Authentication
      summary: Obtain OAuth Token
      description: Retrieve an OAuth token using client credentials.
      operationId: getToken
      servers:
        - url: https://testipa.infinx.com
        - url: https://ipas.infinx.com
      parameters:
        - name: content-type
          in: header
          required: true
          schema:
            type: string
            enum:
              - application/x-www-form-urlencoded
          description: Content type of the request
          example: application/x-www-form-urlencoded
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              properties:
                grant_type:
                  type: string
                  enum:
                    - client_credentials
                  description: Value must be 'client_credentials'
                  example: client_credentials
                client_id:
                  type: string
                  description: Client's ID provided by IPA
                  example: pap-contract-srvc-example
                client_secret:
                  type: string
                  description: Client's secret key provided by IPA
                  example: efd605a5-91cb-413c-95ba-example
                ifx-security-realm:
                  type: string
                  description: IPA Contract realm code
                  example: Infinx
              required:
                - grant_type
                - client_id
                - client_secret
                - ifx-security-realm
      responses:
        "200":
          description: Successful token retrieval
          content:
            application/json:
              schema:
                type: object
                properties:
                  access_token:
                    type: string
                  expires_in:
                    type: integer
                  refresh_expires_in:
                    type: integer
                  refresh_token:
                    type: string
                  token_type:
                    type: string
                  not-before-policy:
                    type: integer
                  session_state:
                    type: string
                  scope:
                    type: string
        "400":
          $ref: "#/components/responses/Auth400Response"
        "401":
          $ref: "#/components/responses/Auth401Response"
        "403":
          $ref: "#/components/responses/Auth403Response"
        "404":
          $ref: "#/components/responses/Auth404Response"
        "500":
          $ref: "#/components/responses/Auth500Response"

  /cases:
    get:
      summary: List cases
      tags:
        - SaaS Cases
      description: Fetch a paginated list of cases filtered by assignee ID with security headers.
      parameters:
        - name: assigneeId
          in: query
          required: false
          schema:
            type: integer
          example: 1103
        - name: assigneeName
          in: query
          required: false
          schema:
            type: string
            example: pa.agent
        - name: pageNumber
          in: query
          schema:
            type: integer
            minimum: 1
          example: 1
        - name: pageSize
          in: query
          schema:
            type: integer
            minimum: 1
          example: 10
        - name: sortBy
          in: query
          schema:
            type: string
          example: id
        - name: sortOrder
          in: query
          schema:
            type: string
            enum:
              - asc
              - desc
          example: desc
        - name: created_at
          in: query
          required: false
          description: |
            Filter cases by creation datetime. Supports datetime filtering with operators.
            **Type:** DateTime (includes date and time)
            **Format:** `operator:YYYY-MM-DDTHH:mm:ss` or `operator:YYYY-MM-DD` (time defaults to 00:00:00)
            **Timezone:** All datetime values must be in UTC zone.
            **Supported Operators:**
            - `gte` - Greater than or equal to
            - `gt` - Greater than
            - `lte` - Less than or equal to
            - `lt` - Less than
            - `eq` - Equal to
            **Examples:**
            - `created_at=gte:2025-01-01T00:00:00&created_at=lt:2025-02-01T00:00:00` - Cases created in January 2025
            - `created_at=gte:2025-01-01&created_at=lt:2025-02-01` - Same as above (time defaults to 00:00:00)
            - `created_at=eq:2025-01-15T10:30:00` - Cases created exactly at this datetime
            **Note:** This parameter can be repeated multiple times to combine operators.
          schema:
            type: array
            items:
              type: string
              pattern: "^(gte|gt|lte|lt|eq):\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2})?$"
          style: form
          explode: true
          example:
            - gte:2025-01-01T00:00:00
            - lt:2025-02-01T00:00:00
        - name: last_worked
          in: query
          required: false
          description: |
            Filter cases by last worked datetime. Supports datetime filtering with operators.
            **Type:** DateTime (includes date and time)
            **Format:** `operator:YYYY-MM-DDTHH:mm:ss` or `operator:YYYY-MM-DD` (time defaults to 00:00:00)
            **Timezone:** All datetime values must be in UTC zone.
            **Supported Operators:**
            - `gte` - Greater than or equal to
            - `gt` - Greater than
            - `lte` - Less than or equal to
            - `lt` - Less than
            - `eq` - Equal to
            **Examples:**
            - `last_worked=gte:2025-01-01T00:00:00&last_worked=lt:2025-02-01T00:00:00` - Cases last worked in January 2025
            - `last_worked=gte:2025-01-01&last_worked=lt:2025-02-01` - Same as above (time defaults to 00:00:00)
            - `last_worked=eq:2025-01-15T10:30:00` - Cases last worked exactly at this datetime
            **Note:** This parameter can be repeated multiple times to combine operators.
          schema:
            type: array
            items:
              type: string
              pattern: "^(gte|gt|lte|lt|eq):\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2})?$"
          style: form
          explode: true
          example:
            - gte:2025-01-01T00:00:00
            - lt:2025-02-01T00:00:00
        - name: followup_date
          in: query
          required: false
          description: |
            Filter cases by follow-up date. Supports date-only filtering with operators.
            **Type:** Date only (no time component)
            **Format:** `operator:YYYY-MM-DD`
            **Timezone:** All date values must be in UTC zone.
            **Supported Operators:**
            - `gte` - Greater than or equal to
            - `gt` - Greater than
            - `lte` - Less than or equal to
            - `lt` - Less than
            - `eq` - Equal to
            **Examples:**
            - `followup_date=gte:2025-01-01&followup_date=lt:2025-02-01` - Cases with follow-up date in January 2025
            - `followup_date=eq:2025-01-15` - Cases with follow-up date exactly on January 15, 2025
            - `followup_date=gte:2025-01-01` - Cases with follow-up date on or after January 1, 2025
            **Note:** This parameter can be repeated multiple times to combine operators. Only date values are accepted (no time component).
          schema:
            type: array
            items:
              type: string
              format: date
              pattern: "^(gte|gt|lte|lt|eq):\\d{4}-\\d{2}-\\d{2}$"
          style: form
          explode: true
          example:
            - gte:2025-01-01
            - lt:2025-02-01
        - name: include_finalized_cases
          in: query
          required: false
          description: |
            Controls whether cases in the System Finalized Queue are included in search results.
            When `false` (default), these cases are excluded.
            When `true`, these cases are included.
          schema:
            type: boolean
            default: false
          example: false
        - $ref: "#/components/parameters/AuthorizationHeader"
        - $ref: "#/components/parameters/IfxSecurityRealmHeader"
        - $ref: "#/components/parameters/ContentTypeHeader"
      responses:
        "200":
          description: Successful response, returns cases page
          content:
            application/json:
              schema:
                type: object
                properties:
                  pageSize:
                    type: integer
                  pageNumber:
                    type: integer
                  recordCount:
                    type: integer
                  sortBy:
                    type: string
                  sortOrder:
                    type: string
                  results:
                    type: array
                    items:
                      $ref: "#/components/schemas/CaseDetail"
        "400":
          description: Bad request - missing or invalid parameters
        "401":
          description: Unauthorized - invalid or missing headers
        "500":
          description: Internal server error

  /cases/{caseNumber}:
    get:
      summary: Get case details by caseNumber
      tags:
        - SaaS Cases
      description: Retrieve case details by caseNumber.
      operationId: getCaseDetails
      parameters:
        - name: caseNumber
          in: path
          required: true
          schema:
            type: string
          example: Sh-Tenant1-14658
        - $ref: "#/components/parameters/AuthorizationHeader"
        - $ref: "#/components/parameters/IfxSecurityRealmHeader"
      responses:
        "200":
          description: Case details retrieved successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CaseDetail"
        "400":
          description: Bad Request - Invalid input
        "401":
          description: Unauthorized
        "403":
          description: Forbidden
        "404":
          description: Case not found
        "500":
          description: Internal Server Error
    patch:
      summary: Update case details
      tags:
        - SaaS Cases
      description: Update case details.
      operationId: updateCaseDetails
      parameters:
        - name: caseNumber
          in: path
          required: true
          schema:
            type: string
          example: Sh-Tenant1-14658
        - $ref: "#/components/parameters/AuthorizationHeader"
        - $ref: "#/components/parameters/IfxSecurityRealmHeader"
        - $ref: "#/components/parameters/IfxUserNameHeader"
        - $ref: "#/components/parameters/ContentTypeHeader"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CaseDetail"
            encoding:
              caseDetails:
                contentType: application/json
      responses:
        "200":
          description: Case details updated successfully
        "400":
          description: Bad Request - Invalid input
        "401":
          description: Unauthorized
        "403":
          description: Forbidden
        "404":
          description: Case not found
        "500":
          description: Internal Server Error

  /cases/{caseNumber}/statuses:
    post:
      summary: Update case status.
      tags:
        - SaaS Cases
      description: |
        Update case status. To include attachments, send as multipart/form-data with a `files` part
      operationId: updateCaseStatus
      parameters:
        - name: caseNumber
          in: path
          required: true
          schema:
            type: string
          example: Sh-Tenant1-14658
        - $ref: "#/components/parameters/AuthorizationHeader"
        - $ref: "#/components/parameters/IfxSecurityRealmHeader"
        - $ref: "#/components/parameters/IfxUserNameHeader"
        - $ref: "#/components/parameters/ContentTypeHeaderWithDescription"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CaseDetail"
          multipart/form-data:
            schema:
              type: object
              required:
                - request
              properties:
                request:
                  $ref: "#/components/schemas/CaseDetail"
                files:
                  type: string
                  format: binary
                  description:
                    Optional CSV or other file attachment. **File requirements:** - Filename should
                    contain only ASCII characters and symbols, with **only one dot (.)** for the
                    extension. - **Allowed file types:** pdf, doc, docs, docx, csv, htm, html, bmp,
                    tiff, tif, jpg, jpeg, png. - **File size:** must be **greater than 0 MB** and
                    **less than 25 MB** (non-empty).
            encoding:
              caseDetails:
                contentType: application/json
      responses:
        "200":
          description: Case updated successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CaseDetail"
        "400":
          description: Bad Request - Invalid input
        "401":
          description: Unauthorized
        "403":
          description: Forbidden
        "404":
          description: Case not found
        "500":
          description: Internal Server Error

components:
  parameters:
    AuthorizationHeader:
      name: Authorization
      in: header
      required: true
      schema:
        type: string
        format: bearer
      example: Bearer <access_token>
      description: Bearer token for authentication.

    IfxSecurityRealmHeader:
      name: Ifx-Security-Realm
      in: header
      required: true
      schema:
        type: string
      example: infinx
      description: Security realm key for identifying the tenant.

    IfxUserNameHeader:
      name: ifx-user-name
      in: header
      required: true
      schema:
        type: string
      example: pa.agent
      description: User name for auditing or tracking purposes.

    ContentTypeHeader:
      name: Content-Type
      in: header
      required: true
      schema:
        type: string
      example: application/json
      description: Content type of the request payload.

    ContentTypeHeaderWithDescription:
      name: Content-Type
      in: header
      required: true
      schema:
        type: string
      example: application/json
      description:
        Content type of the request payload.Include **only** if sending JSON payloads.Omit when
        sending multipart/form-data requests.

    CaseNumberPath:
      name: caseNumber
      in: path
      required: true
      schema:
        type: string
      example: Sh-Tenant1-14658
      description: Case number identifier.

  responses:
    Auth400Response:
      description: Bad Request - Invalid inputs for OAuth
    Auth401Response:
      description: Unauthorized - Invalid client credentials
    Auth403Response:
      description: Forbidden - Access denied
    Auth404Response:
      description: Not Found - Invalid token endpoint
    Auth500Response:
      description: Internal Server Error - Token service failure

  schemas:
    CaseDetail:
      type: object
      properties:
        caseNumber:
          type: string
          description: Infinx identifier
        accessionNumber:
          type: string
          description: Customer identifier
        executionMode:
          type: string
          nullable: true
          enum:
            - AUTOMATION_ONLY
            - HITL
        tenantKey:
          type: string
        contractKey:
          type: string
        product:
          type: string
        outReachAttemptMessage:
          type: string
        outReachAttemptMessageOther:
          type: string
        status:
          $ref: "#/components/schemas/Status"
        followupDate:
          type: string
          format: date
        dateOfServiceStartDate:
          type: string
          format: date
        dateOfServiceEndDate:
          type: string
          format: date
        priority:
          type: string
        epicOrderId:
          type: string
        patient:
          $ref: "#/components/schemas/Patient"
        renderingPhysician:
          $ref: "#/components/schemas/Provider"
        renderingFacility:
          $ref: "#/components/schemas/Facility"
        orderingPhysician:
          $ref: "#/components/schemas/Provider"
        orderingFacility:
          $ref: "#/components/schemas/Facility"
        diagnoses:
          type: array
          items:
            $ref: "#/components/schemas/Diagnoses"
        payors:
          type: array
          items:
            $ref: "#/components/schemas/Payor"
        procedures:
          type: array
          items:
            $ref: "#/components/schemas/Procedure"
        attachments:
          type: array
          items:
            $ref: "#/components/schemas/Attachment"
        comments:
          type: array
          items:
            $ref: "#/components/schemas/Comment"
        assignments:
          type: array
          items:
            $ref: "#/components/schemas/Assignment"
        customFields:
          $ref: "#/components/schemas/customFields"

    CaseStatusUpdate:
      type: object
      properties:
        status:
          type: string
        subStatus:
          type: string
        comment:
          type: string

    CaseManualUpdate:
      type: object
      properties:
        status:
          type: string
        subStatus:
          type: string
          example: Info Requested
        reasonCode:
          type: string
          example: AUTO_FAILED_ELIGIBILITY_CHECK
        comment:
          type: string
          example: Unable to verify eligibility; requires manual review.

    Attachment:
      type: object
      properties:
        id:
          type: integer
        attachmentName:
          type: string
        mimeType:
          type: string
        fileSize:
          type: integer

    Status:
      type: object
      properties:
        status:
          type: string
        subStatus:
          type: string
        statusReason:
          type: string
        statusReasonOther:
          type: string
        updatedAt:
          type: string
          format: date-time
          description: Date and time the status was updated in ISO 8601 format, UTC timezone.
          example: 2025-01-01T00:00:00Z
        decisionDate:
          type: string
          format: date
          description: Date and time the decision was made in ISO 8601 format, UTC timezone.
          example: 2025-01-01T00:00:00Z

    Patient:
      type: object
      properties:
        firstName:
          type: string
        middleName:
          type: string
          nullable: true
        lastName:
          type: string
        dateOfBirth:
          type: string
          format: date
        gender:
          type: string
          enum:
            - Female
            - Male
            - Other
            - Unknown
        mrn:
          type: string
        phone:
          type: string
        address:
          type: string
        city:
          type: string
        state:
          type: string
        zip:
          type: string
        notes:
          type: string

    BaseProvider:
      type: object
      properties:
        npi:
          type: string
        tin:
          type: string
        phone:
          type: string
        fax:
          type: string
        address:
          type: string
        city:
          type: string
        state:
          type: string
        zip:
          type: string
        taxonomyCode:
          type: string

    Provider:
      allOf:
        - $ref: "#/components/schemas/BaseProvider"
        - type: object
          properties:
            firstName:
              type: string
            lastName:
              type: string

    Facility:
      allOf:
        - $ref: "#/components/schemas/BaseProvider"
        - type: object
          properties:
            name:
              type: string

    Diagnoses:
      type: object
      properties:
        id:
          type: integer
        code:
          type: string
        description:
          type: string

    Payor:
      type: object
      properties:
        id:
          type: integer
        insuranceType:
          type: string
          enum:
            - PRIMARY
            - SECONDARY
        insuranceCustomerName:
          type: string
        insuranceName:
          type: string
        insuranceCode:
          type: string
        groupName:
          type: string
        groupNumber:
          type: string
        phone:
          type: string
        memberId:
          type: string
        caseReferenceNumber:
          type: string
        callReferenceNumber:
          type: string
        referral:
          $ref: "#/components/schemas/Referral"

    Referral:
      type: object
      description: |
        Referral information at the payor level.

        **Conditional required fields based on `referralStatus`:**
        - `Referral Approved`: **referralAuthorizationNumber**, **referralReferenceNumber**, **referralStartDate**, **referralEndDate** are required.
        - `Referral Denied`: **referralDenialReason**, **referralReferenceNumber** are required.
        - `No Referral Required`: **referralReferenceNumber** is required.
        - `Not Applicable`: no mandatory fields.
      properties:
        referralTpa:
          type: string
          example: "AIM"
        referralMode:
          type: string
          example: "Phone"
        referralStatus:
          type: string
          nullable: true
          enum:
            - Referral Approved
            - Referral Denied
            - No Referral Required
            - Not Applicable
          example: "Referral Approved"
        referralAuthorizationNumber:
          type: string
          nullable: true
          description: Required when referralStatus is `Referral Approved`.
          example: "RAN123"
        referralStartDate:
          type: string
          format: date
          nullable: true
          description: Required when referralStatus is `Referral Approved`.
          example: "2026-02-12"
        referralEndDate:
          type: string
          format: date
          nullable: true
          description: Required when referralStatus is `Referral Approved`.
          example: "2026-03-12"
        referralReferenceNumber:
          type: string
          nullable: true
          description: Required when referralStatus is `Referral Approved`, `Referral Denied`, or `No Referral Required`.
          example: "RRN123"
        referralDenialReason:
          type: string
          nullable: true
          description: Required when referralStatus is `Referral Denied`.
          example: null

    Procedure:
      type: object
      properties:
        id:
          type: integer
        cptCode:
          type: string
        description:
          type: string
        modifier:
          type: string
        serviceType:
          type: string
        placeOfService:
          type: string
        quantity:
          type: integer
        testName:
          type: string
        testCode:
          type: string
        payorStatus:
          type: array
          items:
            $ref: "#/components/schemas/PayorStatus"

    PayorStatus:
      type: object
      properties:
        id:
          type: integer
        insuranceCode:
          type: string
        mode:
          type: string
          description: Required when the case is not in Referral Required status.
        priorAuthEntity:
          type: string
          description: Required when the case is not in Referral Required status.
        priorAuthEntityOther:
          type: string
        status:
          type: string
        authorizationNumber:
          type: string
        effectiveDate:
          type: string
          format: date
        expiryDate:
          type: string
          format: date
        denialReason:
          type: string
        unitsAuthorized:
          type: string
        unitsAuthorizedType:
          type: string
        statusReason:
          type: string
        statusReasonOther:
          type: string
        caseReferenceNumber:
          type: string
        callReferenceNumber:
          type: string
        surveyLink:
          type: string

    customFields:
      type: object
      properties:
        customField1:
          type: string
          maxLength: 50
          description: Custom field 1.
          example: custom field1
        customField2:
          type: string
          maxLength: 50
          description: Custom field 2.
          example: custom field2

    Comment:
      type: object
      properties:
        createdAt:
          type: string
          format: date-time
          description: Date and time the comment was created in ISO 8601 format, UTC timezone.
          example: 2025-01-01T00:00:00Z
        createdById:
          description: Id of the user who created the comment
          type: integer
        createdByUsername:
          description: Username of the user who created the comment
          type: string
        assigneeId:
          deprecated: true
          description:
            User who created the comment. Deprecated, please use createdById. This field will be
            removed in a future version.
          type: integer
        comment:
          description: The actual comment text.
          type: string
          maxLength: 2048
          example: "Per portal, auth has been approved"

    Assignment:
      type: object
      properties:
        queueId:
          type: integer
        queueName:
          type: string
        queueType:
          type: string
          enum:
            - Audit Queue
            - Follow-up Queue
            - Outreach Queue
            - Manual Queue
        assignedToId:
          type: integer
        assignedToUsername:
          type: string
        assignedAt:
          type: string
          format: date-time
          description: Date and time the assignment was performed, represented in ISO 8601 format, UTC timezone.
          example: 2026-05-28T07:28:22Z

    Mode:
      type: string
      description: |
        Mode of communication.
        Possible values:
        - **Phone**: Communication via phone.
        - **Portal**: Communication via online portal.
        - **Fax**: Communication via fax.
      enum:
        - Phone
        - Portal
        - Fax
      example: Phone

    PriorAuthEntity:
      type: string
      description: |
        Represents the Prior Authorization entity for processing authorizations.
        Possible values:
        - **AIM** - AIM Specialty Health
        - **Availity** - Availity Portal
        - **Avalon** - Avalon Healthcare
        - **BCBSRI** - Blue Cross Blue Shield Rhode Island
        - **Beacon** - Beacon Health Options
        - **CignaEVB** - Cigna EVB Portal
        - **CohereHealth** - Cohere Health Platform
        - **Connex** - Connex Healthcare System
        - **EviCore** - EviCore Healthcare
        - **Healthhelp** - HealthHelp Portal
        - **HealthSun** - HealthSun Health Plans
        - **Homeplan** - Home Plan Portal
        - **Medi-Cal** - California Medicaid (Medi-Cal)
        - **Medsolution** - MedSolution Platform
        - **Meritain** - Meritain Health
        - **Navinet** - NaviNet Portal
        - **NIA** - National Imaging Associates
        - **Sunshine** - Sunshine Health
        - **Tricare** - Tricare Health System
        - **TurningPoint** - TurningPoint Healthcare
        - **UnitedHealth** - UnitedHealthcare
      enum:
        - AIM
        - Availity
        - Avalon
        - BCBSRI
        - Beacon
        - CignaEVB
        - CohereHealth
        - Connex
        - EviCore
        - Healthhelp
        - HealthSun
        - Homeplan
        - Medi-Cal
        - Medsolution
        - Meritain
        - Navinet
        - NIA
        - Sunshine
        - Tricare
        - TurningPoint
        - UnitedHealth
      example: Availity