SOFORT Payments with Sources

    Use Sources to accept payments using SOFORT, a popular payment method in Europe.

    Stripe users in Europe can use Sources—a single integration path for creating payments using any supported method—to accept SOFORT payments from customers in the following countries:

    • Austria
    • Belgium
    • Germany
    • Italy
    • Netherlands
    • Spain

    During the payment process, a Source object is created and your customer is redirected to the SOFORT web interface for authentication of their banking credentials. After completing this, your integration uses the source to make a charge request and complete the payment.

    SOFORT is a is a push-based, single-use and asynchronous method of payment. This means your customer takes action to send the amount to you through a redirect and it can take up to 14 days to confirm the success or failure of a payment.

    Step 1: Create a Source object

    A Source object is either created client-side using Stripe.js or server-side using the Source creation endpoint, with the following parameters:

    Parameter Value
    type sofort
    amount A positive integer in the smallest currency unit representing the amount to charge the customer (e.g., 1099 for a €10.99 payment).
    currency eur (SOFORT must always use Euros)
    redirect[return_url] The URL the customer should be redirected to after the authorization process.
    sofort[country] The ISO-3166 2-letter country code of the customer’s bank.
    statement_descriptor (optional) A custom statement descriptor for the payment.

    To create a source with Stripe.js, first include the library within your website and set your publishable API key. Once included, use the following createSource method to create a source client-side:

    stripe.createSource({
      type: 'sofort',
      amount: 1099,
      currency: 'eur',
      redirect: {
        return_url: 'https://shop.example.com/crtA6B28E1',
      },
      sofort: {
        country: 'DE',
      },
    }).then(function(result) {
      // handle result.error or result.source
    });
    

    Using either method, Stripe returns a Source object containing the relevant details for the specified method of payment.

    {
      "id": "src_16xhynE8WzK49JbAs9M21jaR",
      "object": "source",
      "amount": 1099,
      "client_secret": "src_client_secret_UfwvW2WHpZ0s3QEn9g5x7waU",
      "created": 1445277809,
      "currency": "eur",
      "flow": "redirect",
      "livemode": true,
      "owner": {
    See all 38 lines "address": null, "email": null, "name": "Jenny Rosen", "phone": null, "verified_address": null, "verified_email": null, "verified_name": "Jenny Rosen", "verified_phone": null }, "redirect": { "return_url": "https://shop.example.com/crtA6B28E1", "status": "pending", "url": "https://pay.stripe.com/redirect/src_16xhynE8WzK49JbAs9M21jaR?client_secret=src_client_secret_UfwvW2WHpZ0s3QEn9g5x7waU" }, "statement_descriptor": null, "status": "pending", "type": "sofort", "usage": "single_use", "sofort": { "country": "DE", "bank_code": null, "bic": null, "bank_name": null, "iban_last4": null, "preferred_language": null, "statement_descriptor": null } }

    Source creation in mobile applications

    If you’re building an iOS or Android app, you can implement sources using our mobile SDKs. Refer to our sources documentation for iOS or Android to learn more.

    Optional: Providing a custom statement descriptor

    SOFORT requires a statement descriptor before the customer is redirected to authenticate the payment. By default, your Stripe account’s statement descriptor is used (you can review this in the Dashboard). You can provide a custom descriptor by specifying statement_descriptor when creating a source. SOFORT statement descriptors support a maximum of 35 characters and cannot contain the special characters /, (, ), {, or }.

    stripe.createSource({
      type: 'sofort',
      amount: 1099,
      currency: 'eur',
      statement_descriptor: 'ORDER AT11990',
      redirect: {
        return_url: 'https://shop.example.com/crtA6B28E1',
      },
      sofort: {
        country: 'DE',
      },
    }).then(function(result) {
      // handle result.error or result.source
    });
    

    Providing a custom statement descriptor within a subsequent charge request has no effect.

    Error codes

    Source creation for SOFORT payments may return any of the following errors:

    Error Description
    payment_method_not_available The payment method is currently not available. You should invite your customer to fallback to another payment method to proceed.
    processing_error An unexpected error occurred preventing us from creating the source. The source creation should be retried.
    invalid_amount The source amount is invalid. SOFORT enforces a minimum payment amount of 1 EUR.
    invalid_sofort_country The owner’s country is not supported by SOFORT. The countries supported are listed above.

    Step 2: Have the customer authorize the payment

    When creating a source, its status is initially set to pending and cannot yet be used to create a charge. Your customer must authorize a SOFORT payment to make the source chargeable. To allow your customer to authorize the payment, redirect them to the URL provided within the redirect[url] attribute of the Source object.

    After the authorization process, your customer is redirected back to the URL provided as a value of redirect[return_url]. This happens regardless of whether authorization was successful or not. If the customer has authorized the payment, the Source object’s status is updated to chargeable and it is ready to use in a charge request. If your customer declines the payment, the status transitions to failed.

    Stripe populates the redirect[return_url] with the following GET parameters when returning your customer to your website:

    • source: a string representing the original ID of the Source object
    • livemode: indicates if this is a live payment, either true or false
    • client_secret: used to confirm that the returning customer is the same one who triggered the creation of the source (source IDs are not considered secret)

    You may include any other GET parameters you may need when specifying redirect[return_url]. Do not use the above as parameter names yourself as these would be overridden with the values we populate.

    Mobile applications

    # If you are integrating SOFORT within a mobile application, you can use your application URI scheme when providing a value for redirect[return_url] so that your customers are returned to your app after they have completed authentication. Refer to our sources documentation for iOS or Android to learn more.

    Testing the redirect process

    When creating a Source object using your test API keys, you can follow the URL returned in the redirect[url] field. This leads to a Stripe page that displays information about the API request and you can either authorize or cancel the payment. Authorizing the payment redirects you to the URL specified in redirect[return_url].

    Step 3: Charge the Source

    Once the customer has authenticated the payment, the source’s status transitions to chargeable and it can be used to make a charge request. This transitions happens asynchronously and may occur after the customer was redirected back to your website.

    Some customers using SOFORT assume that the order process is complete once they have authenticated the payment and received confirmation from their bank. This results in customers who close their browser instead of following the redirect and returning to your app or website.

    For these reasons it is essential that your integration rely on webhooks to determine when the source becomes chargeable in order to create a charge. Please refer to our best practices for more details on how to best integrate payment methods using webhooks.

    Webhooks

    The following webhook events are sent to notify you about changes to the source’s status:

    Event Description
    source.chargeable A Source object becomes chargeable after a customer has authenticated and verified a payment.
    source.failed A Source object failed to become chargeable as your customer declined to authenticate the payment.
    source.canceled A Source object expired and cannot be used to create a charge.

    Make a charge request using the source

    Once the source is chargeable, from your source.chargeable webhook handler, you can make a charge request using the source ID as the value for the source parameter to complete the payment.

    curl https://api.stripe.com/v1/charges \
       -u sk_test_BQokikJOvBiI2HlWgH4olfQ2: \
       -d amount=1099 \
       -d currency=eur \
       -d source=src_18eYalAHEMiOZZp1l9ZTjSU0
    
    # Set your secret key: remember to change this to your live secret key in production
    # See your keys here: https://dashboard.stripe.com/account/apikeys
    Stripe.api_key = "sk_test_BQokikJOvBiI2HlWgH4olfQ2"
    
    charge = Stripe::Charge.create({
      amount: 1099,
      currency: 'eur',
      source: 'src_18eYalAHEMiOZZp1l9ZTjSU0',
    })
    
    # Set your secret key: remember to change this to your live secret key in production
    # See your keys here: https://dashboard.stripe.com/account/apikeys
    stripe.api_key = "sk_test_BQokikJOvBiI2HlWgH4olfQ2"
    
    charge = stripe.Charge.create(
      amount=1099,
      currency='eur',
      source='src_18eYalAHEMiOZZp1l9ZTjSU0',
    )
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    \Stripe\Stripe::setApiKey("sk_test_BQokikJOvBiI2HlWgH4olfQ2");
    
    $charge = \Stripe\Charge::create(array(
      "amount" => 1099,
      "currency" => "eur",
      "source" => "src_18eYalAHEMiOZZp1l9ZTjSU0",
    ));
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    Stripe.apiKey = "sk_test_BQokikJOvBiI2HlWgH4olfQ2";
    
    Map<String, Object> chargeParams = new HashMap<String, Object>();
    chargeParams.put("amount", 1099);
    chargeParams.put("currency", "eur");
    chargeParams.put("source", "src_18eYalAHEMiOZZp1l9ZTjSU0");
    
    Charge charge = Charge.create(chargeParams);
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    var stripe = require("stripe")("sk_test_BQokikJOvBiI2HlWgH4olfQ2");
    
    stripe.charges.create({
      amount: 1099,
      currency: "eur",
      source: "src_18eYalAHEMiOZZp1l9ZTjSU0",
    }, function(err, charge) {
      // asynchronously called
    });
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    stripe.Key = "sk_test_BQokikJOvBiI2HlWgH4olfQ2"
    
    chargeParams := &stripe.ChargeParams{
      Amount: 1099,
      Currency: "eur",
    }
    chargeParams.SetSource("src_18eYalAHEMiOZZp1l9ZTjSU0")
    ch, err := charge.New(chargeParams)
    

    SOFORT Sources are single-use and cannot not be used recurring or additional payments. Refer to our Sources & Customers guide for more information on how single-use Sources interact with Customers.

    Step 4: Confirm that the charge has succeeded

    Since SOFORT is an asynchronous payment method, the Charge object’s status remains in a pending state for up to 14 days from its creation (also known as the cut-off date). Once the charge is confirmed—and the funds guaranteed—its status is updated to succeeded. Either of the following events are sent when the charge’s status is updated:

    Event Description
    charge.succeeded The charge succeeded and the payment is complete.
    charge.failed The charge has failed and the payment could not be completed.

    We recommend that you rely on these webhook events to notify your customer of their payment status. Please refer to our best practices for more details on how to best integrate payment methods using webhooks.

    Failed charges

    If a charge has not been confirmed within the cut-off time, the charge’s status is automatically transitioned from pending to failed. Additionally, if the funds are received after the cut-off date, the customer is automatically refunded.

    On average, approximately 0.2% of SOFORT charges can be expected to fail. This may vary based on your industry or customer base. Depending on your average payment amount, the type of products or service being provided, and risk associated with your business, you may prefer to fulfil orders only once the charge.succeeded webhook has been received.

    Refunding a pending charge

    You can perform a refund against charges that are still pending and have not yet been confirmed. If you create a full or partial refund on a pending charge, the refund is performed only after the charge’s status is transitioned to succeeded. In the event of the charge transitioning to status failed, full and partial refunds will be marked as canceled, as the money never left the customer’s bank account.

    Testing charge success and failure

    You can mimic a successful or failed charge by creating a test source with one of the following values for the owner[name] parameter. Use this source to create a test charge that either succeeds or fails.

    • succeeding_charge: The charge status transitions from pending to succeeded
    • failing_charge: The charge status transitions from pending to failed

    When creating a test charge with this source, the charge’s status is initially set to pending before being automatically transitioned. Webhook events are also triggered when using test sources and charges. The charge.pending event is first triggered, followed by either the charge.suceeeded or charge.failed event immediately after.

    Disputed payments

    The risk of fraud or unrecognized payments is much lower as the customer must authenticate the payment with their bank. As such, there is no dispute process that can result in a chargeback and funds withdrawn from your Stripe account. Should a customer dispute a payment to their bank, it is handled internally—no dispute information is presented in the Dashboard.

    Source expiration

    A source must be used within six hours of becoming chargeable. If it is not, its status is automatically transitioned to canceled and your integration receives a source.canceled webhook event. Additionally, pending sources are canceled after one hour if they are not used to authenticate a payment.

    Once a source is canceled, the customer’s authenticated payment is refunded automatically—no money is moved into your account. For this reason, make sure the order is canceled on your end and the customer is notified once you receive the source.canceled event.

    Related resources