openapi: 3.0.3
info:
  title: Ingo Check Protect API
  version: '1'
  description: |
    Real-time check risk scoring API. Submit predictive customer and
    check transaction attributes; receive a transactional risk score
    correlated to a recommended funds hold time.

    Check Protect is an Ingo-driven decisioning service — Ingo Money
    assesses the risk and returns a score. For data-only services where
    the client retains the underwriting decision, see the Fraud Alert,
    Check Maker Alert, and Duplicate Exchange APIs.

    **Authentication.** OAuth 2.0 client credentials grant. Production
    token URL: `https://auth.ingo.money/connect/token`. UAT token URL:
    `https://auth-uat.ingo.money/connect/token`. Required scope:
    `https://apis.ingo.money/auth/deposit-underwriting`. Access tokens are
    valid for 3600 seconds — cache and reuse the token across calls.

    **Idempotency.** The endpoint is idempotent on the pair
    (`clientId`, `transactionId`). Retries with the same pair return the
    most recent score with response header `X-Idempotent: true`. A retry
    sent while the original request is still in flight returns HTTP 409.

    **Connectivity.** TLS 1.2 minimum. Client IPs must be on the
    pre-provisioned allowlist. Client credentials are provisioned by Ingo
    Client Services via PGP-encrypted file.

    **Versioning.** Current API version: `1`. Specify via `apiVersion`
    request header or query string.
servers:
  - url: https://deposit-underwriting-uat.ingo.money
    description: UAT (Sandbox)
  - url: https://deposit-underwriting.ingo.money
    description: Production
security:
  - OAuth2:
      - https://apis.ingo.money/auth/deposit-underwriting
tags:
  - name: Check Scoring
    description: Submit a check transaction for risk scoring.
