What are co-badged cards?

A co-badged card refers to a debit or credit card that supports multiple card schemes. This is usually:

  • an international network, such as Visa and Mastercard
  • paired with a local brand, like Cartes Bancaires (France) or Dankort (Denmark).

Some regions have specific requirements that must be implemented in order to be compliant with local regulations.

It is your responsibility to meet these compliancy criteria.

Regulations

European Economic Area (EEA)

In the European Union, the Regulation (EU) 2015/751 sets the rules on how merchants should handle co-badged cards.

If you accept one of the following card networks, you are impacted by the regulation and must follow the guidelines outlined below:

  • Bancontact (Belgium)
  • Cartes Bancaires (France)
  • Dankort (Denmark)

Other local card networks are available as co-badged cards in Europe - however only the three above can be used today for online card payments, and therefore are relevant for these guidelines.

Guidelines

Identify the supported card schemes

You do not have to accept all card networks.

However, when the customer is about to enter their card details, you must make it transparent and clear which card networks are accepted.

This can be done by presenting the logo and/or name of all the supported card networks.
If you decide to present the logo, they must have the same clarity, size and quality.

Choice of payment brand

Choice of payment brand

If you accept all the card networks available on the customer’s co-badged card, you must enable the customer to choose which network they want to pay with.

You are free to set a default card network or pre-select one in order to reduce friction and optimize for cost. However, you must always honor the choice of the customer if they decide to override your preference.

In the case of recurring payments, the card network selected by the customer when they first entered their card must be honored for all subsequent payments.

To provide your users with the most seamless UX, we recommend you to use Primer Universal Checkout to automatically detect the networks as the user enters their card number.

Choice of payment brand

Compliancy

This regulation was put in place in 2016.

Visa started conducting audits with the acquirers on the 31st of December 2023.

Failing to comply with the regulation exposes you to penalties defined by the acquirer and the card brand.

It is worth noting that "Bancontact Cards" is for now considered by Primer to be an independent payment method, and not a card network.

Other countries

Some countries outside of the EEA have other regulations related to co-badged cards. This is the case for Australia (with eftpos cards) and Saudi Arabia (with mada cards).

Primer does not support these card networks at the moment. This documentation will be updated when these card networks are added to Primer.

Get started with Drop-in Checkout

This feature is currently not available on Drop-in Checkout

Get started with Headless Checkout

In order to be compliant with the regulations, Headless Checkout enables you to

  • detect the networks of the card number entered by the user
  • retrieve the logo of each card network
  • pass the card network selected by the customer to Primer

This feature is currently not available on React Native

Example projects

Feel free to use these example projects to get started quicker:

Pre-requisites

This guide assumes that you have already integrated a card form with Headless Checkout.

Make sure to follow the "Get Started with Headless Checkout" first.

Step 1. Set the list of supported card networks in the client session

When creating a client session, it is recommended to pass the list of the card networks supported for this particular session. This ensures that the customer is not asked to choose a card network that you do not accept.

The card network should be sorted in order of preference. This enables us to identify the default card network to consider if the user enters a co-badged card.

123456
// POST /client-session{    "paymentMethod": {        "orderedAllowedCardNetworks": ["VISA", "CARTES_BANCAIRES", "MASTERCARD"]    }}
json
copy

With the example above:

  • If the user enters a “Visa & Cartes Bancaires” card, the default network will be Visa
  • If the user enters a “Mastercard & Cartes Bancaires” card, the default network will be Cartes Bancaires

Learn more about orderedAllowedCardNetworks in the API Reference.

Step 2. Detect the card networks

When you pass a full or partial card number by setting rawData on the RawDataManager object, Headless Checkout retrieves the list of card networks available for the card.

Retrieving the cards requires a network call, so primerRawDataManager(_:willFetchMetadataForState:) is called to indicate that the network request has started.

After a response is received, the list of card networks is passed to your integration through a callback called primerRawDataManager(_:didReceiveMetadata:forState:).

