{"templateId":"markdown","sharedDataIds":{"sidebar":"sidebar-guides/sidebars.yaml"},"props":{"metadata":{"markdoc":{"tagList":["admonition","json-schema"]},"type":"markdown"},"seo":{"title":"One-Way TLS Encryption Support","description":"Discover the API documentation to start developing your Bancontact Pro application","llmstxt":{"hide":false,"sections":[{"title":"Table of contents","includeFiles":["**/*"],"excludeFiles":[]}],"excludeFiles":[]}},"dynamicMarkdocComponents":["openapi"],"compilationErrors":[],"ast":{"$$mdtype":"Tag","name":"article","attributes":{},"children":[{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"danger","name":"New payment URLs"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Following the decommissioning of the Payconiq brand in Belgium, these URL changes are essential to ensure compliance and"," ","mark the final phase in aligning our branding with the new Bancontact Pro identity."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Please implement adaptations ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"/guides/general/payloadurlupdate"},"children":["described here"]}," promptly to avoid service interruptions and guarantee the continued acceptance of mobile payments via Bancontact Pay and Wero."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Changes are already available in our pre-production environement and will be rolled out in production starting ",{"$$mdtype":"Tag","name":"b","attributes":{},"children":["11/05/2026"]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Merchant Callback"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Each merchant may define a specific asynchronous HTTPS confirmation URL (callback URL) through which Bancontact notifies the status of a payment. This enables the merchant's or partner's backend to act upon the payment status (e.g., mark the payment in a database, update stock, send confirmation emails, etc.)."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Callbacks are asynchronous and issued via HTTP POST requests using TLS 1.2 encryption."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["For certain products (e.g., Top Up), a callback URL must be provided at the time of product creation."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"one-way-tls-encryption-support","__idx":0},"children":["One-Way TLS Encryption Support"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["In one-way TLS, Bancontact encrypts callback requests and validates the merchant's server certificate. No certificate exchange is needed beforehand. Callbacks should function out of the box."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Contact: ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"mailto:devsupport@bancontact.com"},"children":["devsupport@bancontact.com"]}," for assistance."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"callback-retry-policy","__idx":1},"children":["Callback Retry Policy"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Bancontact retries sending callbacks for up to ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["24 hours"]}," if an HTTP 200 OK response is not received. Retry triggers include:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["No response within 15 seconds"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["HTTP 429 Too Many Requests"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["HTTP 500 Internal Server Error"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["HTTP 503 Service Unavailable"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["HTTP 504 Gateway Timeout"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["HTTP 509 Bandwidth Limit Exceeded"]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Notes:"]}]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The payment status does not change."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The callback content (headers, body, target URL) remains identical."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Bancontact stops retrying after a 200 OK or after 24 hours."]}]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"callback-headers","__idx":2},"children":["Callback Headers"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Callback requests contain several headers, including:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"http","header":{"controls":{"copy":{}}},"source":"signature: <JWS Signature>\ncontent-type: application/json\nuser-agent: Bancontact Payments/v3\n","lang":"http"},"children":[]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Name"},"children":["Name"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Description"},"children":["Description"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["signature"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["A JSON Web Signature (JWS) in base64url format, digitally signed by Bancontact."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["user-agent"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Identifies the Bancontact callback sender."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["content-type"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Indicates the media type of the payload (application/json)."]}]}]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"callback-signature","__idx":3},"children":["Callback Signature"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["To verify Bancontact-generated callbacks, use the detached ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"https://tools.ietf.org/html/rfc7797"},"children":["JSON Web Signature (JWS)"]}," sent in the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["signature"]}," header."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The JWS includes:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["JOSE Header (base64url encoded)"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["JWS Payload (not included)"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["JWS Signature"]}]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"text","header":{"controls":{"copy":{}}},"source":"jws = base64URLEncode(JOSE Header)..base64URLEncode(Signature(base64URLEncode(JOSE Header) + base64URLEncode(Request Body)))\n","lang":"text"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"jose-header-example","__idx":4},"children":["JOSE Header Example"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"json","header":{"controls":{"copy":{}}},"source":"{\n  \"typ\": \"jose+json\",\n  \"kid\": \"JWK kid\",\n  \"alg\": \"ES256\",\n  \"crit\": [\"https://payconiq.com/sub\", \"https://payconiq.com/iss\", \"https://payconiq.com/iat\", \"https://payconiq.com/jti\", \"https://payconiq.com/path\"],\n  \"https://payconiq.com/sub\": \"{PaymentProfileId}\",\n  \"https://payconiq.com/iss\": \"payconiq\",\n  \"https://payconiq.com/iat\": \"{ISO 8601 UTC Timestamp}\",\n  \"https://payconiq.com/jti\": \"{Unique-request-identifier}\",\n  \"https://payconiq.com/path\": \"https://www.merchantcallback.com/payconiqpayment\"\n}\n","lang":"json"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"signature-verification-steps","__idx":5},"children":["Signature Verification Steps"]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Cache the JWKS from Bancontact."]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Extract ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["kid"]}," from JOSE header."]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Match ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["kid"]}," with cached JWK:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["If matched, verify signature using your preferred library (e.g., jose4j for Java)."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Ensure all ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["crit"]}," headers are present and valid."]}]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["If not matched, fetch and re-cache the JWKS, then repeat step 3."]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"callback-body","__idx":6},"children":["Callback Body"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The body contains JSON with payment status details. Verify the signature before processing this data."]},{"$$mdtype":"Tag","name":"JsonSchema","attributes":{"schema":{"$ref":"../../apis/merchant-payment.openapi.yaml#/components/schemas/merchant-callback"},"options":{},"schemaResolved":{"openapi":"3.1.0","components":{"schemas":{"__root":{"$ref":"#/components/schemas/merchant-callback"},"merchant-payment-status":{"type":"string","title":"MerchantPaymentStatus","description":"| Status | Description |\n|--------|-------------|\n| PENDING | The merchant has created the payment and and is pending to proceed with identify step. |\n| IDENTIFIED | The user has scanned the payment's QR code with the Bancontact Pay. |\n| AUTHORIZED | The user has confirmed the payment and the bank authorized it. |\n| AUTHORIZATION_FAILED | The authorization with the bank failed. |\n| FAILED | Something went wrong during the payment process(e.g authorization failed). |\n| SUCCEEDED | The payment has succeeded. |\n| CANCELLED | When the payment has been canceled after the user has scanned it, or the merchant has cancelled the payment.|\n| EXPIRED | The payment has expired. |\n| PENDING_MERCHANT_ACKNOWLEDGEMENT | The payment is waiting for the merchant to acknowledge. |\n| VOIDED | The payment has been voided |\n","enum":["PENDING","IDENTIFIED","AUTHORIZED","AUTHORIZATION_FAILED","SUCCEEDED","FAILED","CANCELLED","EXPIRED","PENDING_MERCHANT_ACKNOWLEDGEMENT","VOIDED"]},"merchant-callback":{"type":"object","title":"MerchantCallback","properties":{"paymentId":{"type":"string","description":"Bancontact Company Payment ID","minLength":24,"maxLength":24,"examples":["5f91483d-78a7-4914-bc6f="]},"currency":{"type":"string","default":"EUR","description":"Only EUR is supported currently"},"amount":{"type":"integer","description":"Requested amount in cents","format":"int64"},"description":{"type":"string","description":"Description of the payment that will be shown to the debtor, also used in the bank statement for reconciliation purposes. The characters used must comply with the [SEPA Requirements for an Extended Character Set (UNICODE Subset) - Best Practices | European Payments Council](https://www.europeanpaymentscouncil.eu/document-library/guidance-documents/sepa-requirements-extended-character-set-unicode-subset-best).\n"},"reference":{"type":"string","description":"Merchant payment reference, used to reference the Bancontact Company payment in the merchant’s system. The characters used must comply with the [SEPA Requirements for an Extended Character Set (UNICODE Subset) - Best Practices | European Payments Council](https://www.europeanpaymentscouncil.eu/document-library/guidance-documents/sepa-requirements-extended-character-set-unicode-subset-best).\n","examples":["19848995"]},"createdAt":{"type":"string","format":"date-time","description":"When the payment was created"},"expireAt":{"type":"string","format":"date-time","description":"When the payment is going to expire. After that date the payment can't be confirmed anymore"},"succeededAt":{"type":"string","format":"date-time","description":"if the payment is SUCCEEDED, then this field represents the date-time on which the payment was SUCCEEDED"},"status":{"$ref":"#/components/schemas/merchant-payment-status"},"debtor":{"type":"object","description":"Customer that paid","required":["iban"],"properties":{"iban":{"type":"string","description":"Debtor's IBAN masked","examples":["*************12636"]},"name":{"type":"string","description":"Debtor's first name","examples":["John"]}}}},"required":["paymentId","totalAmount","currency","amount","createdAt","status","debtor"]}}}},"schemaResolvedErrors":[]},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"certificates","__idx":7},"children":["Certificates"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Bancontact publishes its public keys in JWKS format:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["PREPROD JWK"]},": ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"https://jwks.preprod.bancontact.net","target":"_blank"},"children":["jwks.preprod.bancontact.net"]}," ",{"$$mdtype":"Tag","name":"br","attributes":{},"children":[]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["PROD JWK"]},": ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"https://jwks.bancontact.net","target":"_blank"},"children":["jwks.bancontact.net"]}," ",{"$$mdtype":"Tag","name":"br","attributes":{},"children":[]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"certificate-rotation","__idx":8},"children":["Certificate Rotation"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Bancontact may rotate its certificate without prior notice."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Merchants who pin certificates must pin only the CN name of the certificate, enabling seamless rotation."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["A new JWK will be added for 24 hours before the old one is removed."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Merchants should cache JWKs for up to 12 hours and re-fetch if verification fails."]}]}]},"headings":[{"value":"One-Way TLS Encryption Support","id":"one-way-tls-encryption-support","depth":2},{"value":"Callback Retry Policy","id":"callback-retry-policy","depth":2},{"value":"Callback Headers","id":"callback-headers","depth":2},{"value":"Callback Signature","id":"callback-signature","depth":2},{"value":"JOSE Header Example","id":"jose-header-example","depth":3},{"value":"Signature Verification Steps","id":"signature-verification-steps","depth":3},{"value":"Callback Body","id":"callback-body","depth":2},{"value":"Certificates","id":"certificates","depth":2},{"value":"Certificate Rotation","id":"certificate-rotation","depth":3}],"frontmatter":{"seo":{"title":"One-Way TLS Encryption Support"}},"lastModified":"2026-03-16T13:20:15.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/guides/general/callback052025","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}