# Regional considerations Learn about regional considerations for integrating Terminal in different countries. ​​For the most part, you’ll be able to use a single Terminal integration in all supported countries. However, due to local payment methods or regulations there are some country-specific requirements. After going through the [sample integration](https://docs.stripe.com/terminal/quickstart.md), use this guide to learn about country-specific requirements for Terminal. > To process Terminal payments, both the Stripe account receiving the funds and the [location](https://docs.stripe.com/terminal/fleet/locations-and-zones.md) associated with the reader must be in the same country, accepting local currency only. ## Availability Refer to the following table to understand which readers you can use in each country. | Country | [Smart readers](https://docs.stripe.com/terminal/smart-readers.md) | [Mobile readers](https://docs.stripe.com/terminal/mobile-readers.md) | [Tap to Pay](https://docs.stripe.com/terminal/payments/setup-reader/tap-to-pay.md) | | ----------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | | US | - BBPOS WisePOS E - Stripe Reader S710 - Stripe Reader S700 - Verifone readers (Public preview) | - Stripe Reader M2 | - Tap to Pay on Android - Tap to Pay on iPhone | | - AU - BE - NZ | - BBPOS WisePOS E - Stripe Reader S710 - Stripe Reader S700 | - BBPOS WisePad 3 | - Tap to Pay on Android - Tap to Pay on iPhone | | CA | - BBPOS WisePOS E - Stripe Reader S710 - Stripe Reader S700 - Verifone readers (Public preview) | - BBPOS WisePad 3 | - Tap to Pay on Android - Tap to Pay on iPhone | | - IE - GB | - BBPOS WisePOS E - Stripe Reader S710 - Stripe Reader S700 - Verifone V660p, UX700, P630 (Private preview) | - BBPOS WisePad 3 | - Tap to Pay on Android - Tap to Pay on iPhone | | SG | - BBPOS WisePOS E - Stripe Reader S710 - Stripe Reader S700 - Verifone V660p, P630 (Private preview) | - BBPOS WisePad 3 | - Tap to Pay on Android - Tap to Pay on iPhone | | - AT - CZ - DK - FI - FR - IT - LU - NL - NO - PL - PT - ES - SE - CH | - BBPOS WisePOS E - Stripe Reader S710 - Stripe Reader S700 | - BBPOS WisePad 3 | - Tap to Pay on Android - Tap to Pay on iPhone | | DE | - BBPOS WisePOS E - Stripe Reader S700 | - BBPOS WisePad 3 | - Tap to Pay on Android - Tap to Pay on iPhone | | JP | - Stripe Reader S700 | - BBPOS WisePad 3 | - Tap to Pay on iPhone | | MY | - BBPOS WisePOS E - Stripe Reader S710 - Stripe Reader S700 | - BBPOS WisePad 3 | - Tap to Pay on Android - Tap to Pay on iPhone (Public preview) | | - LI - CY - EE - HR - LT - LV - MT - SI - SK - HU - RO - BG | | | - Tap to Pay on Android - Tap to Pay on iPhone | | - GI | | | - Tap to Pay on Android | ## Regional considerations by country Select a country to view its specific regional considerations # Canada (CA) ## Integrate Terminal in Canada Stripe supports Visa, Mastercard, American Express, Discover, and [Interac](https://docs.stripe.com/terminal/payments/regional.md?integration-country=CA#interac-payments) payments in Canada. All transactions must be made in Canadian dollars (CAD). To accept Terminal charges in Canada, either your platform account or connected account must be in Canada. ### Use locations Create [Locations](https://docs.stripe.com/api/terminal/locations/create.md) for your business with addresses in CA and [associate your readers to them](https://docs.stripe.com/terminal/fleet/locations-and-zones.md). This will ensure that they automatically download the configuration needed to properly process charges in CA. A valid [address for a Location](https://docs.stripe.com/api/terminal/locations/create.md#create_terminal_location-address) in CA must contain the properties. #### curl ```bash curl https://api.stripe.com/v1/terminal/locations \ -u <>: \ -d "display_name"="HQ" \ -d "address[line1]"="3040 Bur Oak Ave" \ -d "address[city]"="Markham" \ -d "address[state]"="ON" \ -d "address[country]"="CA" \ -d "address[postal_code]"="L6B 0R1" \ ``` ### Reader software version BBPOS WisePad 3 readers must use the reader software version `4.01.04.00_Prod_NA_off_v30_480001` or later. Read about [BBPOS WisePad 3 software updates](https://docs.stripe.com/terminal/payments/connect-reader.md?reader-type=bluetooth#update-reader) for details. ### Translation [Language regulations](http://www.legisquebec.gouv.qc.ca/en/showdoc/cs/C-11#ga:l_i-gb:l_vii-h1) require that services, including point-of-sale services, be provided in French unless English has been agreed upon by the cardholder and their card issuer. Terminal is built to help you comply with these requirements if they apply to your business. #### Default reader language The [BBPOS WisePOS E](https://docs.stripe.com/terminal/readers/bbpos-wisepos-e.md) and [Stripe Reader S700/S710](https://docs.stripe.com/terminal/readers/stripe-reader-s700-s710.md) support changing reader language in the Settings panel. Swipe right across the screen to access the Settings panel, and select your language. The [BBPOS WisePad 3](https://docs.stripe.com/terminal/readers/bbpos-wisepad3.md) supports changing reader language directly in the reader interface. After you have registered your reader to a [Location](https://docs.stripe.com/api/terminal/locations.md) with an address in CA, the reader installs a language pack relevant for your region if one isn’t already in place. To view available language options and to select a language, click the **Power / Settings** button and scroll down using the arrow keys until you reach the language selection menu. Highlight your desired language and press the green **Enter** key. #### Transaction language After the cardholder has presented their card, the reader determines the cardholder’s preferred language. Each screen after that point is translated according to the cardholder’s preferences. #### Other translations If you’re required to provide services in or would like to translate text into French in addition to English, ensure that any of your [custom reader screens](https://docs.stripe.com/terminal/features/display.md) and [receipts](https://docs.stripe.com/terminal/features/receipts.md) display the appropriate translations. ## Interac payments Interac is the interbank network that handles routing of debit payments in Canada. Consumer debit cards in Canada are branded with an Interac logo and might also be co-branded with another payment network’s logo. Even if the card is co-branded, however, all Interac debit transactions must be routed through Interac. To maximize card acceptance, you should build Interac support into your integration. > Interac isn’t supported while [operating offline](https://docs.stripe.com/terminal/features/operate-offline/overview.md). ### Create a PaymentIntent To accept Interac transactions you need to create your payments using the `interac_present` payment method type. Include the `card_present` payment method type as well if you accept Visa, Mastercard, and American Express payments. > Learn more about the [in-person PaymentIntent flow](https://docs.stripe.com/terminal/payments/collect-card-payment.md). **Client-side** Create a `PaymentIntent` from your client using one of the following options: #### Server-driven > Client-side `PaymentIntent` creation is possible with the iOS, Android, and React Native SDKs. If you’re using the server-driven integration, create a `PaymentIntent` server-side. #### JavaScript > Client-side `PaymentIntent` creation is possible with the other client SDKs. If you’re using the JavaScript SDK for Stripe Terminal, create a `PaymentIntent` server-side. #### iOS - [createPaymentIntent (iOS)](https://stripe.dev/stripe-terminal-ios/docs/Classes/SCPTerminal.html#/c:objc\(cs\)SCPTerminal\(im\)createPaymentIntent:completion:) #### Swift ```swift import UIKit import StripeTerminal class PaymentViewController: UIViewController { // ... // Action for a "Checkout" button func checkoutAction() throws { let params = PaymentIntentParametersBuilder(amount: 1000, currency: "cad") .setPaymentMethodTypes([.cardPresent, .interacPresent]) .build() Terminal.shared.createPaymentIntent(params) { createResult, createError in if let error = createError { print("createPaymentIntent failed: \(error)") } else if let paymentIntent = createResult { print("createPaymentIntent succeeded") // ... } } } // ... } ``` #### Android - [createPaymentIntent (Android)](https://stripe.dev/stripe-terminal-android/core/com.stripe.stripeterminal/-terminal/create-payment-intent.html) #### Kotlin ```kotlin val params = PaymentIntentParameters.Builder( listOf( PaymentMethodType.CARD_PRESENT, PaymentMethodType.INTERAC_PRESENT ) ) .setAmount(1000) .setCurrency("cad") .build() Terminal.getInstance().createPaymentIntent( params, object : PaymentIntentCallback { override fun onSuccess(paymentIntent: PaymentIntent) { // Placeholder for handling successful operation } override fun onFailure(e: TerminalException) { // Placeholder for handling exception } } ) ``` #### React Native - [createPaymentIntent (React Native)](https://stripe.dev/stripe-terminal-react-native/api-reference/interfaces/StripeTerminalSdkType.html#createPaymentIntent) ```js const {error, paymentIntent} = await createPaymentIntent({ amount: 1000, currency: "cad", paymentMethodTypes: ["cardPresent", "interacPresent"], }); ``` Alternatively, if you want to use manual capture for other payment methods while still accepting Interac payments (which require automatic capture), use `manual_preferred`: #### Server-driven > Client-side `PaymentIntent` creation is possible with the iOS, Android, and React Native SDKs. If you’re using the server-driven integration, create a `PaymentIntent` server-side. #### JavaScript > Client-side `PaymentIntent` creation is possible with the other client SDKs. If you’re using the JavaScript SDK for Stripe Terminal, create a `PaymentIntent` server-side. #### iOS #### Swift ```swift let cardPresentParams = try CardPresentParametersBuilder() .setCaptureMethod(.manualPreferred) .build() let paymentMethodOptionsParams = try PaymentMethodOptionsParametersBuilder() .setCardPresentParameters(cardPresentParams) .build() let params = try PaymentIntentParametersBuilder(amount: 1000, currency: "cad") .setPaymentMethodTypes([.cardPresent, .interacPresent]) .setPaymentMethodOptionsParameters(paymentMethodOptionsParams) .build() Terminal.shared.createPaymentIntent(params) { createResult, createError in if let error = createError { print("createPaymentIntent failed: \(error)") } else if let paymentIntent = createResult { print("createPaymentIntent succeeded") // ... } } ``` #### Android #### Kotlin ```kotlin val cardPresentParams = CardPresentParameters.Builder() .setCaptureMethod(CardPresentCaptureMethod.ManualPreferred) .build() val paymentMethodOptionsParams = PaymentMethodOptionsParameters.Builder() .setCardPresentParameters(cardPresentParams) .build() val params = PaymentIntentParameters.Builder( listOf( PaymentMethodType.CARD_PRESENT, PaymentMethodType.INTERAC_PRESENT ) ) .setAmount(1000) .setCurrency("cad") .setPaymentMethodOptionsParameters(paymentMethodOptionsParams) .build() Terminal.getInstance().createPaymentIntent( params, object : PaymentIntentCallback { override fun onSuccess(paymentIntent: PaymentIntent) { // Placeholder for handling successful operation } override fun onFailure(e: TerminalException) { // Placeholder for handling exception } } ) ``` #### React Native ```js const {error, paymentIntent} = await createPaymentIntent({ amount: 1000, currency: "cad", paymentMethodTypes: ["cardPresent", "interacPresent"], paymentMethodOptions: { captureMethod: "manual_preferred", }, }); ``` **Server-side** - [Create a PaymentIntent](https://docs.stripe.com/api/payment_intents/create.md) The JavaScript SDK and the server-driven integration require you to create the `PaymentIntent` on your server. For the other client SDKs, you can create the `PaymentIntent` on your server if the information required to start a payment isn’t readily available in your app. ```curl curl https://api.stripe.com/v1/payment_intents \ -u "<>:" \ -d amount=999 \ -d currency=cad \ -d "payment_method_types[]=card_present" \ -d "payment_method_types[]=interac_present" \ -d capture_method=automatic ``` Alternatively, if you want to use manual capture for other payment methods while still accepting Interac payments (which require automatic capture), use `manual_preferred`: ```curl curl https://api.stripe.com/v1/payment_intents \ -u "<>:" \ -d amount=999 \ -d currency=cad \ -d "payment_method_types[]=card_present" \ -d "payment_method_types[]=interac_present" \ -d "payment_method_options[card_present][capture_method]=manual_preferred" ``` ### Collect and process a payment After you [process the payment](https://docs.stripe.com/terminal/payments/collect-card-payment.md), the reader determines whether to route the payment across Interac rails based on the profile of the card presented. In cases where the Interac card is co-branded, the `payment_method_details.interac_present.brand` field on a PaymentIntent’s returned [charge](https://docs.stripe.com/api/charges/object.md#charge_object-payment_method_details-interac_present-brand) reports the co-brand. The type field on the `payment_method` for an Interac transaction is always `interac_present`. There are further Interac requirements that Stripe handles automatically for you, without additional integration work on your side: - Before a card is presented, on-screen prompts are in the default reader language. After the card information has been collected, the localization is based on the language preference specified by the presented card. - The reader automatically prompts for PIN in cases where it’s required. - Interac Flash (contactless) payments are limited to 250 CAD and generally up to three consecutive transactions. Transactions higher than 100 CAD or the fourth contactless transaction in a row require the customer to insert their Interac card and enter their PIN. ### Capture and reconcile Interac only supports payments that are authorized and captured in a single step. Unlike networks like Visa and Mastercard, Interac doesn’t support placing a “hold” on a card and capturing the funds later. Only payments with `automatic`, `automatic_async`, or `manual_preferred` capture type can be processed on Interac. | Capture type | Implementation | Result | | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **automatic** | Set [​capture_method](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-capture_method) on the PaymentIntent to `automatic`. | All card payments are authorized and captured in a single step. | | **automatic\_async** | Set [​capture_method](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-capture_method) on the PaymentIntent to `automatic_async`. | All card payments are authorized and captured asynchronously in a single step. | | **manual\_preferred** | Set [​capture_method](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-payment_method_options-card_present-capture_method) on the nested `payment_method_options.card_present` attribute to `manual_preferred`. | Interac card payments are authorized and captured in a single step. Non-Interac card payments are authorized only. To [capture the funds](https://docs.stripe.com/terminal/payments/collect-card-payment.md?terminal-sdk-platform=server-driven#capture-payment), make a separate request. | | **manual** | Set [​capture_method](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-capture_method) on the PaymentIntent to `manual`. | Interac card payments are always declined. Non-Interac card payments are authorized only. To [capture the funds](https://docs.stripe.com/terminal/payments/collect-card-payment.md?terminal-sdk-platform=server-driven#capture-payment), make a separate request. | Make sure that your application doesn’t continue to capture the `PaymentIntent` for Interac transactions. If you attempt to capture an `interac_present` payment, the Stripe API returns an error. Make sure that you prevent unintended and duplicate payments in your integration; if failures or declines occur while processing Interac, you can attempt to re-use the same `PaymentIntent` from the original transaction to safeguard against double-charging. > As of the `2025-03-31.basil` API version, `interac_present` payments require the [capture_method](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-capture_method) parameter to be set to `automatic`, `automatic_async`, or `manual_preferred` on the `PaymentIntent`. ### Refund an Interac payment In-person refunds are mandatory for Interac transactions in Canada. You can’t create refunds in the API or in the Dashboard for these payments. In this flow, the reader prompts the cardholder to present the card used in the original charge. After the card details are read successfully, your application processes the refund. Like online refunds, you can perform partial refunds by passing in an amount less than the transaction value. The currency and the card used for refund processing must match those of the original charge, otherwise the request fails with an error. As a fallback, you can offer refunds to different payment methods such as store credit or cash. #### Server-driven To initiate an in-person refund for an Interac payment, call the [refund_payment](https://docs.stripe.com/api/terminal/readers/refund_payment.md) endpoint: ```curl curl https://api.stripe.com/v1/terminal/readers/tmr_xxx/refund_payment \ -u "<>:" \ -d payment_intent=pi_xxx \ -d amount=2000 ``` The [status of the reader action](https://docs.stripe.com/api/terminal/readers/object.md#terminal_reader_object-action-status) is `in_progress`, as shown in the following example, until the customer presents a card on the reader: ```json { "id": "tmr_xxx", "object": "terminal.reader", "action": {"type": "refund_payment", "refund_payment": { "payment_intent": "pi_xxx" }, "status": "in_progress" "failure_code": null, "failure_message": null }, … } ``` If you’re using a [simulated reader](https://docs.stripe.com/terminal/payments/collect-card-payment.md?terminal-sdk-platform=server-driven&reader=simulated), you can simulate payment method presentment with the [present_payment_method](https://docs.stripe.com/api/terminal/readers/present_payment_method.md) endpoint: ```curl curl https://api.stripe.com/v1/test_helpers/terminal/readers/tmr_xxx/present_payment_method \ -u "<>:" \ -d type=interac_present ``` A successful refund generates a [terminal.reader.action_succeeded](https://docs.stripe.com/api/events/types.md#event_types-terminal.reader.action_succeeded) event. The reader’s `action.status` value changes to `succeeded`, and the `action.refund_payment` has a [refund](https://docs.stripe.com/api/terminal/readers/object.md#terminal_reader_object-action-refund_payment-refund) attribute under it. A failed refund generates a [terminal.reader.action_failed](https://docs.stripe.com/api/events/types.md#event_types-terminal.reader.action_failed) event. The reader’s `action.status` value changes to `failed`, and the [action.failure_code](https://docs.stripe.com/api/terminal/readers/object.md#terminal_reader_object-action-failure_code) and [action.failure_message](https://docs.stripe.com/api/terminal/readers/object.md#terminal_reader_object-action-failure_message) properties each have a detailed failure explanation under them. The `action.refund_payment` property won’t have a `refund` attribute set under it. We recommend using [webhooks](https://docs.stripe.com/terminal/payments/collect-card-payment.md?terminal-sdk-platform=server-driven#webhooks) to track when the reader action status changes. #### JavaScript ```javascript const result = await this.terminal.collectRefundPaymentMethod( "ch_xxxxxxxxxx", 2000, "cad" ); if (result.error) { // Placeholder for handling result.error } else { const refund = await this.terminal.processRefund(); if (refund.error) { // Placeholder for handling refund.error } else { console.log("Charge fully refunded!"); return refund; } } ``` #### iOS #### Swift ```swift let refundParams = try RefundParametersBuilder( chargeId: "ch_1FLyVV2eZvKYlo2C9Z8rmX02", amount: 1000, currency: "cad" ).build() self.refundCancelable = Terminal.shared.processRefund(refundParams) { processedRefund, processError in if let error = processError { print("processRefund failed. \(error)") } else if let refund = processedRefund, refund.status == .succeeded { print("processRefund successful! \(refund)") } else { print("Refund pending or unsuccessful.") } } ``` #### Android #### Kotlin ```kotlin val refundParams = RefundParameters.ByChargeId( id = "ch_1FLyVV2eZvKYlo2C9Z8rmX02", amount = 1000, currency = "cad" ).build() val refundCancelable = Terminal.getInstance().processRefund( refundParams, object : RefundCallback { override fun onSuccess(refund: Refund) { if (refund.status == "succeeded") { println("processRefund successful!") } else { println("Refund pending or unsuccessful.") } } override fun onFailure(e: TerminalException) { // Placeholder for handling exception } } ) ``` #### React Native ```js const { refund, error } = await processRefund({ chargeId: 'ch_1FLyVV2eZvKYlo2C9Z8rmX02', amount: 2000, currency: 'cad', }); if (error) { // Handle error return; } if (!refund || refund.status !== 'succeeded') { // Refund pending or unsuccessful. return; } // Process refund successful! ```