123456789101112131415161718
@objc optional    func primerRawDataManager(_ rawDataManager: PrimerHeadlessUniversalCheckout.RawDataManager,                              willFetchMetadataForState state: PrimerValidationState) {        // ... Do nothing, or show a loading spinner ...    }
    @objc optional    func primerRawDataManager(_ rawDataManager: PrimerHeadlessUniversalCheckout.RawDataManager,                              didReceiveMetadata metadata: PrimerPaymentMethodMetadata,                              forState state: PrimerValidationState) {
        if let cardMetadata = metadata as? PrimerCardNumberEntryMetadata {          // ... Display received card networks to the user ...          if let cardState = state as? PrimerCardNumberEntryState {              // ... If you want to check which card number caused the returned card networks ...          }        }    }
swift
copy

This callback returns the following data:

  • source
    Enum value indicating how the card networks were retrieved
    • .local if the card networks come from the SDK, usually by leveraging the first few digits.
    • .remote if the card networks come from Primer's server.
    • .localFallback if Primer's server fails to be reached. This works similarly to .local.
  • detectedCardNetworks.items
    The list of all the detected card networks, including the ones that are not allowed.
  • detectedCardNetworks.preferred
    The first allowed card network in the detected card networks. Can be nil if the user entered a card that is not allowed.
  • selectableCardNetworks?.items
    The list of all the detected card networks that can be selected by the user. selectableCardNetworks is nil if Headless Checkout does not detect a co-badged card.
  • selectableCardNetworks?.preferred
    The card network selected by default, according to the order set in orderedAllowedCardNetworks. selectableCardNetworks is nil if Headless Checkout does not detect a co-badged card.

The card networks returned by primerRawDataManager(_:didReceiveMetadata:forState:) are PrimerCardNetwork objects that contain the network id, its display name, and a flag, allowed, that indicates whether the card network is in orderedAllowedCardNetworks.

Learn more about primerRawDataManager(_:didReceiveMetadata:forState:) in the API reference.

Less than 8 digits

If the user enters less than 8 digits, Headless Checkout cannot detect co-badged cards. Instead, Headless Checkout tries to detect major card networks using data available locally.

In this case:

  • source is set to .local
  • detectedCardNetworks.preferred contains the card network you should present to the user
  • detectedCardNetworks.items contains all the detected card networks
  • selectableCardNetworks is always nil

8 digits or more

If the user enters 8 digits or more, Headless Checkout attempts to make a request to Primer to retrieve the list of card networks available on the card using our BIN data.

In this case:

  • source is set to .remote
  • selectableCardNetworks is only available if the user has entered a co-badged card and both its detected networks are allowed for this session
    • selectableCardNetworks.items contains the list of card networks from which the user can select

If Headless Checkout fails to contact Primer, Headless Checkout falls back to a local detection (similar to when less than 8 digits are entered). In this case, source is set to .localFallback .

Let’s say orderedAllowedCardNetworks is ["CARTES_BANCAIRES", "VISA", "MASTERCARD"]

If the user enters a card that is co-badged Visa and Cartes Bancaires:

  • detectedCardNetworks.items is CARTES_BANCAIRES and VISA
  • detectedCardNetworks.preferred is CARTES_BANCAIRES
  • selectableCardNetworks?.items is CARTES_BANCAIRES and VISA
  • selectableCardNetworks?.preferred is CARTES_BANCAIRES

If the user enters a card that is only Visa:

  • detectedCardNetworks.items is only VISA
  • detectedCardNetworks.preferred is VISA
  • selectableCardNetworks is nil

If the user enters an Amex card (not allowed for this session):

  • detectedCardNetworks.items is only AMEX
  • detectedCardNetworks.preferred is nil
  • selectableCardNetworks is nil

Example

123456789101112131415161718192021222324252627282930313233343536
extension MyViewController: PrimerHeadlessUniversalCheckoutRawDataManagerDelegate {
    func primerRawDataManager(_ rawDataManager: PrimerHeadlessUniversalCheckout.RawDataManager,                              willFetchMetadataForState cardState: PrimerValidationState) {        guard let state = cardState as? PrimerCardNumberEntryState else {            logger.error("Received non-card metadata. Ignoring ...")            return        }        /* ... display spinner ... */    }
    func primerRawDataManager(_ rawDataManager: PrimerHeadlessUniversalCheckout.RawDataManager,                                didReceiveMetadata metadata: PrimerPaymentMethodMetadata,                                forState cardState: PrimerValidationState) {
        guard let metadata = metadata as? PrimerCardNumberEntryMetadata,              let cardState = cardState as? PrimerCardNumberEntryState else {            logger.error("Received non-card metadata. Ignoring ...")            return        }
        var networksForDisplay: [PrimerCardNetwork] = []        var isAllowedNetwork: Bool = true
        if metadata.source == .remote, let selectableNetworks = metadata.selectableCardNetworks?.items, !selectableNetworks.isEmpty {            networksForDisplay = selectableNetworks        } else if let preferredDetectedNetwork = metadata.detectedCardNetworks.preferred {            networksForDisplay = [preferredDetectedNetwork]        } else if let cardNetwork = metadata.detectedCardNetworks.items.first {            networksForDisplay = [cardNetwork]            isAllowedNetwork = false        }
        /* ... networksForDisplay contains the models to display to the user 🎉 ... */    }}
swift
copy

Step 3. Present the list of card networks and handle the selection

It is now your responsibility to present the list of card networks to the customer and enable them to choose the network they want to pay with.

To support you, Headless Checkout exposes the logos and human readable names of each card network via the AssetsManager.

12345678
let cardAssets: [PrimerCardNetworkAsset] = networksForDisplay.compactMap { network in  return PrimerHeadlessUniversalCheckout.AssetsManager.getCardNetworkAsset(for: network)}
cardAssets.forEach { asset in  // ... display the card, e.g. ... */  showCard(title: asset.displayName, image: asset.cardImage)}
swift
copy

When the user selects a card network, set rawData, passing the relevant card network to let us know which the customer chose.

123456789
let selectedCardNetwork: CardNetwork = primerCardNetwork.value // Enum value for the network
rawDataManager?.rawData = PrimerCardData(    cardNumber: cardNumber,    expiryDate: expiryDate,    cvv: cvvNumber,    cardholderName: cardholderName,    cardNetwork: selectedCardNetwork // pass the enum value here)
swift
copy

Learn more about getCardNetworkAsset(for:) in the API Reference.

Step 4. Create a payment with the selected card network

When the user clicks on “Pay”, call the submit function to start the payment.

1
rawDataManager.submit()
swift
copy

If the card network was not provided via rawData, Primer follows the order of preference given by the option orderedAllowedCardNetworks passed in the client session API.

Testing co-badged cards

Primer Sandbox Processor supports a few co-badged test cards to enable you to test your integration.

You can find them in the list of test card payments.

Integrations

This is the current list of integrations that provide support for co-badged cards:

  • Worldline SIPs
  • Stripe

Notes

Slow and unreliable internet connection

When the customer's network connection is slow or unreliable, it is possible that the customer finishes entering their card details before Universal Checkout retrieves the card networks.

In order to keep the friction low, it is important to note that Universal Checkout does not block the creation of a payment while the card networks are being retrieved or if the card networks could not be retrieved at all.

This means that, if a co-badged card is entered, the customer is not guaranteed to be presented a card choice before they submit their card details.

Selected card network on the payment method data

In the case of a card payment, you can get the selected network by looking at paymentMethodData.network.

We recommend against using paymentMethodData.binData.network as it only contains the international card network.