Integrating the Card Capture UI

This guide explains how to integrate Card Capture UI into your application. The Card Capture UI is a secure, iframe-based component that captures debit card information for external account linking. This feature allows you to collect sensitive card data through an iframe that handles card validation, network detection, and secure submission, helping you remain PCI compliant.

Supported card types: The iframe supports Visa and Mastercard debit, prepaid, and deferred debit cards. Credit cards are automatically rejected.

Result of integrating Card Capture UI

Upon a successful card submission, your system receives a long-lived external account link ID. You use this ID to initiate instant transfers via the Payment Hub API without storing or transmitting sensitive PANs. Because the iframe transmits card data server-to-server directly from the user's browser to Galileo's PCI-compliant environment, the PAN and CVV data never travel through your systems.

Workflow

The card capture process follows this sequence:

  1. Authorization — You request a session token (JWT) from Galileo to authorize the session. See Authorization steps for more details.

  2. Iframe session — You embed the iframe using the JWT provided by Galileo.

  3. Capture — The account holder inputs their card information directly into the Galileo-hosted iframe, which creates an externalAccountLinkId.

  4. Decision — Galileo performs CVV, address, and name validations through Visa to confirm the cardholder. The Card Capture UI triggers the CREDIT_CARD_SUBMISSION event to signify when the external account link passes validation.

  5. Execution — Use the externalAccountLinkId to call the Payment Hub API transfer endpoints.

Authorization steps

Follow these steps to authorize the session.
Note: This section focuses exclusively on token generation; see Handling submissions for the card validation flow.

  1. The account holder requests to link their account.

  2. Use the Get External Account Link Access endpoint to start the access token creation process with these parameters:

    • accountNoPRN of the account on your platform
    • integrationGALILEO_CARD_CAPTURE
  3. The Card Capture service validates the request and generates a fully formed, signed JWT.

  4. Galileo returns a response to your server where the value field contains the JWT.

  5. You pass this JWT directly to the iframe URL as ?jwtToken={value} to authorize this session.

Iframe integration steps

Follow these steps to embed the Card Capture UI into your application:

  1. Embed the iframe
    Add the iframe to your application. Set the initial visibility to hidden to prevent the account holder from seeing unstyled content while the iframe loads.

    <iframe
      id="cardCaptureFrame"
      src="https://{CORE}.{DOMAIN}/1.0/cardCapture?jwtToken={JWT_TOKEN}"
      allow="clipboard-read; clipboard-write"
      sandbox="allow-scripts allow-same-origin allow-forms"
      style="visibility: hidden; border: none; width: 100%; height: 400px;">
    </iframe>
    

    Note: To successfully authorize the session, your src URL must include the JWT returned from the Get External Account Link Access endpoint. By default, the iframe only accepts domestic AFT-capable cards. To disable this restriction, append the optional &restrictToAFT=false parameter to your URL.

  2. Listen for messages
    The iframe communicates with your parent page using the window.postMessage API. You must configure your system to listen for the iframe lifecycle and submission results below.

    Event typeDescription
    IFRAME_READYSent when the iframe initializes. You should send your configuration after receiving this.
    APP_READY_TO_SHOWSent when styles are applied. You should now make the iframe visible to the user.
    CREDIT_CARD_SUBMISSIONSent when the account holder submits their card information. Contains the externalAccountLinkId on success.
    RESIZE_REQUESTSent if the iframe content height changes. Use this to adjust your container height.

    Example

    window.addEventListener('message', (event) => {
      // Validate origin in production
      // if (event.origin !== 'https://expected-origin.com') return;
    
      switch (event.data.type) {
        case 'IFRAME_READY':
          sendConfiguration();
          break;
        case 'APP_READY_TO_SHOW':
          document.getElementById('cardCaptureFrame').style.visibility = 'visible';
          break;
        case 'CREDIT_CARD_SUBMISSION':
          if (event.data.success) {
            handleSuccess(event.data.data.externalAccountLinkId);
          } else {
            handleError(event.data.statusReason);
          }
          break;
      }
    });
    

    Note: See the Events reference for examples of the payload data returned by these events.

  3. Send configuration
    To customize the appearance of the iframe, send your brand's CSS properties and font information after you receive the IFRAME_READY event.

    function sendConfiguration() {
      const iframe = document.getElementById('cardCaptureFrame');
      iframe.contentWindow.postMessage({
        type: 'CSS_CUSTOM_PROPERTIES',
        properties: {
          '--color-primary': '#0057b8',
          '--surface-main': '#ffffff',
          '--typography-body': '#222222'
        },
        fontInfo: {
          family: 'Open Sans',
          type: 'google',
          weights: ['400', '600', '700'],
          display: 'swap'
        }
      }, '*');
    }
    

CSS variables reference

You can customize the following properties in your CSS_CUSTOM_PROPERTIES payload to match your brand.:

VariableDescription
--color-primaryPrimary brand color
--color-secondarySecondary/accent color
--surface-mainMain background color
--typography-bodyBody text color
--font-familyFont family name
--external-gap-xHorizontal outer padding
--external-gap-yVertical outer padding
--between-formitems-xHorizontal gap between form items
--between-formitems-yVertical gap between form items
--between-form-and-submitGap between form and submit button
--c-alert-icon-sizeAlert icon size

