Accept a payment - Ideal

Securely handling ideal payments

Ideal is a payment method that is a common payment method in the Netherlands.

This integration combines all of the steps required to creating a payment intent with Ideal as well as handling the result.

1. Create

First, you need a Stripe account. Register now.

Server-side

This integration requires endpoints on your server that talk to the Stripe API. Use one official libraries for access to the Stripe API from your server. Follow the steps to create an Ideal payment here. For a full list of supported banks check here.

Client-side

The Flutter SDK is open source, fully documented.

To install the SDK, follow these steps:

  • Run the commmand flutter pub add flutter_stripe
  • This will add a line like this to your project's pubspec.yaml with the latest package version

For details on the latest SDK release and past versions, see the Releases page on GitHub. To receive notifications when a new release is published, watch releases for the repository.

When your app starts, configure the SDK with your Stripe publishable key so that it can make requests to the Stripe API.

void main() async {
  Stripe.publishableKey = stripePublishableKey;
  runApp(const App());
}

Use your test mode keys while you test and develop, and your live mode keys when you publish your app.

2. Add an endpoint [Server Side]

First you need to create a PaymentIntent on your backend server. A paymentintent is an object that represents your intent to collect a payment from a customer and tracks the lifecycle of the payment process through each stage.

Checkout the example implementation for your server in the official stripe docs

Returns the Payment Intent’s client secret, to your app.

3. Collect the payment details [Client Side]

There are 2 ways to collect payment details in the Stripe sdk:

  • By using the payment sheet
  • Using the Sdk's webview and present the bank's website or app.

By using the payment sheet

Before displaying the payment sheet, your checkout page should:

  • Show the products being purchased and the total amount
  • Collect any required shipping information
  • Include a checkout button to present Stripe’s UI

Next, integrate Stripe’s prebuilt payment UI into your app’s checkout.

First you need to inititalize the payment sheet

Future<void> initPaymentSheet() async {
    try {
      // 1. create payment intent on the server
      final data = await _createTestPaymentSheet();

      // 2. initialize the payment sheet
     await Stripe.instance.initPaymentSheet(
        paymentSheetParameters: SetupPaymentSheetParameters(
          // Enable custom flow
          customFlow: true,
          // Main params
          merchantDisplayName: 'Flutter Stripe Store Demo',
          paymentIntentClientSecret: data['paymentIntent'],
          // Customer keys
          customerEphemeralKeySecret: data['ephemeralKey'],
          customerId: data['customer'],
          // Extra options
          testEnv: true,
          applePay: true,
          googlePay: true,
          style: ThemeMode.dark,
          merchantCountryCode: 'DE',
        ),
      );
      setState(() {
        _ready = true;
      });
    } catch (e) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Error: $e')),
      );
      rethrow;
    }
}

When the customer taps a Checkout button, call present to present the payment sheet. After the customer completes the payment, the sheet is dismissed.

await Stripe.instance.presentPaymentSheet();

Unless your business model requires immediate payment (e.g., an on-demand service), don’t assume you have received payment at this point. Instead, inform the customer that you confirmed their order and notify them by email when you fulfill their order in the next step.

Using the Sdk's webview

Step1: configure the callback url

The Stripe sdk specificies safepay/ as the host for the return URL for bank redirect methods. After the customer completes the payment this callback url will be called using your custom url scheme. To specify a custom url scheme and how to handle it checkout the official Flutter docs.

After you have specified the custom scheme make sure to specify it in the initialization parameters of the Flutter Stripe sdk

  Stripe.publishableKey = stripePublishableKey;
  Stripe.urlScheme = 'flutterstripe';
  await Stripe.instance.applySettings();

Step2: Create a screen that opens the webview

Unless your business model requires immediate payment (e.g., an on-demand service), don’t assume you have received payment at this point. Instead, inform the customer that you confirmed their order and notify them by email when you fulfill their order in the next step. Before displaying the payment sheet, your checkout page should:

  • Show the products being purchased and the total amount
  • Collect any required shipping information
  • Include a checkout button to launch the SDK's webview (see example below) and handle the result or errors.
Future<void> _pay(BuildContext context) async{
    try {
      await Stripe.instance.confirmPayment(
        clientSecret,
        PaymentMethodParams.ideal(bankName: kIsWeb ? 'revolut' : null),
      );
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(
          content: Text('Payment succesfully completed'),
        ),
      );
    } on Exception catch (e) {
      if (e is StripeException) {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(
            content: Text('Error from Stripe: ${e.error.localizedMessage}'),
          ),
        );
      } else {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(
            content: Text('Unforeseen error: ${e}'),
          ),
        );
      }
    }
}

 @override
  Widget build(BuildContext context) {
    return ExampleScaffold(
      title: 'Ideal',
      tags: ['Payment method'],
      padding: EdgeInsets.all(16),
      children: [
        LoadingButton(
          onPressed: () async {
           await pay(context);
          },
          text: 'Pay',
        ),
      ],
    );
  }

4. Handle post-payment events

Stripe sends a payment_intent.succeeded event when the payment completes. Use the Dashboard, a custom webhook, or a partner solution to receive these events and run actions, like sending an order confirmation email to your customer, logging the sale in a database, or starting a shipping workflow.

Listen for these events rather than waiting on a callback from the client. On the client, the customer could close the browser window or quit the app before the callback executes. Setting up your integration to listen for asynchronous events also makes it easier to accept more payment methods in the future. Check out our guide to payment methods to see the differences between all supported payment methods.

5. Test the integration

If you are using your test Api key stripe will show a test page after confirming the intent. You can choose yourself whether or not to authorize or fail the payment. For more info about testing check the Stripe docs.