paths:
  /deposit/score:
    post:
      tags:
        - Check Scoring
      operationId: scoreDeposit
      summary: Score a check transaction
      description: |
        Submit a single check transaction (mobile, ATM/kiosk, or
        branch) for real-time risk scoring. Returns a numeric
        `transactionRiskScore` correlated to a recommended funds hold
        time. Score `1` indicates the transaction was referred to the
        Ingo Risk Center for manual review and that an asynchronous
        webhook will follow once the review completes.

        Returns `X-Idempotent: true` in the response headers when the
        request is a duplicate of a prior `(clientId, transactionId)`
        pair. Duplicate requests sent while the original is still in
        flight return HTTP 409.
      parameters:
        - name: apiVersion
          in: header
          required: false
          schema:
            type: string
            default: '1'
          description: |
            API version. Current version is `1`. May also be supplied as
            a query string parameter of the same name.
        - name: apiVersion
          in: query
          required: false
          schema:
            type: string
          description: |
            Alternative to the `apiVersion` header. Same semantics.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ScoreDepositRequest'
            examples:
              mobileDeposit:
                summary: Mobile check submission, full payload
                value:
                  clientId: 9f6ca047-7f0a-40a4-9685-6894f228d588
                  transactionId: ef17e5bf-97e6-4a7a-bfb0-24faa09fe3ee
                  customerId: 4dc95598-bb5b-4eea-97e7-08bc94c6bcf4
                  depositChannel: MOBILE
                  depositAccounts:
                    - accountNumberLast4: '7777'
                      accountType: DDA
                      accountAddress:
                        addressType: PERSONAL
                        addressLine1: 123 Sesame St
                        addressLine2: null
                        city: Denver
                        stateCode: CO
                        zipCode: '12345'
                        isStandardized: false
                      depositAccountAttributes:
                        tenureInDays: 370
                        totalTransactionCountPerMonth: 5
                        averageMonthlyDepositAmountInCents: 65840
                        currentBalanceInCents: 59695
                        isDirectDepositEnabled: false
                        checksSubmittedCountLast2Years: 25
                        checksAcceptedCountLast2Years: 20
                        averageChecksAcceptedAmountInCentsLast2Years: 250000
                        checksReturnedCountLast2Years: 5
                        averageCheckReturnAmountInCentsLast2Years: 65840
                        customAttributes:
                          - attributeName: tenureInMonths
                            attributeValue: '5'
                  profile:
                    firstName: Jim
                    middleName: Allen
                    lastName: LaDue
                    email: someone@email.com
                    ssn: '555555555'
                    dob: 05-05-1985
                    mobilePhoneNumber: '6158675309'
                    alternatePhoneNumber: null
                    profileAddress:
                      addressType: PERSONAL
                      addressLine1: 123 Sesame St
                      addressLine2: null
                      city: Denver
                      stateCode: CO
                      zipCode: '12345'
                      isStandardized: false
                    profileRelationshipAttributes:
                      tenureInDays: 345
                      totalActiveAccounts: 5
                      totalClosedAccountsCount: 10
                      totalTransactionCountPerMonthAllAccounts: 5
                      averageMonthlyDepositAmountInCentsAllAccounts: 65840
                      currentBalanceInCentsAllAccounts: 59695
                      isDirectDepositEnabled: true
                      totalChecksSubmittedCountLast2Years: 8
                      totalChecksAcceptedCountLast2Years: 7
                      averageTotalChecksAcceptedAmountInCentsLast2Years: 512670
                      totalChecksReturnedCountLast2Years: 1
                      averageTotalCheckReturnAmountInCentsLast2Years: 50087
                      customAttributes:
                        - attributeName: hasGoldAccountStatus
                          attributeValue: 'false'
                  deviceInfo:
                    fingerPrinting:
                      iovation:
                        blackBoxValue: BLACK_BOX_VALUE_GOES_HERE
                  geoLocation:
                    latitude: '89.998998'
                    longitude: '179.21212121'
                  checkDetails:
                    endorsementCheckRequired: true
                    accountNumber: '11223333'
                    checkNumber: '1234'
                    aba: '123456789'
                    micr: MICR
                    ocrAmountInCents: 50000
                    checkAmountInCents: 50000
                    checkDate: 01-10-2020
                    checkImages:
                      frontImageJpg: base64EncodedJPG|URL
                      backImageJpg: base64EncodedJPG|URL
                    checkMaker:
                      makerName: Chuck Jones
                      makerAddress:
                        addressLine1: 123 Sesame St
                        addressLine2: Optional
                        city: Denver
                        stateCode: CO
                        zipCode: '12345'
                  correlationData:
                    - attributeName: correlationId1
                      attributeValue: '12345'
      responses:
        '200':
          description: |
            Risk score returned. Inspect `transactionRiskScore` for the
            recommended funds hold time:
            - `1` — referred to Ingo Risk Center for manual review;
              follow-up webhook will deliver the final score
            - `2`–`299` — discrete high-risk / fraud indicators
            - `300`–`1000` — continuous scores (higher is better)
          headers:
            X-Idempotent:
              schema:
                type: string
                enum:
                  - 'true'
                  - 'false'
              description: |
                `true` when this response is a replay of a prior
                request with the same `(clientId, transactionId)`.
                `false` for the original request. Idempotent responses
                do NOT trigger webhooks.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ScoreDepositResponse'
              examples:
                approved:
                  summary: Continuous score (recommended hold time path)
                  value:
                    clientData:
                      clientId: 9f6ca047-7f0a-40a4-9685-6894f228d588
                      transactionId: ef17e5bf-97e6-4a7a-bfb0-24faa09fe3ee
                      customerId: 4dc95598-bb5b-4eea-97e7-08bc94c6bcf4
                    ingoCustomerId: 30355728-d834-4feb-a7a4-2471e036cee5
                    ingoTransactionId: af0fa81c-9110-4b6d-a0d6-8855f652bed5
                    checkType: PersonalCheck
                    checkMakerName: Regions
                    ingoCheckAmountInCents: 88419
                    transactionRiskScore: 900
                    transactionRiskEngineScore: 900
                    requestId: 3a9d273c-91f3-4580-96e6-b3ad19512e32
                referredToManualReview:
                  summary: Referred to Ingo Risk Center (webhook follows)
                  value:
                    clientData:
                      clientId: 9f6ca047-7f0a-40a4-9685-6894f228d588
                      transactionId: ef17e5bf-97e6-4a7a-bfb0-24faa09fe3ee
                      customerId: 4dc95598-bb5b-4eea-97e7-08bc94c6bcf4
                    ingoCustomerId: 30355728-d834-4feb-a7a4-2471e036cee5
                    ingoTransactionId: af0fa81c-9110-4b6d-a0d6-8855f652bed5
                    checkType: PersonalCheck
                    checkMakerName: null
                    ingoCheckAmountInCents: 50000
                    transactionRiskScore: 1
                    transactionRiskEngineScore: 1
                    requestId: 3a9d273c-91f3-4580-96e6-b3ad19512e32
        '409':
          description: |
            An idempotent request was received while the original is
            still being processed (in-flight conflict). Retry once the
            original completes.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/InFlightConflictError'
              example:
                errorCode: IN_FLIGHT_TRANSACTION_CONFLICT
                type: https://httpstatuses.com/409
                title: IN_FLIGHT_TRANSACTION_CONFLICT
                status: 409
                detail: IN_FLIGHT_TRANSACTION_CONFLICT
                instance: /deposit/score
        '422':
          description: |
            Business validation error. The request was well-formed but
            failed a domain rule (e.g., unreadable check image,
            invalid address, account in an unsupported state).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BusinessValidationError'
              example:
                businessErrorCode: BAD_CHECK_IMAGE
                type: https://httpstatuses.com/422
                title: Image Read Error
                status: 422
                detail: We are unable to accurately read the provided check image
                instance: /deposit/score
        '500':
          description: |
            Unexpected server error. Use a fault-tolerant retry strategy
            (see Ingo Check Protect overview, "Fault Tolerance" section).
