Skip to main content
After creating a payment request, embed the Quidkey bank selection iframe on your checkout page alongside your existing Stripe Payment Element. Customers choose between Stripe or Quidkey, and you route the payment based on their selection.

Add the Iframe

Add the iframe using the payment_token from the create step. Place it near your Stripe Payment Element so customers see both options. If the Quidkey API call fails, keep your page in its default Stripe-only state.
<iframe
  id="quidkey-iframe"
  src="https://core.quidkey.com/api/v1/embedded?payment_token=YOUR_PAYMENT_TOKEN"
  title="Quidkey checkout"
  style="width:100%;height:108px;border:0;overflow:hidden"
  loading="lazy"
></iframe>
Quidkey will automatically predict and pre-select the customer’s bank based on their country and information.

Stripe PaymentIntent

Your existing PaymentIntent creation stays exactly as it is. As long as you already render a single Stripe Payment Element, no backend changes are required.

Dynamic Height

The iframe adjusts its height based on available payment methods and open bank lists. Height calculation:
  • Base: payment_method_count x 54px (includes 1px border per method)
  • With drawer open: Additional 263px when bank selection lists are open
  • Standard markets: 2 payment methods (108px base)
  • Enhanced markets: 3+ payment methods (162px+ base) — e.g., Portugal with Multibanco
JavaScript:
window.addEventListener('message', (event) => {
  if (event.data.type === 'quidkey-state-update' && event.data.dynamicHeight) {
    document.documentElement.style.setProperty(
      '--quidkey-dynamic-height',
      event.data.dynamicHeight
    );
  }
});
CSS:
:root {
  --quidkey-dynamic-height: 108px; /* Default for 2 methods */
}

.quidkey-element-container {
  position: relative;
  overflow: hidden;
  width: 100%;
  height: var(--quidkey-dynamic-height);
  min-height: var(--quidkey-dynamic-height);
  box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.03), 0px 3px 6px rgba(0, 0, 0, 0.02);
  transition: height 0.35s !important;
}

.quidkey-element-container iframe {
  border: none;
  height: inherit;
  left: 0;
  overflow: hidden;
  position: absolute;
  top: 0;
  width: 100%;
}

Handle Bank Selection & Stripe Mutual Exclusion

The key behavior is ensuring only one payment method (Stripe or Quidkey) is active at a time. Listen for postMessage events from the iframe to track the customer’s bank selection, and collapse the Stripe Payment Element when Quidkey is active.
// Track which payment method is currently selected
let currentSelection = { source: null, method: null };
let currentPaymentScheme = null;

window.addEventListener('message', (event) => {
  if (event.data.type !== 'quidkey-state-update') return;

  // Update dynamic height
  if (event.data.dynamicHeight) {
    document.documentElement.style.setProperty(
      '--quidkey-dynamic-height',
      event.data.dynamicHeight
    );
  }

  // Track payment scheme
  currentPaymentScheme = event.data.paymentScheme || null;

  // Handle bank selection
  const selectedBankId = event.data.selectedBankId;
  if (selectedBankId) {
    currentSelection = { source: 'quidkey', method: selectedBankId };
    purchaseButton.disabled = false;
  }

  // Collapse Stripe when Quidkey is active
  if (event.data.isListOpen || event.data.isPredictedBankSelected) {
    if (paymentElement) {
      paymentElement.collapse();
    }
  }
});
When the customer interacts with the Stripe Payment Element again, update currentSelection to { source: 'stripe', method: null } using Stripe’s change event listener.

postMessage Fields

FieldTypeDescription
typestringAlways "quidkey-state-update"
selectedBankIdstring | nullSelected bank ID (null if deselected)
paymentSchemestring | nullPayment scheme (e.g., "SEPA_CREDIT_TRANSFER", "MULTIBANCO")
dynamicHeightstringCSS height value (e.g., "108px", "371px")
isListOpenbooleanWhether the bank list drawer is open
isPredictedBankSelectedbooleanWhether Quidkey’s predicted bank is selected

Payment Schemes

The iframe supports multiple payment schemes automatically based on the customer’s country:
  • SEPA — EU-wide credit transfers
  • Faster Payments — UK instant payments
  • Multibanco — Portuguese payment method
Payment Scheme Values:
  • null or undefined — use default scheme for customer’s country
  • "MULTIBANCO" — user explicitly selected Multibanco
  • "SEPA_CREDIT_TRANSFER" — user explicitly selected SEPA
  • Future schemes like "PIX" and "UPI" will work automatically

Route the Purchase Button

When the customer clicks your purchase button, route to either Stripe or Quidkey based on their current selection.
if (currentSelection.source === 'quidkey') {
  const response = await fetch('/api/quidkey/initiate', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      bankId: currentSelection.method,
      paymentToken: quidkeyPaymentToken,
      paymentScheme: currentPaymentScheme
    }),
  });

  const result = await response.json();
  if (result.success && result.payment_link) {
    window.location.href = result.payment_link; // Redirect to bank
  }
}

Quidkey Initiation Backend

Your backend proxies the payment initiation to Quidkey and returns the bank redirect URL:
app.post('/api/quidkey/initiate', async (req, res) => {
  const { bankId, paymentToken, paymentScheme } = req.body;

  const result = await fetch('https://core.quidkey.com/api/v1/embedded/payment-initiation', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${accessToken}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      bankId,
      paymentScheme: paymentScheme || null
    })
  });

  const data = await result.json();
  res.json(data);
});
After the customer authenticates with their bank, they’re redirected to your success_url or failure_url.

Test with Demo Bank

1

Open your checkout page

Load the page in your browser. You should see both the Stripe Payment Element and the Quidkey bank picker. Quidkey will predict and pre-select a demo bank in test mode.
2

Test Quidkey path

Click the Quidkey bank option — the Stripe Payment Element should collapse. Your purchase button should be enabled. Click Purchase, authenticate with any credentials (demo mode), and verify you’re redirected to your success URL.
3

Test Stripe path

Reload and interact with the Stripe Payment Element instead — the Quidkey selection should clear. Confirm the Stripe payment flow works as before.
4

Verify with webhook

Check your webhook endpoint (if configured) for the Quidkey payment confirmation.

Reference Implementation

Next Steps