Optional iframe commands

In addition to the initial CSS configuration, you can send these optional events to the iframe via postMessage to dynamically update its behavior:

  • ui_config: Configure UI behavior, such as forcing mobile or desktop device simulation.
  • color_mode_sync: Programmatically set the iframe's color mode to dark, light, or system.
  • ping: Perform a health check. The iframe will respond with an ack (acknowledgment) and its current status.
  • parent_window_resize: Notify the iframe when the parent window size changes to maintain a responsive layout.

Events reference

Use these event examples to understand the payload data sent from the Card Capture iframe to your applications message listener.

IFRAME_READY

Sent when the iframe initializes.

{
  "type": "IFRAME_READY",
  "data": {
    "timestamp": 1707591234000,
    "url": "https://..."
  },
  "timestamp": 1707591234001
}

APP_READY_TO_SHOW

Sent when the UI is styled and ready to display.

{
  "type": "APP_READY_TO_SHOW",
  "data": {
    "timestamp": 1707591234500,
    "fontLoaded": true,
    "fontFamily": "Open Sans"
  },
  "timestamp": 1707591234501
}

Note: If the iframe fails to load your custom font and relies on a fallback, the data object returns "fontLoaded": false and "fallbackUsed": true.

CREDIT_CARD_SUBMISSION

Sent when the user submits their card information.

Success example:

{
  "type": "CREDIT_CARD_SUBMISSION",
  "success": true,
  "data": {
    "externalAccountLinkId": "585101000008",
    "statusReason": "Visa card validation passed"
  },
  "timestamp": 1707591234000
}

Error example:

{
  "type": "CREDIT_CARD_SUBMISSION",
  "success": false,
  "statusReason": "Data mismatch: [CVV]",
  "timestamp": 1234567890
}
statusReason values

When you receive the CREDIT_CARD_SUBMISSION event, you can use the statusReason field to determine the exact outcome of the submission.

Success values:

  • "Visa card validation passed"
  • "{Network} card validation passed" (e.g., "Mastercard card validation passed")

Data mismatch failures (one or more fields):

  • Data mismatch:[CVV]
  • Data mismatch:[Name]
  • Data mismatch:[Address]
  • Data mismatch:[CVV, Name]
  • Data mismatch:[Name, Address]
  • Data mismatch:[CVV, Name, Address]

Validation failed values:

  • [Network Failure]
  • [System Failure]

Handling submissions

When the account holder clicks the submit button, your listener receives the CREDIT_CARD_SUBMISSION event. The iframe validates submissions and may reject them for issues like invalid card numbers (Luhn check failure), missing CVVs, invalid dates, or unsupported card types.

Submission flow

This flow describes the synchronous exchange that occurs after the account holder submits the form:

  1. The account holder inputs their debit card information directly into the iframe and clicks submit.
  2. The Card Capture service creates an external account link with the card details in pending status and kicks off an internal validation workflow.
    Note: The iframe manages this polling state entirely internally; you do not receive webhooks or notifications while the account link is pending.
  3. Upon resolution, the Card Capture service sends a CREDIT_CARD_SUBMISSION event to your application via the postMessage API.
  4. Your application listener receives the event and checks the success field.
    a. If success: false, you use the provided statusReason to display the specific error to the account holder.
    b. If success: true, your application passes the externalAccountLinkId to your backend server.
  5. You store the externalAccountLinkId in your database for the future transfer requests.
  6. You use the externalAccountLinkId to create a funds transfer.

Security considerations

To maintain the integrity of the card capture process and protect sensitive cardholder data, you must implement the following security measures:

  • Origin validation — You must validate the event.origin property in your production message handlers to ensure your application only accepts data from your Galileo core domain.
  • Sandbox attributes — You must keep the sandbox attributes on the iframe to maintain a secure environment for the card capture session.
  • HTTPS requirement — You must use HTTPS for all URLs and communication in your production environment.
  • Secure token exchange — Your system must call the Get External Account Link Access endpoint server-to-server to generate the session JWT.
  • Sensitive data handling — You do not receive sensitive card details (PAN or CVV) through postMessage events. The iframe transmits this data server-to-server directly from the user's browser to Galileo's PCI-compliant environment.
  • Message listener safety — Your listener must only process specific Galileo event types, such as CREDIT_CARD_SUBMISSION, to prevent unauthorized script execution.

By using this iframe, the PAN and CVV data are transmitted directly from the user's browser to Galileo's PCI-compliant environment.



© Galileo Financial Technologies, LLC 2026    Privacy Disclosure

All documentation, including but not limited to text, graphics, images, and any other content, are the exclusive property of Galileo Financial Technologies, LLC and are protected by copyright laws. These materials may not be reproduced, distributed, transmitted, displayed, or otherwise used without the prior written permission of Galileo Financial Technologies, LLC. Any unauthorized use or reproduction of these materials are expressly prohibited.