components:
  securitySchemes:
    OAuth2:
      type: oauth2
      description: |
        OAuth 2.0 client credentials grant. Production token URL is
        defined below. For UAT, use
        `https://auth-uat.ingo.money/connect/token` instead. Client
        credentials are provisioned by Ingo Client Services via
        PGP-encrypted file. Tokens are valid for 3600 seconds.
      flows:
        clientCredentials:
          tokenUrl: https://auth.ingo.money/connect/token
          scopes:
            https://apis.ingo.money/auth/deposit-underwriting: Check Protect check risk scoring
  schemas:
    ScoreDepositRequest:
      type: object
      required:
        - clientId
        - transactionId
        - customerId
        - depositChannel
        - depositAccounts
        - profile
        - checkDetails
      properties:
        clientId:
          type: string
          maxLength: 50
          format: uuid
          description: Ingo-assigned client identifier (GUID).
          example: 9f6ca047-7f0a-40a4-9685-6894f228d588
        transactionId:
          type: string
          maxLength: 50
          description: |
            Client-supplied unique transaction identifier. Combined with
            `clientId` forms the idempotency key.
          example: ef17e5bf-97e6-4a7a-bfb0-24faa09fe3ee
        customerId:
          type: string
          maxLength: 50
          description: Client-supplied unique customer identifier.
          example: 4dc95598-bb5b-4eea-97e7-08bc94c6bcf4
        depositChannel:
          type: string
          enum:
            - MOBILE
            - ATM_KIOSK
            - BRANCH
          description: |
            Channel through which the deposit was captured. Drives which
            of `atmKiosk`, `bankInfo`, `deviceInfo`, and `geoLocation`
            objects are required.
        atmKiosk:
          $ref: '#/components/schemas/AtmKiosk'
          description: Required when `depositChannel` is `ATM_KIOSK`.
        bankInfo:
          $ref: '#/components/schemas/BankInfo'
          description: Required when `depositChannel` is `BRANCH`.
        depositAccounts:
          type: array
          items:
            $ref: '#/components/schemas/DepositAccount'
          minItems: 1
          description: One or more deposit accounts being credited.
        profile:
          $ref: '#/components/schemas/Profile'
        deviceInfo:
          $ref: '#/components/schemas/DeviceInfo'
          description: Required when `depositChannel` is `MOBILE`.
        geoLocation:
          $ref: '#/components/schemas/GeoLocation'
          description: Required when `depositChannel` is `MOBILE`.
        checkDetails:
          $ref: '#/components/schemas/CheckDetails'
        correlationData:
          type: array
          items:
            $ref: '#/components/schemas/Attribute'
          description: Optional client-supplied correlation attributes.
    AtmKiosk:
      type: object
      required:
        - atmNumber
        - atmAddress
      properties:
        atmNumber:
          type: string
          maxLength: 50
          description: ATM identifier.
        atmAddress:
          $ref: '#/components/schemas/Address'
    BankInfo:
      type: object
      required:
        - bankCode
        - branchCode
        - bankAddress
      properties:
        bankCode:
          type: string
          maxLength: 50
        branchCode:
          type: string
          maxLength: 50
        bankAddress:
          $ref: '#/components/schemas/Address'
    Address:
      type: object
      required:
        - addressLine1
        - city
        - stateCode
        - zipCode
      properties:
        addressLine1:
          type: string
          maxLength: 75
        addressLine2:
          type: string
          maxLength: 75
          nullable: true
        city:
          type: string
          maxLength: 75
        stateCode:
          type: string
          minLength: 2
          maxLength: 2
          description: Two-character US state code.
        zipCode:
          type: string
          maxLength: 10
          pattern: ^[0-9]{5}(-[0-9]{4})?$
          description: 5-digit or 9-digit (with optional dash) US ZIP code.
        isStandardized:
          type: boolean
          description: |
            Flag indicating whether the address has been standardized
            per USPS Publication 28.
    AddressedAddress:
      allOf:
        - $ref: '#/components/schemas/Address'
        - type: object
          required:
            - addressType
          properties:
            addressType:
              type: string
              enum:
                - PERSONAL
                - BUSINESS
    DepositAccount:
      type: object
      required:
        - accountNumberLast4
        - accountType
        - accountAddress
      properties:
        accountNumberLast4:
          type: string
          minLength: 4
          maxLength: 4
          pattern: ^[0-9]{4}$
          description: Last 4 digits of the deposit account number.
        accountType:
          type: string
          enum:
            - DDA
            - SAVINGS
            - MONEY_MARKET
            - INVESTMENT
            - DEBIT_CARD
            - PREPAID_CARD
            - DIGITAL_WALLET
        accountAddress:
          $ref: '#/components/schemas/AddressedAddress'
        depositAccountAttributes:
          $ref: '#/components/schemas/DepositAccountAttributes'
    DepositAccountAttributes:
      type: object
      description: |
        Risk attributes about this deposit account. See the
        depositAccount & profileRelationship attributes PDF on the dev
        center for full definitions.
      properties:
        tenureInDays:
          type: integer
        totalTransactionCountPerMonth:
          type: integer
        averageMonthlyDepositAmountInCents:
          type: integer
        currentBalanceInCents:
          type: integer
        isDirectDepositEnabled:
          type: boolean
        checksSubmittedCountLast2Years:
          type: integer
        checksAcceptedCountLast2Years:
          type: integer
        averageChecksAcceptedAmountInCentsLast2Years:
          type: integer
        checksReturnedCountLast2Years:
          type: integer
        averageCheckReturnAmountInCentsLast2Years:
          type: integer
        customAttributes:
          type: array
          items:
            $ref: '#/components/schemas/Attribute'
    Profile:
      type: object
      required:
        - firstName
        - lastName
        - email
        - ssn
        - dob
        - mobilePhoneNumber
        - profileAddress
        - profileRelationshipAttributes
      properties:
        firstName:
          type: string
          maxLength: 75
        middleName:
          type: string
          maxLength: 75
        lastName:
          type: string
          maxLength: 75
        email:
          type: string
          format: email
          maxLength: 320
        ssn:
          type: string
          minLength: 9
          maxLength: 9
          pattern: ^[0-9]{9}$
          description: 9-digit US Social Security Number, digits only.
        dob:
          type: string
          maxLength: 10
          description: |
            Date of birth in `mm/dd/yyyy` or `mm-dd-yyyy` format.
          example: 05-05-1985
        mobilePhoneNumber:
          type: string
          minLength: 10
          maxLength: 10
          pattern: ^[0-9]{10}$
        alternatePhoneNumber:
          type: string
          minLength: 10
          maxLength: 10
          pattern: ^[0-9]{10}$
          nullable: true
        profileAddress:
          $ref: '#/components/schemas/AddressedAddress'
        profileRelationshipAttributes:
          $ref: '#/components/schemas/ProfileRelationshipAttributes'
    ProfileRelationshipAttributes:
      type: object
      description: |
        Aggregate risk attributes across all of the customer's accounts.
        See the depositAccount & profileRelationship attributes PDF on
        the dev center for full definitions.
      properties:
        tenureInDays:
          type: integer
        totalActiveAccounts:
          type: integer
        totalClosedAccountsCount:
          type: integer
        totalTransactionCountPerMonthAllAccounts:
          type: integer
        averageMonthlyDepositAmountInCentsAllAccounts:
          type: integer
        currentBalanceInCentsAllAccounts:
          type: integer
        isDirectDepositEnabled:
          type: boolean
        totalChecksSubmittedCountLast2Years:
          type: integer
        totalChecksAcceptedCountLast2Years:
          type: integer
        averageTotalChecksAcceptedAmountInCentsLast2Years:
          type: integer
        totalChecksReturnedCountLast2Years:
          type: integer
        averageTotalCheckReturnAmountInCentsLast2Years:
          type: integer
        customAttributes:
          type: array
          items:
            $ref: '#/components/schemas/Attribute'
    DeviceInfo:
      type: object
      required:
        - fingerPrinting
      properties:
        statedIp:
          type: string
          maxLength: 39
          description: Client-stated IP address (IPv4 or IPv6).
        fingerPrinting:
          type: object
          required:
            - iovation
          properties:
            iovation:
              type: object
              required:
                - blackBoxValue
              properties:
                blackBoxValue:
                  type: string
                  maxLength: 4000
                  description: iovation device fingerprint blackbox value.
    GeoLocation:
      type: object
      required:
        - latitude
        - longitude
      properties:
        latitude:
          type: string
          description: |
            Decimal latitude as a string. Inclusive range -90 to 90.
        longitude:
          type: string
          description: |
            Decimal longitude as a string. Inclusive range -180 to 180.
    CheckDetails:
      type: object
      required:
        - accountNumber
        - checkNumber
        - aba
        - micr
        - checkAmountInCents
        - checkDate
        - checkImages
      properties:
        endorsementCheckRequired:
          type: boolean
          default: false
          description: |
            Client-supplied flag forcing manual review of the check
            images. Default `false`.
        accountNumber:
          type: string
          maxLength: 25
        checkNumber:
          type: string
          maxLength: 15
        aba:
          type: string
          maxLength: 10
          description: Check routing (ABA) number.
        micr:
          type: string
          maxLength: 75
        ocrAmountInCents:
          type: integer
          minimum: 1
          description: OCR-derived check amount in cents.
        checkAmountInCents:
          type: integer
          minimum: 1
          description: Client-asserted check amount in cents.
        checkDate:
          type: string
          description: |
            Check date in `mm/dd/yyyy` or `mm-dd-yyyy` format.
        checkImages:
          $ref: '#/components/schemas/CheckImages'
        checkMaker:
          $ref: '#/components/schemas/CheckMaker'
        ocrScores:
          $ref: '#/components/schemas/OcrScores'
    CheckImages:
      type: object
      description: |
        Front and back check images. JPG images are required for manual
        reviews; TIFF images are optional but may improve automated
        decisioning. Pre-signed URLs are preferred over base64 encoding.
      properties:
        frontImageJpg:
          type: string
        backImageJpg:
          type: string
        frontImageTiff:
          type: string
        backImageTiff:
          type: string
    CheckMaker:
      type: object
      properties:
        makerName:
          type: string
          maxLength: 150
        makerAddress:
          $ref: '#/components/schemas/Address'
    OcrScores:
      type: object
      description: Optional OCR confidence scores for each parsed field.
      properties:
        scoreRangeMax:
          type: integer
        accountNumberScore:
          type: integer
        checkNumberScore:
          type: integer
        abaScoreScore:
          type: integer
        micrScore:
          type: integer
        checkAmountScore:
          type: integer
        checkDateScore:
          type: integer
    Attribute:
      type: object
      required:
        - attributeName
        - attributeValue
      properties:
        attributeName:
          type: string
          maxLength: 75
        attributeValue:
          type: string
          maxLength: 75
    ScoreDepositResponse:
      type: object
      required:
        - clientData
        - ingoCustomerId
        - ingoTransactionId
        - checkType
        - ingoCheckAmountInCents
        - transactionRiskScore
        - requestId
      properties:
        clientData:
          type: object
          required:
            - clientId
            - transactionId
            - customerId
          properties:
            clientId:
              type: string
              format: uuid
              description: Echo of request `clientId`.
            transactionId:
              type: string
              maxLength: 50
              description: Echo of request `transactionId`.
            customerId:
              type: string
              maxLength: 50
              description: Echo of request `customerId`.
        ingoCustomerId:
          type: string
          format: uuid
          description: Ingo-assigned internal customer identifier.
        ingoTransactionId:
          type: string
          format: uuid
          description: Ingo-assigned internal transaction identifier.
        checkType:
          type: string
          description: Identified check type (e.g., PersonalCheck, Government).
        checkMakerName:
          type: string
          maxLength: 50
          nullable: true
        ingoCheckAmountInCents:
          type: integer
          description: Ingo-derived check amount in cents.
        transactionRiskScore:
          type: integer
          description: |
            Primary Ingo risk score. Interpretation:
            - `1` — referred to Ingo Risk Center; final score arrives
              via webhook
            - `2`–`299` — discrete high-risk / fraud indicators
            - `300`–`1000` — continuous scores correlated to hold time
              (higher is better)
        transactionRiskEngineScore:
          type: integer
          nullable: true
          description: |
            Raw engine score. Typically echoes `transactionRiskScore`;
            may diverge when client-configured scoring overrides apply.
        requestId:
          type: string
          maxLength: 128
    BusinessValidationError:
      type: object
      description: |
        RFC 7807-style problem details for business validation failures
        (HTTP 422).
      required:
        - businessErrorCode
        - type
        - title
        - status
        - detail
        - instance
      properties:
        businessErrorCode:
          type: string
          description: Stable machine-readable error code.
        type:
          type: string
          format: uri
        title:
          type: string
        status:
          type: integer
          example: 422
        detail:
          type: string
        instance:
          type: string
    InFlightConflictError:
      type: object
      description: |
        RFC 7807-style problem details returned when a duplicate
        idempotent request is received while the original is still being
        processed (HTTP 409).
      required:
        - errorCode
        - type
        - title
        - status
        - detail
        - instance
      properties:
        errorCode:
          type: string
          enum:
            - IN_FLIGHT_TRANSACTION_CONFLICT
        type:
          type: string
          format: uri
        title:
          type: string
        status:
          type: integer
          example: 409
        detail:
          type: string
        instance:
          type: string
