Giropay Payments with Sources Preview

    Use Sources to accept payments using BanGiropay, a popular payment method in Germany. If you need help after reading this, check out our answers to common questions or chat live with other developers in #stripe on freenode.

    Stripe users in Europe can accept Giropay payments from customers in Germany using Sources—a single integration path for creating payments using any supported method.

    During the payment process, a Source object is created and your customer is redirected to their bank’s website or mobile application to authorize the payment. After completing this, your integration can use the source to make a charge request to complete the payment.

    Within the scope of Sources, Giropay is a push-based, synchronous method of payment. This means that your customer takes action to send the amount to you and there is immediate confirmation about 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 API. To create a source with Stripe.js, first include the library within your payment page and set your publishable API key.

    Once included, use the following source.create method to create a source, providing the following information:

    Parameter Value
    type giropay
    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 (Giropay must always use Euros)
    owner[name] The full name of the account holder.
    redirect[return_url] The URL the customer should be redirected to after they have successfully authorized the payment.
    Stripe.source.create({
      type: 'giropay',
      amount: 1099,
      currency: 'eur',
      owner: {
        name: 'Jenny Rosen',
      },
      redirect: {
        return_url: 'https://shop.foo.com/crtA6B28E1',
      },
    }, stripeResponseHandler);
    

    Server-side source creation

    The use of Stripe.js to create this type of source is optional, but highly recommended. If you forgo this step and pass the information directly to Stripe when creating a Source object, you must take appropriate steps to safeguard any sensitive information that passes through your servers.

    curl https://api.stripe.com/v1/sources \
       -u sk_test_BQokikJOvBiI2HlWgH4olfQ2: \
       -d amount=1099 \
       -d currency=eur \
       -d type=giropay \
       -d owner[name]="Jenny Rosen" \
       -d redirect[return_url]="https://shop.foo.com/crtA6B28E1"
    
    # 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"
    
    source = Stripe::Source.create({
      amount: 1099,
      currency: 'eur',
      type: 'giropay',
      owner: {name: 'Jenny Rosen'},
      redirect: {return_url: 'https://shop.foo.com/crtA6B28E1'},
    })
    
    # 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"
    
    source = stripe.Source.create(
      amount=1099,
      currency='eur',
      type='giropay',
      owner={'name': 'Jenny Rosen'},
      redirect={'return_url': 'https://shop.foo.com/crtA6B28E1'},
    )
    
    // 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");
    
    $source = \Stripe\Source::create(array(
      "amount" => 1099,
      "currency" => "eur",
      "type" => "giropay",
      "owner" => array("name" => "Jenny Rosen"),
      "redirect" => array("return_url" => "https://shop.foo.com/crtA6B28E1"),
    ));
    
    // 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> sourceParams = new HashMap<String, Object>();
    sourceParams.put("amount", 1099);
    sourceParams.put("currency", "eur");
    sourceParams.put("type", "giropay");
    
    Map<String, Object> ownerParams = new HashMap<String, Object>();
    ownerParams.put("name", "Jenny Rosen");
    sourceParams.put("owner", ownerParams);
    
    Map<String, Object> redirectParams = new HashMap<String, Object>();
    redirectParams.put("return_url", "https://shop.foo.com/crtA6B28E1");
    sourceParams.put("redirect", redirectParams);
    
    Source source = Source.create(sourceParams);
    
    // 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");
    
    var source = stripe.sources.create({
      amount: 1099,
      currency: "eur",
      type: "giropay",
    owner: {name: "Jenny Rosen"},  redirect: {return_url: "https://shop.foo.com/crtA6B28E1"},
    }, function(err, source) {
      // asynchronously called
    });
    

    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": {
        "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.foo.com/crtA6B28E1",
        "status": "pending",
        "url": "https://pay.stripe.com/redirect/src_16xhynE8WzK49JbAs9M21jaR?client_secret=src_client_secret_UfwvW2WHpZ0s3QEn9g5x7waU"
      },
      "status": "pending",
      "type": "giropay",
      "usage": "single_use",
      "giropay": {
      }
    }

    Optional: Providing a custom statement descriptor

    Giropay 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 giropay[statement_descriptor] when creating a source.

    curl https://api.stripe.com/v1/sources \
       -u sk_test_BQokikJOvBiI2HlWgH4olfQ2: \
       -d amount=1099 \
       -d currency=eur \
       -d type=giropay \
       -d owner[name]="Jenny Rosen" \
       -d redirect[return_url]="https://shop.foo.com/crtA6B28E1" \
       -d giropay[statement_descriptor]="ORDER AT11990"
    
    # 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"
    
    source = Stripe::Source.create({
      amount: 1099,
      currency: 'eur',
      type: 'giropay',
      owner: {name: 'Jenny Rosen'},
      redirect: {return_url: 'https://shop.foo.com/crtA6B28E1'},
      giropay: {
        statement_descriptor: 'ORDER AT11990',
      },
    })
    
    # 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"
    
    source = stripe.Source.create(
      amount=1099,
      currency='eur',
      type='giropay',
      owner={'name': 'Jenny Rosen'},
      redirect={'return_url': 'https://shop.foo.com/crtA6B28E1'},
      giropay={
        'statement_descriptor': 'ORDER AT11990',
      },
    )
    
    // 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");
    
    $source = \Stripe\Source::create(array(
      "amount" => 1099,
      "currency" => "eur",
      "type" => "giropay",
      "owner" => array("name" => "Jenny Rosen"),
      "redirect" => array("return_url" => "https://shop.foo.com/crtA6B28E1"),
      "giropay" => array(
        "statement_descriptor" => "ORDER AT11990",
      ),
    ));
    
    // 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> sourceParams = new HashMap<String, Object>();
    sourceParams.put("amount", 1099);
    sourceParams.put("currency", "eur");
    sourceParams.put("type", "giropay");
    
    Map<String, Object> ownerParams = new HashMap<String, Object>();
    ownerParams.put("name", "Jenny Rosen");
    sourceParams.put("owner", ownerParams);
    
    Map<String, Object> redirectParams = new HashMap<String, Object>();
    redirectParams.put("return_url", "https://shop.foo.com/crtA6B28E1");
    sourceParams.put("redirect", redirectParams);
    
    Map<String, Object> giropayParams = new HashMap<String, Object>();
    giropayParams.put("statement_descriptor", "ORDER AT11990");
    sourceParams.put("giropay", giropayParams);
    
    Source source = Source.create(sourceParams);
    
    // 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");
    
    var source = stripe.sources.create({
      amount: 1099,
      currency: "eur",
      type: "giropay",
    owner: {name: "Jenny Rosen"},  redirect: {return_url: "https://shop.foo.com/crtA6B28E1"},
      giropay: {
        statement_descriptor: "ORDER AT11990",
      },
    }, function(err, source) {
      // asynchronously called
    });
    

    Providing a custom statement descriptor within a subsequent charge request has no effect. Any custom statement descriptor must be provided when creating a source.

    Error codes

    Source creation for Giropay 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_owner_name The owner name is invalid. It must be at least three characters in length.

    Step 2: Have the customer authorize the payment

    When creating a source, it’s status is initially set to pending and cannot yet be used to make a charge request. Your customer must authorize a Giropay payment to make the source chargeable. To allow your customer to authorize the payment, redirect them to the URL provided within theredirect[url] attribute of the Source object. We recommend using a 302 HTTP status code when performing this redirect if the source has been created as part of a form submission or using client-side Javascript using AJAX.

    After 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. Stripe populates the redirect[return_url] with the following GET parameters when your customer returns 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 by the values we populate.

    Mobile applications

    If you are integrating Giropay within a mobile application, the redirect URL must be opened using the phone’s native browser (e.g., Safari on iOS). The use of in-app web views and containers can prevent your customer’s installed banking app from launching to complete authentication—resulting in a lower conversion rate.

    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.

    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 where you can either authorize or cancel the payment. Authorizing the payment redirects you to the URL specified in redirect[return_url].

    Step 3: Confirm that the source is ready to use

    Once the customer has authenticated the payment, the source’s status transitions to chargeable and it can be used to make a charge request. You can determine whether authentication was successful using client-side source polling with Stripe.js, or webhooks.

    Client-side source polling

    You can use Stripe.js to poll the Source object, client-side. The JavaScript handler is called as soon as the Source object is retrieved, client-side, and every time its status is updated. In particular, it is called when the status changes from pending to either failed or chargeable, and from chargeable to consumed once your server makes the associated charge request.

    Stripe.source.poll(
      "src_16xhynE8WzK49JbAs9M21jaR",
      "src_client_secret_UfwvW2WHpZ0s3QEn9g5x7waU",
      function(status, source) {
        // `source`: is the source object.
        // `status`: is the HTTP status. if non 200, an error occured
        //          and the poll is canceled.
    
        // This handler is called as soon as the source is retrieved and subsequently
        // anytime the source's status (`source.status`) is updated.
      })
    

    Webhooks

    The following webhook events are also 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.canceled A Source object expired and cannot be used to create a charge.
    source.consumed A Source object that was single-use has already been charged.
    source.failed A Source object failed to become chargeable as your customer declined to authenticate the payment.

    Handling customers that don’t return after completing authentication

    Customers using Giropay 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. When accepting Giropay payments, always use the source.chargeable event to confirm when a source is chargeable, even if you make use of client-side polling. This allows you to confirm that the customer has authorized the payment and the source is can be used in a charge request, should they have closed their browser.

    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.

    Once a source is canceled, the customer’s authenticated Giropay 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.

    Step 4: Make a charge request using the source

    Once the source is chargeable, 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)
    

    Step 5: Confirm that the charge has succeeded and the payment is complete

    Since Giropay is a synchronous payment method, the Charge object’s status immediately reflects whether or not it has been successful. 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.

    After confirming that the charge has succeeded, notify your customer that the payment process has been completed and their order is confirmed.

    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.

    Next steps

    Congrats! You've learned about processing Giropay payments using Sources. Some documentation you might want to read next: