openapi: 3.0.3
info:
  title: Ingo Fraud Alert API
  version: '1'
  description: |
    Inquire about Ingo's positive or negative experience with a consumer
    across multiple independent identifiers. Submit any combination of
    identity (name + SSN + DOB), email address, mobile number, address,
    device ID, and/or geolocation; receive a per-identifier risk score
    plus first/last seen dates across the Ingo network. Fraud Alert is
    a data service — the client retains the underwriting decision.

    Each identifier is scored independently. The response includes a
    section for each identifier submitted in the request. If a section
    cannot be located in the network, that section is returned as
    `null`.

    **Score interpretation.** Scores fall into discrete negative
    buckets, neutral, or a continuous positive range:

    - `9` — Suspected Identity Theft
    - `99` — Likely Fraud
    - `199` — Suspicious Activity
    - `299` — High Risk Activity
    - `300`–`499` — No positive transactional experience
    - `500`–`1000` — Continuous positive transactional experience
      (higher is better)
    - `9999` — No reportable positive or negative information; passed
      KYC but no transactional history, or data not reportable for
      compliance reasons

    Transactional experience scores (`300`–`1000`) are returned only on
    the `identity` block, never on devices, addresses, email addresses,
    or geolocation.

    **Validation errors do not fail the call.** When a request field is
    invalid, the API returns HTTP 200 with the affected response group
    set to `null` and a `validationErrors` array describing the issue.
    Hard failures (auth, version, malformed request) return RFC 7807
    Problem Details with a 4xx/5xx status.

    **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/insights/identity-score`. Access
    tokens are valid for 3600 seconds — cache and reuse the token
    across calls.

    **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. Defaults to `1` if omitted.
servers:
  - url: https://insights-uat.ingo.money
    description: UAT (Sandbox)
  - url: https://insights.ingo.money
    description: Production
security:
  - OAuth2:
      - https://apis.ingo.money/auth/insights/identity-score
tags:
  - name: Identity Scoring
    description: >-
      Score a consumer across identity, email, mobile, address, device, and
      geolocation.
paths:
  /identity/score:
    post:
      tags:
        - Identity Scoring
      operationId: scoreIdentity
      summary: Score a consumer identity and associated identifiers
      description: |
        Submit any combination of identity, email address, mobile
        number, address, device ID, and geolocation. The API returns a
        score per identifier group plus first/last seen dates. Groups
        that cannot be located are returned as `null`. Field-level
        validation issues do not fail the call — they appear in a
        `validationErrors` array with the affected group nulled out.
      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. If both are supplied
            with different values, the API returns 400 AmbiguousApiVersion.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/IdentityScoreRequest'
            example:
              identity:
                firstName: Gabriel
                lastName: Mitchell
                ssn: '900000001'
              emailAddress: aaron53@adventure-works.com
              deviceId: '1674238924'
              geoLocation:
                latitude: '18.375'
                longitude: '28.375'
              mobileNumber: '9735550195'
              address:
                line1: 1197 Santa Barbara
                city: Santa Monica
                state: CA
                zipCode: '90401'
              correlationData:
                - attributeName: AttributeName1
                  attributeValue: AttributeValue1
                - attributeName: AttributeName2
                  attributeValue: AttributeValue2
      responses:
        '200':
          description: |
            Scores returned for each submitted identifier group.
            Sections may be `null` when the group cannot be located or
            when a request-level validation error affected that group.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/IdentityScoreResponse'
              examples:
                allGroupsLocated:
                  summary: All requested groups located
                  value:
                    identity:
                      firstNameMatch: true
                      lastNameMatch: true
                      score: 900
                      firstSeenOn: 12-31-2020
                      lastSeenOn: 01-25-2019
                    emailAddress:
                      score: 9999
                      firstSeenOn: 12-31-2020
                      lastSeenOn: 01-25-2019
                    mobileNumber:
                      score: 199
                      firstSeenOn: 12-31-2020
                      lastSeenOn: 01-25-2019
                    address:
                      score: 9999
                      firstSeenOn: 12-31-2020
                      lastSeenOn: 01-25-2019
                    deviceId:
                      score: 9999
                      firstSeenOn: 12-31-2020
                      lastSeenOn: 01-25-2019
                    geoLocation:
                      score: 9999
                      firstSeenOn: 12-31-2020
                      lastSeenOn: 01-25-2019
                withValidationErrors:
                  summary: One group invalid; others returned normally
                  value:
                    identity:
                      firstNameMatch: true
                      lastNameMatch: true
                      score: 9
                      firstSeenOn: 06-23-2021
                      lastSeenOn: 06-24-2021
                    emailAddress: null
                    mobileNumber:
                      score: 299
                      firstSeenOn: 12-11-2020
                      lastSeenOn: 06-24-2021
                    address:
                      matchType: Full
                      score: 9999
                      firstSeenOn: 05-19-2020
                      lastSeenOn: 06-24-2021
                    deviceId:
                      score: 9999
                      firstSeenOn: 12-13-2018
                      lastSeenOn: 06-24-2021
                    geoLocation: null
                    validationErrors:
                      - fieldName: EmailAddress
                        error: '''Email Address'' is not a valid email address.'
        '400':
          description: |
            Hard validation, versioning, or other client-side error.
            Note: field-level validation issues that do not prevent
            scoring are returned in the 200 response's `validationErrors`
            array instead.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetails'
              examples:
                inputValidationError:
                  summary: Identity field validation failure
                  value:
                    type: https://tools.ietf.org/html/rfc7231#section-6.5.1
                    title: InputValidationError
                    status: 400
                    detail: See the errors field for details.
                    instance: /identity/score
                    traceId: '|bad4a210-4b51729b279dd00f.'
                    errors:
                      Identity.FirstName:
                        - '''First Name'' must not be empty.'
                unsupportedApiVersion:
                  summary: Unsupported API version
                  value:
                    type: https://tools.ietf.org/html/rfc7231#section-6.5.1
                    title: UnsupportedApiVersion
                    status: 400
                    detail: >-
                      The HTTP resource that matches the request URI does not
                      support the API version '2'.
                    traceId: '|bad4a211-4b51729b279dd00f.'
                ambiguousApiVersion:
                  summary: Conflicting versions in header and query string
                  value:
                    type: https://tools.ietf.org/html/rfc7231#section-6.5.1
                    title: AmbiguousApiVersion
                    status: 400
                    detail: >-
                      The following API versions were requested: 1, 2. At most,
                      only a single API version may be specified.
                    traceId: '|31f77797-4a8da50f4fd3a851.'
        '401':
          description: Authorization failure.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetails'
              example:
                type: https://tools.ietf.org/html/rfc7235#section-3.1
                title: Unauthorized
                status: 401
                detail: Authorization failure.
                instance: /identity/score
                traceId: '|b56c1133-4c83cf831979499e.'
        '404':
          description: Resource not found at the requested URL.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetails'
              example:
                type: https://tools.ietf.org/html/rfc7231#section-6.5.4
                title: ResourceNotFound
                status: 404
                detail: Resource '/resource-not-located' not found.
                instance: /resource-not-located
                traceId: '|ddcf5087-4b680597207c67c5.'
        '500':
          description: >-
            Unexpected server error. Contact Ingo Client Services with the
            `traceId`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetails'
              example:
                type: https://tools.ietf.org/html/rfc7231#section-6.6.1
                title: InternalServerError.
                status: 500
                detail: Please contact Ingo money client services.
                instance: /identity/score
                traceId: '|c1ecee92-4f4cec828884a904.'
                errors: {}
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/insights/identity-score: Fraud Alert identity scoring
  schemas:
    IdentityScoreRequest:
      type: object
      description: |
        Submit any subset of identifier groups. The `identity` block is
        the primary section — when present, all three of `firstName`,
        `lastName`, and `ssn` are required; `dob` becomes required when
        only the last 4 of SSN is supplied.
      properties:
        identity:
          $ref: '#/components/schemas/IdentityRequestBlock'
        emailAddress:
          type: string
          format: email
          maxLength: 320
          description: Consumer email address.
        mobileNumber:
          type: string
          minLength: 10
          maxLength: 10
          pattern: ^[0-9]{10}$
          description: 10-digit consumer mobile number.
        address:
          $ref: '#/components/schemas/AddressRequestBlock'
        deviceId:
          type: string
          maxLength: 100
          description: iovation device identifier.
        geoLocation:
          $ref: '#/components/schemas/GeoLocationRequestBlock'
        correlationData:
          type: array
          items:
            $ref: '#/components/schemas/CorrelationAttribute'
          description: Optional client-supplied correlation attributes.
    IdentityRequestBlock:
      type: object
      required:
        - firstName
        - lastName
        - ssn
      properties:
        firstName:
          type: string
          maxLength: 75
        lastName:
          type: string
          maxLength: 75
        ssn:
          type: string
          description: |
            Full SSN (length 10 with dashes, or 9 digits — confirm with
            integration specialist) OR last 4 digits of SSN. When
            supplying the last 4, `dob` becomes required.
        dob:
          type: string
          minLength: 10
          maxLength: 10
          description: |
            Date of birth in `MM/dd/yyyy` or `MM-dd-yyyy` format.
            Required when only the last 4 digits of SSN are supplied.
    AddressRequestBlock:
      type: object
      required:
        - line1
        - city
        - state
        - zipCode
      properties:
        line1:
          type: string
          maxLength: 150
        line2:
          type: string
          maxLength: 150
        city:
          type: string
          maxLength: 150
        state:
          type: string
          minLength: 2
          maxLength: 2
          description: Two-character US state code.
        zipCode:
          type: string
          minLength: 5
          maxLength: 5
          pattern: ^[0-9]{5}$
          description: 5-digit US ZIP code.
    GeoLocationRequestBlock:
      type: object
      required:
        - latitude
        - longitude
      properties:
        latitude:
          type: string
          description: |
            Decimal latitude as a string. Range -90 to 90, precision
            up to 18 decimal places.
        longitude:
          type: string
          description: |
            Decimal longitude as a string. Range -180 to 180, precision
            up to 18 decimal places.
    CorrelationAttribute:
      type: object
      required:
        - attributeName
        - attributeValue
      properties:
        attributeName:
          type: string
          maxLength: 75
        attributeValue:
          type: string
          maxLength: 75
    IdentifierScoreBlock:
      type: object
      description: |
        Base score block for non-identity identifiers (email, mobile,
        address, deviceId, geolocation). Score interpretation matches
        the top-level spec description:
        9 / 99 / 199 / 299 are discrete negative buckets; 300–1000 do
        not apply to non-identity blocks (only `identity.score` carries
        transactional experience scores); 9999 indicates no reportable
        information.
      required:
        - score
      properties:
        score:
          type: integer
          description: |
            One of: `9` (Suspected Identity Theft), `99` (Likely Fraud),
            `199` (Suspicious Activity), `299` (High Risk Activity), or
            `9999` (no reportable information).
        firstSeenOn:
          type: string
          description: Date this identifier was first observed on the Ingo network.
        lastSeenOn:
          type: string
          description: Date this identifier was most recently observed on the Ingo network.
    AddressScoreBlock:
      allOf:
        - $ref: '#/components/schemas/IdentifierScoreBlock'
        - type: object
          properties:
            matchType:
              type: string
              description: |
                Indicates the degree of address match — e.g., `Full`.
                Surfaced only on the address block.
    IdentityScoreBlock:
      type: object
      description: |
        Score block for the `identity` group. This is the only block
        that returns transactional experience scores in the `300`–`1000`
        range.
      required:
        - score
      properties:
        firstNameMatch:
          type: boolean
        lastNameMatch:
          type: boolean
        score:
          type: integer
          description: |
            Score interpretation:
            - `9` Suspected Identity Theft
            - `99` Likely Fraud
            - `199` Suspicious Activity
            - `299` High Risk Activity
            - `300`–`499` No positive transactional experience
            - `500`–`1000` Continuous positive transactional experience
            - `9999` No reportable information
        firstSeenOn:
          type: string
        lastSeenOn:
          type: string
    IdentityScoreResponse:
      type: object
      description: |
        Each identifier group is scored independently. Any group can be
        `null` if it could not be located in the network or if a
        request-level field validation issue caused that group to be
        skipped (the issue is then surfaced in `validationErrors`).
      properties:
        identity:
          nullable: true
          allOf:
            - $ref: '#/components/schemas/IdentityScoreBlock'
        emailAddress:
          nullable: true
          allOf:
            - $ref: '#/components/schemas/IdentifierScoreBlock'
        mobileNumber:
          nullable: true
          allOf:
            - $ref: '#/components/schemas/IdentifierScoreBlock'
        address:
          nullable: true
          allOf:
            - $ref: '#/components/schemas/AddressScoreBlock'
        deviceId:
          nullable: true
          allOf:
            - $ref: '#/components/schemas/IdentifierScoreBlock'
        geoLocation:
          nullable: true
          allOf:
            - $ref: '#/components/schemas/IdentifierScoreBlock'
        validationErrors:
          type: array
          description: |
            Per-field validation errors that did not prevent scoring
            but caused one or more identifier groups to be returned as
            `null`. Returned alongside HTTP 200 — distinct from the
            400 InputValidationError problem details envelope.
          items:
            type: object
            required:
              - fieldName
              - error
            properties:
              fieldName:
                type: string
              error:
                type: string
    ProblemDetails:
      type: object
      description: |
        RFC 7807 Problem Details. Used for hard 4xx and 5xx failures
        only — soft field-level issues appear in the 200 response's
        `validationErrors` array.
      required:
        - type
        - title
        - status
      properties:
        type:
          type: string
          format: uri
        title:
          type: string
        status:
          type: integer
        detail:
          type: string
        instance:
          type: string
        traceId:
          type: string
          description: |
            Tracing identifier. Record this value on failed requests for
            support escalation.
        errors:
          type: object
          additionalProperties:
            type: array
            items:
              type: string
          description: |
            Field-level validation error map populated on 400
            InputValidationError.
