Skip to content
Last updated

Introduction

On a Display allows you to generate a one-time usage digital QR code and show it on a consumer-facing screen. Your consumers scan the QR code with their preferred payment application and confirm the transaction.

Process Flow

The following section outlines the key steps involved in a "On a Display" Instore payment with Bancontact Payconiq. The process involves several key parties, each playing a specific role in completing the transaction.

Prerequisites

  • API Key – This is used to secure the request between the Merchant’s backend and Bancontact Payconiq’s backend. Do not share your API keys in public areas such as online sites or client-side code.
  • Merchant CallbackUrl (Optional) – This URL will be called by Bancontact Payconiq’s backend servers in order to send the status of the payment to the merchant.

Involved Parties

The following parties participate in a display-based in-store payment with Bancontact Payconiq:

  • Payer Application: The consumer's preferred payment app used to complete the transaction.
  • Merchant Frontend: The consumer-facing screen (e.g., POS or tablet) where the QR code is displayed.
  • Merchant Backend: The merchant’s server-side system that integrates with Bancontact Payconiq.
  • Bancontact Payconiq Backend: The backend system responsible for handling payment processing and integration services.

Step-by-Step Payment Flow

This section outlines a typical “On a Display” in-store payment flow using Bancontact Payconiq. The process begins when the transaction is initiated at the merchant’s location and ends when both the merchant and the consumer receive the final confirmation.

On a Display can be used with or without the "Void Functionality". Void is an intermediary step that allows your backend to remain in the lead of a payment transaction after your consumer has confirmed the payment.

With Void, you will be required to individually acknowledge each payment within a maximum of seven (7) calendar days. If a payment is voided, your consumer will be automatically refunded.

Important Note: in case Void is required, it should be specified upon contract signature. The functionality needs to be activated by our Support Team.

The initial steps are identical whether the Void feature is enabled or disabled. Differences between the two flows are clearly presented in the comparison table that follows.

Common Initial Steps

  • The merchant frontend sends payment creation details to the merchant backend. Request should at least contain the payment amount.
  • The merchant backend issues a REST request to the Bancontact Payconiq backend to create the payment, providing parameters like amount, currency, description, and other relevant parameters.
  • The Bancontact Payconiq backend responds with the created payment ID and other relevant details, including a unique QR code URL.
  • The merchant backend forwards the QR code URL to the merchant frontend, which displays it for the consumer.
  • The Payer app scans the QR code and sends a request to retrieve payment details from the backend.
  • The Bancontact Payconiq backend sends payment details to the Payer App, including merchant name and amount to pay.
  • The consumer confirms the payment using PIN, fingerprint, or face ID. The app then submits the payment request to the backend for authorization.

Flow Differences: Void Enabled vs. Void Disabled

Void DisabledVoid Enabled
A payment response is sent back to the Payer App, indicating whether the payment was successful or failed.The consumer is debited, and the payment enters a PENDING_MERCHANT_ACKNOWLEDGEMENT state, awaiting confirmation from the merchant backend.
The Bancontact Payconiq backend sends a payment notification with the payment status to the merchant backend via the configured callback URL.The Bancontact Payconiq backend sends a callback to the Merchant backend with the payment status. The merchant can also poll for updates.
The merchant frontend displays the payment confirmation status.The consumer is prompted in the app to check the consumer-facing screen for the final payment status.
The merchant backend sends a positive acknowledgment to indicate successful processing.
The Bancontact Payconiq backend marks the payment as SUCCEEDED and initiates a payout to the merchant.
The merchant frontend displays the final confirmation to the consumer.
The Payer App notifies the consumer of the final payment outcome.

Important Note: The order in which the merchant and consumer receive payment status notifications is not guaranteed. Network and connectivity differences may cause one party to receive the update before the other.

Payment Flow Diagrams

In the following diagrams you will find a visual overview of the process flows presented above:

Flow Diagram - Void Disabled

VOID DISABLED

Flow Diagram - Void Enabled

VOID ENAABLED

Implementation Guide

Please follow the below steps to successfully implement "On a Display" on your or consumer facing display.

