openapi: 3.0.3
info:
  title: Mobile Check Cashing SDK — Add or Update Tokenized Card
  version: '1'
  description: |
    PCI-friendlier alternative to `POST /add-or-update-card`. Submit a
    partner-issued tokenized placeholder (`cardToken`) plus the card
    BIN and last 4 digits instead of the raw PAN.

    **Prerequisite.** Using the tokenized endpoint requires that Ingo
    has a direct out-of-band mechanism to load card data, since the
    raw PAN never crosses the SDK API. This is configured per partner
    during onboarding.

    Behavior matches the non-tokenized endpoint:

    - Unchanged data → no reauthorization
    - Card number or expiration change → reauthorization (where a
      validator is set up for the card program)
    - Authorization failure flags the card as invalid

    Partners may only update their own cards. Card validation is
    per-card-program — some partners may opt out entirely.

    Card-Partner only. Requires an active SDK partner session — the
    `SessionId` header from `POST /api/v1/partners/authenticate` — plus
    the customer's `customerId`. It does not require the OBO `ssoToken`;
    card setup typically runs before `/authenticate-obo`.
servers:
  - url: https://check-cashing-uat.spykemobile.net
    description: UAT (Sandbox)
  - url: https://check-cashing.spykemobile.net
    description: Production
security:
  - OAuth2:
      - sdkapi
tags:
  - name: Cards
    description: Card account management for Card Partners.
paths:
  /api/v1/partners/add-or-update-tokenized-card:
    post:
      tags:
        - Cards
      operationId: addOrUpdateTokenizedCard
      summary: Add or update a card (tokenized)
      description: |
        Adds or updates a card using a partner-issued token rather
        than the raw PAN. See `description` in `info` for the
        prerequisite that Ingo has an out-of-band card load mechanism
        configured for the partner.
      parameters:
        - $ref: '#/components/parameters/SessionIdHeader'
        - $ref: '#/components/parameters/DeviceIdHeader'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AddOrUpdateTokenizedCardRequest'
            example:
              customerId: 333554bf-b273-4d6e-b4f8-d319a1929608
              cardToken: 42f76930-2662-4839-bf9f-8bfbe9b58cca
              cardBin: '12345'
              expirationMonthYear: '1225'
              cardNickname: Home
              nameOnCard: Roger Rabbit
              addressLine1: 123 Main St.
              addressLine2: ''
              city: Nashville
              state: TN
              zip: '37075'
      responses:
        '200':
          description: Card added or updated.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CardListResponse'
              example:
                cards:
                  - cardId: 3b2ef6d2-76f2-43bb-b9ab-dc5be2c5c3db
                    cardNickname: ''
                    cardProgram: ''
                    customerId: 333554bf-b273-4d6e-b4f8-d319a1929608
                    lastFourDigits: '****'
                    hashId: ''
        '422':
          description: |
            The supplied card token, BIN, or other detail was rejected.
            Common cause: the account is not allowed in the Ingo
            network for this partner program.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetails'
              example:
                type: https://tools.ietf.org/html/rfc4918#section-11.2
                title: Error
                status: 422
                detail: >-
                  Sorry, the account you're attempting to register is not
                  allowed in our network.(A275)
                instance: /api/v1/partners/add-or-update-tokenized-card
                errorCode: BAD_REQUEST
components:
  securitySchemes:
    OAuth2:
      type: oauth2
      flows:
        clientCredentials:
          tokenUrl: https://auth.spykemobile.net/connect/token
          scopes:
            sdkapi: Mobile Check Cashing SDK partner methods
  parameters:
    SessionIdHeader:
      name: SessionId
      in: header
      required: true
      schema:
        type: string
    DeviceIdHeader:
      name: DeviceId
      in: header
      required: true
      schema:
        type: string
  schemas:
    AddOrUpdateTokenizedCardRequest:
      type: object
      required:
        - customerId
        - cardToken
        - cardBin
        - expirationMonthYear
        - cardNickname
        - addressLine1
        - addressLine2
        - city
        - state
        - zip
      properties:
        customerId:
          type: string
          format: uuid
          minLength: 36
          maxLength: 36
        cardToken:
          type: string
          maxLength: 255
          description: |
            Partner-issued opaque token representing the card. Up to
            256 characters per dev-center docs.
        cardBin:
          type: string
          minLength: 1
          maxLength: 50
          description: |
            Card BIN. 6-to-8-digit prefix per dev-center docs;
            validator allows up to 50 chars.
        lastFourOfCard:
          type: string
          maxLength: 4
          pattern: ^[0-9]{4}$
          description: Last 4 digits of the unformatted card PAN.
        expirationMonthYear:
          type: string
          minLength: 4
          maxLength: 4
          pattern: ^(0[1-9]|1[0-2])[0-9]{2}$
          description: MMYY format.
        cardNickname:
          type: string
          minLength: 1
          maxLength: 20
        nameOnCard:
          type: string
          maxLength: 100
        addressLine1:
          type: string
          minLength: 1
          maxLength: 50
        addressLine2:
          type: string
          minLength: 1
          maxLength: 50
        city:
          type: string
          minLength: 1
          maxLength: 50
        state:
          type: string
          minLength: 1
          maxLength: 2
        zip:
          type: string
          minLength: 5
          maxLength: 5
          pattern: ^[0-9]{5}$
    CardListResponse:
      type: object
      required:
        - cards
      properties:
        cards:
          type: array
          items:
            $ref: '#/components/schemas/Card'
    Card:
      type: object
      properties:
        cardId:
          type: string
        customerId:
          type: string
        cardNickname:
          type: string
        cardProgram:
          type: string
        lastFourDigits:
          type: string
          maxLength: 4
        hashId:
          type: string
    ProblemDetails:
      type: object
      required:
        - type
        - title
        - status
      properties:
        type:
          type: string
          format: uri
        title:
          type: string
        status:
          type: integer
        detail:
          type: string
        instance:
          type: string
        errorCode:
          type: string
