# Integrate Payconiq by Bancontact

This tutorial shows you how to integrate Payconiq by Bancontact (opens new window) payments using Chargebee.js. Payconiq by Bancontact is a European mobile payment solution that enables customers to pay by scanning QR codes with their smartphone app.

# Supported regions

Payconiq by Bancontact is available in:

  • Belgium
  • Netherlands
  • Luxembourg

# What you'll build

By the end of this tutorial, you'll have a working integration that:

  • Creates payment intents for Payconiq by Bancontact.
  • Handles Payconiq payment flow.
  • Creates subscriptions after successful payment authorization.

# Prerequisites

Before you begin, ensure you have enabled Payconiq by Bancontact (opens new window) via Adyen in Chargebee Billing.

# Setting up Chargebee JS

# Inserting chargebee.js script in your application

Include the following script in your HTML page. You need to do this only once per page.

<script src="https://js.chargebee.com/v2/chargebee.js"></script> 
1

# Initializing a Chargebee instance

Inside your JavaScript code, initialize chargebee with the publishable key (opens new window) once the page is loaded and get 'chargebee instance' object. This object is used further to create components.

Example:

var cbInstance = Chargebee.init({
	site: "site-name", // your test site
	domain: "https://mybilling.acme.com" // this is an optional parameter.
    publishableKey: "test__"
})
1
2
3
4
5

Learn more about ​​initializing a Chargebee instance.

# Create a payment intent

About `payment_intent`

A payment_intent resource manages a customer's payment session. It tracks the amount, currency, payment status, and failed payment attempts, and helps prevent duplicate charges for the same session. The payment_intent automatically updates its status based on authorization and capture events, and issues refunds if an error occurs after payment.

# Server-side implementation

Security

Always create payment intents on your server to protect sensitive information.

Create a payment intent using the Create Payment Intent API (opens new window):

curl https://{site-name}.chargebee.com/api/v2/payment_intents \
    -u {fullaccess_api_key}: \
    -d amount=500 \
    -d currency_code="EUR" \
    -d payment_method_type="payconiq_by_bancontact"
1
2
3
4
5

# Client-side implementation

Call your server endpoint from the frontend:

function createPaymentIntent() {
	return fetch('/payment-intents', {
		method: 'POST',
		headers: {
			"Content-Type": "application/json"
		},
		body: JSON.stringify({
			amount: 500,
			currency_code: 'EUR',
			payment_method_type: 'payconiq_by_bancontact'
		})
	}).then(function(response) {
		return response.json();
	}).then(function(responseJson) {
		return responseJson.payment_intent;
	});
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# Implement the payment flow

# Step 1: Load the payment method

Load the Payconiq by Bancontact integration using the load method:

cbInstance.load("payconiq_by_bancontact")
1

# Step 2: Handle the payment

Use the handlePayment method to initiate the payment process.

cbInstance.load("payconiq_by_bancontact").then(() => {
	cbInstance.handlePayment("payconiq_by_bancontact", {
		paymentIntent: () => {
			return createPaymentIntent();
		},
		renderInfo: {
  		    heading: "Scan QR code",
            timerLabel: "This QR code is valid for {time}", // timer will be reflected in place of {time}
            timerDurationSeconds: 15 * 60, // 15 minutes
            buttonText: "Continue to Payconiq by Bancontact",
		}
	}).then(intent => {
		// Payment intent is pending - customer needs to scan QR code
		return createSubscription(intent.id);
	}).catch(err => {
		console.error('Payment failed:', err);
	});
});

function createSubscription(paymentIntentId) {
	return fetch('/subscriptions', {
		method: 'POST',
		headers: {
			"Content-Type": "application/json"
		},
		body: JSON.stringify({
			paymentIntentId: paymentIntentId,
			plan_id: 'pro_plan',
			plan_quantity: 1,
			billingAddress: {
				// Add billing address details
			},
			customer: {
				// Add customer details
			}
		})
	}).then(response => response.json());
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

TIP

For complete parameter documentation, see the API Reference.

# Step 3: Monitor payment status

After calling handlePayment, the payment intent status is pending while the customer scans the QR code. You need to poll the payment intent status until it becomes authorized or fails.

Use the Retrieve payment intent API (opens new window) to check the status:

async function waitForAuthorization(intentId, MAX_RETRIES = 10) {
  for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {
    const response = await fetch(`/payment-intents/${intentId}`, {
      method: "GET",
      headers: {
        "Content-Type": "application/json"
      }
    });
    
    const intent = await response.json();
    const status = intent?.payment_intent?.status;
    
    if (status === "authorized") {
      return intent.payment_intent;
    }
    if (status === "failed") {
      throw new Error(`Payment ${status}`);
    }
    
    // If not done, wait before the next attempt
    await new Promise(r => setTimeout(r, 2000));
  }
  throw new Error(`Authorization not received after ${MAX_RETRIES} retries`);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# Payment status reference

For detailed information about payment intent statuses, see the Payment Intent API documentation (opens new window).

Status Description Action
inited Payment intent created Not applicable in this flow
in_progress Customer is scanning QR code Continue polling
authorized Payment successful Create subscription
consumed Payment used for subscription Do not reuse
expired Payment timed out Show error, allow retry
failed Payment failed Show error, allow retry

Using webhooks

Use webhooks (opens new window) for production use, instead of making the subscription creation request from the client-side, it's more secure and reliable to respond to webhooks from Chargebee on the server-side. Listen to the payment_intent_updated (opens new window) event via webhooks and create the subscription when the payment_intent.status (opens new window) is authorized.

# Create a subscription (server)

Pass the ID of the successfully authorized payment_intent to Chargebee’s create a subscription API (opens new window).

  • Curl