For the full endpoint documentation, please refer to the Merchant Payment API.

1. Create Payment

In order to initiate a payment, you will first have to create it through Bancontact Payconiq via a POST request. Each request will result in a unique payment identifier which will be valid for two minutes (120 seconds).

If the payment does not take place within these two minutes, a new payment must be created.

📦 Request Body

Important Note: for On a Display the returnURL is not necessary.

referencestring<= 35 characters
bulkIdstring<= 35 characters

Field used to reference a bulk batch, so the merchant can inform how the payments should be bulked. If it's not set here it will default to the one configured in the profile.

amountinteger(int64)( 1 .. 999999999999 ]required

Amount in cents requested

currencystring(Currency)

Currency code. Only EUR is supported ISO 4217

Default "EUR"
Value"EUR"
descriptionstring<= 140 characters
identifyCallbackUrlstring^https:\/\/([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}(:\d...

Callback url to which merchants will be notified about the payment identification. If it's not set here it will default to the one configured in the profile

callbackUrlstring^https:\/\/([a-zA-Z0-9-:]+\.)+[a-zA-Z]{2,}(:\...

callbackUrl to which the merchant will be notified about the payment payout. If it's not set here it will default to the one set in the profile

returnUrlstring[ 1 .. 2048 ] characters^https:\/\/([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}(:\d...

Merchant return url to which the dynamic payment page will redirect after the payment is completed

voucherEligibilityArray of objects(VoucherEligibleAmount)Deprecated

List of Value Added Services (vouchers) eligible amounts within the payment

📥 Response

Important Note: for On a Display the checkout link will not be provided in the response.

paymentIdstring= 24 charactersrequired

Payment ID

statusstringrequired

the status of the payment created

Value"PENDING"
createdAtstring(date-time)required

the creation time of the payment

expiresAtstring(date-time)required

the time from which the payment will be expired

descriptionstring
referencestring
amountinteger(int64)( 1 .. 999999999999 ]required

Amount in cents requested

currencystring(Currency)required

Currency code. Only EUR is supported ISO 4217

Default "EUR"
Value"EUR"
creditorobject(PaymentCreditorResponse)required

Creditor account set to receive the payment

creditor.​profileIdstring

The configuration ID of the Merchant

creditor.​merchantIdstring

the Id of the merchant

creditor.​namestring

Merchant's company name that will be shown to the debtor

creditor.​ibanstring

Creditor's Bank Account Iban to where the money will be sent to for this current payment

creditor.​identifyCallbackUrlstring

callbackUrl to which the merchant will be notified about the payment identification

creditor.​callbackUrlstring

callbackUrl to which the merchant will be notified about the payment payout

_linksobject(Links)required

Provides information to navigate to our REST interfaces dynamically, by including hypermedia links to them. Note that for some links inclusion depends on the status of the payment (e.g. cancel link will be available on PENDING and refund on SUCCEEDED)

_links.​selfobject(Link)required
_links.​self.​hrefstringrequired
_links.​deeplinkobject(Link)required
_links.​deeplink.​hrefstringrequired
_links.​qrcodeobject(Link)required
_links.​qrcode.​hrefstringrequired
_links.​cancelobject(Link)
_links.​refundobject(Link)
_links.​checkoutobject(Link)

🔧 Error Codes for create

HTTP StatusCodeMeaning
400BODY_MISSINGA json needs to be provided
400FIELD_IS_REQUIREDField X is mandatory
400FIELD_IS_INVALIDField X is invalid
401UNAUTHORIZEDuser does not have an access token
403ACCESS_DENIEDThe JWT could not be verified (different format) - The JWT does not contain the required authority to access the resource requested
404MERCHANT_PROFILE_NOT_FOUNDThe merchant profile does not exist
422UNABLE_TO_PAY_CREDITORVariable reason(Depends on automatic processing).
500TECHNICAL_ERRORTechnical error in Payment service
503TRY_AGAIN_LATERone of the internal services is unavailable

🔍 Sample Request – create payment

curl -i -X POST \
  https://merchant.api.preprod.bancontact.net/v3/payments \
  -H 'Authorization: YOUR_API_KEY_HERE' \
  -H 'Content-Type: application/json' \
  -d '{
    "reference": "19848995",
    "bulkId": "Bulk-1-200",
    "amount": 1,
    "currency": "EUR",
    "description": "string",
    "identifyCallbackUrl": "https://api.merchant.bancontact.net/identify",
    "callbackUrl": "https://api.merchant.bancontact.net/payment",
    "returnUrl": "https://api.merchant.bancontact.net/payment",
    "voucherEligibility": [
      {
        "voucherSchemes": [
          "BEL_MEAL_VOUCHER"
        ],
        "amount": 1013
      }
    ]
  }'

2. The Bancontact Payconiq QR Code

To display the Bancontact Payconiq QR code, you can render the URL from the attribute _links.self.href received in the Create Payment response in a web view. By doing so, you will make use of Bancontact Payconiq's QR code generation service and will generate by default a small, magenta QR code (cf. Brand Guidelines).

Important: the format, size and colour of the QR code can be modified if necessary using the parameters below. Please make sure to read our Brand Guidelines for more guidance on the minimum sizes and scanning distances.

AttributeDescription
f
[String :: Enum]
Allowed Values: SVG, PNG
Image format
s
[String :: Enum]
Allowed Values: S, M, L, XL
Image size of the QR code to generate.
Small (S) = 180x180
Medium (M) = 250x250
Large (L) = 400x400
Extra Large (XL) = 800x800
The sizes only applies to PNG format.
cl
[String :: Enum]
Allowed Values: magenta, black
The colour of the QR code.
Default is magenta.

3. The Bancontact Payconiq Callback

You can specify a callback URL where the Bancontact Payconiq backend will send notifications about the status of a payment. This will allow you to take appropriate action and process the payment data.

The merchant backend must verify that the notification message originated from Bancontact Payconiq backend was not altered or corrupted during the transmission. To do so, please ensure signature validation.

For the full Callback documentation, please refer to the Callback Guide.

📦 Request Body

paymentIdstring= 24 charactersrequired

PaycBancontact Payconiq Company Payment ID

currencystringrequired

Only EUR is supported currently

Default "EUR"
amountinteger(int64)required

Requested amount in cents

descriptionstring
referencestring
createdAtstring(date-time)required

When the payment was created

expireAtstring(date-time)

When the payment is going to expire. After that date the payment can't be confirmed anymore

succeededAtstring(date-time)

if the payment is SUCCEEDED, then this field represents the date-time on which the payment was SUCCEEDED

statusstring(MerchantPaymentStatus)required
StatusDescription
PENDINGThe merchant has created the payment and and is pending to proceed with identify step.
IDENTIFIEDThe user has scanned the payment's QR code with the Payconiq By Bancontact APP.
AUTHORIZEDThe user has confirmed the payment and the bank authorized it.
AUTHORIZATION_FAILEDThe authorization with the bank failed.
FAILEDSomething went wrong during the payment process(e.g authorization failed).
SUCCEEDEDThe payment has succeeded.
CANCELLEDWhen the payment has been canceled after the user has scanned it, or the merchant has cancelled the payment.
EXPIREDThe payment has expired.
PENDING_MERCHANT_ACKNOWLEDGEMENTThe payment is waiting for the merchant to acknowledge.
VOIDEDThe payment has been voided
Enum"PENDING""IDENTIFIED""AUTHORIZED""AUTHORIZATION_FAILED""SUCCEEDED""FAILED""CANCELLED""EXPIRED""PENDING_MERCHANT_ACKNOWLEDGEMENT""VOIDED"
debtorobjectrequired

Customer that paid

debtor.​ibanstringrequired

Debtor's IBAN masked

debtor.​namestring

Debtor's first name

📥 Response

(No defined response schema)

🔍 Sample Request – callback

curl -i -X POST \
  https://merchant.api.preprod.bancontact.net/callback \
  -H 'Content-Type: application/json' \
  -H 'Signature: YOUR_API_KEY_HERE' \
  -H 'User-Agent: Payconiq' \
  -d '{
    "paymentId": "5f91483d-78a7-4914-bc6f=",
    "currency": "EUR",
    "amount": 0,
    "description": "string",
    "reference": "19848995",
    "createdAt": "2019-08-24T14:15:22Z",
    "expireAt": "2019-08-24T14:15:22Z",
    "succeededAt": "2019-08-24T14:15:22Z",
    "status": "PENDING",
    "debtor": {
      "iban": "*************12636",
      "name": "John"
    }
  }'

Callback Failure

In the event you do not receive a callback or the callback validation fails, please refer to "Get Payment Details". This alternative will also allow you to confirm the status of a transaction in order to complete the payment.

4. Get Payment Details

By calling this endpoint you can obtain the details of an existing payment transaction by passing the unique payment ID.

Note: it is highly recommended to implement this call as a fallback option if callback fails.

🧩 Path Parameters

  • id (string, required)

📥 Response

paymentIdstring= 24 charactersrequired

id of the payment

createdAtstring(date-time)required

the creation time of the payment

expireAtstring(date-time)required

the time from which the payment will be expired

succeededAtstring(date-time)

if the payment is SUCCEEDED, then this field represents the date-time on which the payment was SUCCEEDED

currencystring(Currency)required

Currency code. Only EUR is supported ISO 4217

Default "EUR"
Value"EUR"
statusstring(MerchantPaymentStatus)required
StatusDescription
PENDINGThe merchant has created the payment and and is pending to proceed with identify step.
IDENTIFIEDThe user has scanned the payment's QR code with the Payconiq By Bancontact APP.
AUTHORIZEDThe user has confirmed the payment and the bank authorized it.
AUTHORIZATION_FAILEDThe authorization with the bank failed.
FAILEDSomething went wrong during the payment process(e.g authorization failed).
SUCCEEDEDThe payment has succeeded.
CANCELLEDWhen the payment has been canceled after the user has scanned it, or the merchant has cancelled the payment.
EXPIREDThe payment has expired.
PENDING_MERCHANT_ACKNOWLEDGEMENTThe payment is waiting for the merchant to acknowledge.
VOIDEDThe payment has been voided
Enum"PENDING""IDENTIFIED""AUTHORIZED""AUTHORIZATION_FAILED""SUCCEEDED""FAILED""CANCELLED""EXPIRED""PENDING_MERCHANT_ACKNOWLEDGEMENT""VOIDED"
creditorobject(PaymentCreditorResponse)required

Creditor account set to receive the payment

creditor.​profileIdstring

The configuration ID of the Merchant

creditor.​merchantIdstring

the Id of the merchant

creditor.​namestring

Merchant's company name that will be shown to the debtor

creditor.​ibanstring

Creditor's Bank Account Iban to where the money will be sent to for this current payment

creditor.​identifyCallbackUrlstring

callbackUrl to which the merchant will be notified about the payment identification

creditor.​callbackUrlstring

callbackUrl to which the merchant will be notified about the payment payout

debtorobject
amountinteger(int64)required

Amount in cents originally requested. If no amount was requested by creditor, this will be 0

descriptionstring

merchant's description of the payment

messagestring

debtor's message of the payment

referencestring
bulkIdstring

Field used to reference a bulk batch, so the merchant can choose how to bulk the payments. Mandatory if merchant profile does have bulking enabled, otherwise will miss from the response. If it's not set in the create call it will default to the value configured in the profile if it exists, otherwise its value will be defaulted by the application.

_linksobject(Links)

Provides information to navigate to our REST interfaces dynamically, by including hypermedia links to them. Note that for some links inclusion depends on the status of the payment (e.g. cancel link will be available on PENDING and refund on SUCCEEDED)

🔧 Error Codes for merchant-get-payment

HTTP StatusCodeMeaning
401UNAUTHORIZEDcaller does not have an api-key access token
403ACCESS_DENIEDapi-key access token is invalid, creditor it's not a participant of the requested payment
404PAYMENT_NOT_FOUNDno payment could be found
500TECHNICAL_ERRORTechnical error in Payment service

🔍 Sample Request – merchant-get-payment

curl -i -X GET \
  'https://merchant.api.preprod.bancontact.net/v3/payments/{id}' \
  -H 'Authorization: YOUR_API_KEY_HERE'

5. Get Payment List

You can also retrieve a list of payments by specifying how many records to return, as well as a filter on the results for the total number of records returned per page.

📦 Request Body

fromstring(date-time)

default is today - 1day (yesterday)

tostring(date-time)
paymentStatusesArray of strings(MerchantPaymentStatus)
Items Enum"PENDING""IDENTIFIED""AUTHORIZED""AUTHORIZATION_FAILED""SUCCEEDED""FAILED""CANCELLED""EXPIRED""PENDING_MERCHANT_ACKNOWLEDGEMENT""VOIDED"
referencestring

📥 Response

sizeinteger>= 0required

Size of the elements returned in current page

totalPagesintegerrequired

Total number of pages in the backend for the list requested

totalElementsintegerrequired

Total number of elements in the list requested

numberintegerrequired

Current page number

detailsArray of objects(GetPaymentResponse)
HTTP StatusCodeMeaning
401UNAUTHORIZEDcaller does not have an api-key access token
403ACCESS_DENIEDapi-key access token is invalid, creditor it's not a participant of the requested payment
500TECHNICAL_ERRORTechnical error in Payment service
curl -i -X POST \
  'https://merchant.api.preprod.bancontact.net/v3/payments/search?page=0&size=10' \
  -H 'Authorization: YOUR_API_KEY_HERE' \
  -H 'Content-Type: application/json' \
  -d '{
    "from": "2019-08-24T14:15:22Z",
    "to": "2019-08-24T14:15:22Z",
    "paymentStatuses": [
      "PENDING"
    ],
    "reference": "19848995"
  }'

6. Void Payment

Important Note: Void Functionality is not yet available on our new Merchant API. Void will be available end of September 2025.

Void is an intermediary step that allows your backend to remain in the lead of a payment transaction after your consumer has confirmed the payment.

You will be required to individually acknowledge each payment within a maximum of seven (7) calendar days. If a payment is voided, your consumer will be automatically refunded.

If Void is enabled, the following three scenarios are possible

6.1 Void Payment - Happy Flow

  • Merchant creates a payment via Payconiq and displays the Payconiq QR code.
  • Consumer scans the QR code to retrieve payment information.
  • Consumer signs (enter pin/fingerprint/FaceId) the payment successfully.
  • The consumer is debited, and the payment is in a state that is pending an acknowledgment (PENDING_MERCHANT_ACKNOWLEDGEMENT) from the merchant/terminal.
  • Payconiq sends a callback to the merchant to notify them about the status of the payment. The merchant can also poll Payconiq for the status of the payment.
  • Towards the consumer we will inform them to check the terminal for the final status of the payment.
  • The merchant terminal sends a positive acknowledgement for the payment to indicate that the terminal processed the payment successfully.
  • Payconiq marks the payment as SUCCEEDED and initiates a payout to the merchant.
  • Payconiq updates the consumer about the status of the payment.

🧩 Path Parameters

  • id (string, required)

📦 Request Body

currencystring(Currency)required

Currency code. Only EUR is supported ISO 4217

Default "EUR"
Value"EUR"
amountinteger(int64)(payment_amount)( 1 .. 999999999999 ]required

Amount in cents requested

referencestring

🔧 Error Codes for merchant-acknowledge

HTTP StatusCodeMeaning
400FIELD_IS_REQUIREDField X is mandatory
400FIELD_IS_INVALIDField X is invalid
401UNAUTHORIZEDcaller does not have an api-key access token
403ACCESS_DENIEDThe JWT could not be verified or does not contain the required authority to access the resource requested
404PAYMENT_NOT_FOUNDno payment could be found for the supplied identifier
422PAYMENT_VOIDEDPayment is already voided
500TECHNICAL_ERRORTechnical error in Payment service
503SERVICE_UNAVAILABLEPayment service could not be reached or some unexpected error occurred

🔍 Sample Request – merchant-acknowledge

curl -i -X POST \
  'https://merchant.api.preprod.bancontact.net/v3/payments/{id}/acknowledge' \
  -H 'Authorization: YOUR_API_KEY_HERE' \
  -H 'Content-Type: application/json' \
  -d '{
    "currency": "EUR",
    "amount": 1,
    "reference": "19848995"
  }'

6.2 Void Payment - Unhappy Flow, Merchant Void

  • Merchant creates a payment via Payconiq and displays the Payconiq QR code.
  • Merchant creates a payment via Payconiq and displays the Payconiq QR code.
  • Consumer scans the QR code to retrieve payment information.
  • Consumer signs (enter pin/fingerprint/FaceId) the payment successfully.
  • The consumer is debited, and the payment is in a state that is pending an acknowledgment (PENDING_MERCHANT_ACKNOWLEDGEMENT) from the merchant/terminal.
  • Payconiq sends a callback to the merchant to notify them about the status of the payment. The merchant can also poll Payconiq for the status of the payment.
  • Towards the consumer we will inform them to check the terminal for the final status of the payment.
  • The merchant terminal cancels the payment because something went wrong while processing the payment on the terminal.
  • Payconiq marks the payment as VOIDED and initiates a payout to the consumer.
  • Payconiq updates the consumer about the status of the payment.

🧩 Path Parameters

  • id (string, required) — Payconiq Payment Id

🔧 Error Codes for delete-payment

HTTP StatusCodeMeaning
401UNAUTHORIZEDuser does not have an access token
403ACCESS_DENIEDaccess token is invalid
403CALLER_NOT_ALLOWED_TO_CANCELif caller is not a participant of the payment
404PAYMENT_NOT_FOUNDpayment is not found in the system
422PAYMENT_NOT_PENDINGpayment is not in pending or identify state
500TECHNICAL_ERRORTechnical error in Payment service

🔍 Sample Request – delete-payment

curl -i -X DELETE \
  'https://merchant.api.preprod.bancontact.net/v3/payments/{id}' \
  -H 'Authorization: YOUR_API_KEY_HERE'

6.2 Void Payment - Unhappy Flow, Timeout

  • Consumer scans the QR code to retrieve payment information.
  • Consumer signs (enter pin/fingerprint/FaceId) the payment successfully.
  • The consumer is debited, and the payment is in a state that is pending an acknowledgment (PENDING_MERCHANT_ACKNOWLEDGEMENT) from the merchant/terminal.
  • Payconiq sends a callback to the merchant to notify them about the status of the payment. The merchant can also poll Payconiq for the status of the payment.
  • Towards the consumer we will inform them to check the terminal for the final status of the payment.
  • The merchant terminal does not send a positive acknowledgement/cancel the payment in the X hours timeout.
  • Payconiq marks the payment as VOIDED and initiates a payout to the consumer.
  • Payconiq updates the consumer about the status of the payment.

Canceling a Payment

Endpoint delete-payment can be used to cancel a created payment that is still in status PENDING. The endpoint can also be used to cancel a payment in IDENTIFIED status, as long as the consumer has not initiated payment confirmation.

🧩 Path Parameters

  • id (string, required) — Payconiq Payment Id

🔧 Error Codes for delete-payment

HTTP StatusCodeMeaning
401UNAUTHORIZEDuser does not have an access token
403ACCESS_DENIEDaccess token is invalid
403CALLER_NOT_ALLOWED_TO_CANCELif caller is not a participant of the payment
404PAYMENT_NOT_FOUNDpayment is not found in the system
422PAYMENT_NOT_PENDINGpayment is not in pending or identify state
500TECHNICAL_ERRORTechnical error in Payment service

🔍 Sample Request – delete-payment

curl -i -X DELETE \
  'https://merchant.api.preprod.bancontact.net/v3/payments/{id}' \
  -H 'Authorization: YOUR_API_KEY_HERE'