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:
-
Authorization — You request a session token (JWT) from Galileo to authorize the session. See Authorization steps for more details.
-
Iframe session — You embed the iframe using the JWT provided by Galileo.
-
Capture — The account holder inputs their card information directly into the Galileo-hosted iframe, which creates an
externalAccountLinkId. -
Decision — Galileo performs CVV, address, and name validations through Visa to confirm the cardholder. The Card Capture UI triggers the
CREDIT_CARD_SUBMISSIONevent to signify when the external account link passes validation. -
Execution — Use the
externalAccountLinkIdto 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.
-
The account holder requests to link their account.
-
Use the Get External Account Link Access endpoint to start the access token creation process with these parameters:
accountNo— PRN of the account on your platformintegration—GALILEO_CARD_CAPTURE
-
The Card Capture service validates the request and generates a fully formed, signed JWT.
-
Galileo returns a response to your server where the value field contains the JWT.
-
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:
-
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=falseparameter to your URL. -
Listen for messages
The iframe communicates with your parent page using thewindow.postMessageAPI. You must configure your system to listen for the iframe lifecycle and submission results below.Event type Description 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 externalAccountLinkIdon 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.
-
Send configuration
To customize the appearance of the iframe, send your brand's CSS properties and font information after you receive theIFRAME_READYevent.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.:
| Variable | Description |
|---|---|
--color-primary | Primary brand color |
--color-secondary | Secondary/accent color |
--surface-main | Main background color |
--typography-body | Body text color |
--font-family | Font family name |
--external-gap-x | Horizontal outer padding |
--external-gap-y | Vertical outer padding |
--between-formitems-x | Horizontal gap between form items |
--between-formitems-y | Vertical gap between form items |
--between-form-and-submit | Gap between form and submit button |
--c-alert-icon-size | Alert 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
statusReason valuesWhen 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:
- The account holder inputs their debit card information directly into the iframe and clicks submit.
- 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. - Upon resolution, the Card Capture service sends a
CREDIT_CARD_SUBMISSIONevent to your application via thepostMessageAPI. - Your application listener receives the event and checks the success field.
a. Ifsuccess: false, you use the providedstatusReasonto display the specific error to the account holder.
b. Ifsuccess: true, your application passes theexternalAccountLinkIdto your backend server. - You store the
externalAccountLinkIdin your database for the future transfer requests. - You use the
externalAccountLinkIdto 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.originproperty 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
HTTPSfor 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
postMessageevents. 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.
Updated about 3 hours ago
