We’ve migrated our documentation to a new site, which means some URLs have changed.
Subscriptions

Datatrans

datatrans-logo.jpg

Datatrans Payments

More than 4,500 customers, 126 million transactions in the last year make Datatrans one of Europe’s leading payment service providers. Whether you have a big global project or are an online start-up, you can expect custom solutions and the reliability of a highly successful Swiss enterprise.

Merchant Requirements

Datatrans is available for merchants in the DACH region.

More information about the required transaction volume and pricing is available under the following link.

Limitations

Following the 

announcement

 from Datatrans about security and API changes, we’ve prepared the following instructions for your compliance. There are a few changes required in your Datatrans and Piano dashboards. For more details please see this 

guide

.

  1. This only impacts your Credit card and Postfinance methods - as these are using XML API and the security change requires you to enable HMAC signage. If you need more time to enable HMAC, you can reach out to your Datatrans rep to whitelist your app.

The Twint payment method requires a Twint voucher, which must be linked to a Swiss bank account and therefore supports only payments in CHF.

You cannot remove the postal code field from checkout for credit card payments as it's required by the payment provider itself.

Datatrans currently does not support Apple Pay in third-party browsers. To complete a purchase using Apple Pay, the user must be on a device with Apple Pay properly configured and must use Safari. When testing in other browsers, the Apple Pay button may not appear. For more details, see the Datatrans documentation.

Template Changes

Datatrans 3DS Billing Address Fields

Three new optional fields can be added to the Datatrans Credit Card checkout form to improve 3DS authentication data quality and increase the likelihood of frictionless authentication for your subscribers

New toggles in Datatrans Credit Card settings (Edit Business → Payment providers → Datatrans Credit Card):

  • Billing address (street)billAddrLine1

  • Billing citybillAddrCity

  • Billing countrybillAddrCountry

All default to disabled. ZIP code is a separate existing field and is not part of this update.

These fields apply to Checkout, My Account Wallet, and ATW / Subscribe User (initial transactions only; recurring renewals are not affected).

⚠️Important — template update required first

If you are using customized Payment Components templates, you must update your templates before enabling the toggles. Enabling the toggles without updating the template will cause validation errors that block purchases.

Step 1 — Update templates (required for customized templates)

  • Checkout: Add the below code for the  billing address field rows inside after the existing card fields in the Payment Components template.

    <tr ng-show="cc.collectBillingAddress && !input.billingAddressEnabled">
      <td colspan="4" class="field-card-billing-address">
        <div class="field-wrapper">
          <label class="icon road"></label>
          <div class="input">
            <input class="flat" type="text" name="billAddrLine1" required
                   placeholder="{{'Billing address' | tc:'checkout.platform'}}" ng-model="credit_card.billAddrLine1"/>
          </div>
        </div>
        <span class="error-message" ng-if="ccForm.billAddrLine1.$dirty && ccForm.billAddrLine1.$invalid">
          <t>Billing address is required.</t>
        </span>
      </td>
    </tr>
    <tr ng-show="cc.collectBillingCity && !input.billingAddressEnabled">
      <td colspan="4" class="field-card-billing-city">
        <div class="field-wrapper">
          <label class="icon city"></label>
          <div class="input">
            <input class="flat" type="text" name="billAddrCity" required
                   placeholder="{{'Billing city' | tc:'checkout.platform'}}" ng-model="credit_card.billAddrCity"/>
          </div>
        </div>
        <span class="error-message" ng-if="ccForm.billAddrCity.$dirty && ccForm.billAddrCity.$invalid">
          <t>Billing city is required.</t>
        </span>
      </td>
    </tr>
    <tr ng-if="cc.showBillingCountryDropdown">
      <td colspan="4" class="field-card-billing-country">
        <div class="field-wrapper">
          <label class="icon country"></label>
          <div class="input">
            <div class="tp-dropdown__select billing-country-drop-down"
                 ng-class="{'placeholder-shown': !credit_card.billAddrCountry}"
                 tp-country-selector
                 selector-options="datatransBillingCountrySelectorOptions"
                 default-country="datatransDefaultBillingCountry"
                 click-on-select="selectDatatransBillingCountry"
                 side="'bottom'"
                 country-type="'datatransBillingCountry'"
                 selector-label="{{'Billing country' | tc:'checkout.platform'}}"
                 dropdown-styles="{width: 230, zIndex: 1004, margin: 0}"
                 tabindex="0"
                 role="combobox"
                 aria-label="{{'Billing country' | tc:'checkout.platform'}}">
            </div>
          </div>
        </div>
      </td>
    </tr>

  • My Account Wallet: Update the My Account Components template as follows; locate the Datatrans card table and find the Cardholder name row (the whose input has aria-label="Cardholder name"). Immediatelly after, insert the following:.

    <tr class="table-row" ng-if="datatransCollectBillingAddress && !fullBillingAddressEnabled">
      <td class="table-cell" colspan="4">
        <label class="icon billing-address" aria-hidden="true"></label>
        <input type="text"
               ng-model="cardset.billAddrLine1"
               placeholder="{{'Billing address' | tc:'checkout.platform'}}"
               name="billAddrLine1"
               ng-required="datatransCollectBillingAddress && !fullBillingAddressEnabled"
               ng-readonly="readonly === true"
               aria-label="{{'Billing address' | tc:'checkout.platform'}}" />
      </td>
    </tr>
    <tr class="table-row" ng-if="datatransCollectBillingCity && !fullBillingAddressEnabled">
      <td class="table-cell" colspan="4">
        <label class="icon city" aria-hidden="true"></label>
        <input type="text"
               ng-model="cardset.billAddrCity"
               placeholder="{{'Billing city' | tc:'checkout.platform'}}"
               name="billAddrCity"
               ng-required="datatransCollectBillingCity && !fullBillingAddressEnabled"
               ng-readonly="readonly === true"
               aria-label="{{'Billing city' | tc:'checkout.platform'}}" />
      </td>
    </tr>
    <tr class="table-row" ng-if="datatransCollectBillingCountry && !fullBillingAddressEnabled && !isTaxBillingCountryEnabled">
      <td class="table-cell" colspan="4">
        <label class="icon country" aria-hidden="true"></label>
        <div
                class="tp-dropdown__select billing-country-drop-down datatrans-billing-country"
                ng-class="{'placeholder-shown': !cardset.billAddrCountry}"
                tp-country-selector
                selector-options="datatransBillingCountrySelectorOptions"
                default-country="datatransDefaultBillingCountry"
                click-on-select="selectDatatransBillingCountry"
                side="'bottom'"
                country-type="'datatransBillingCountry'"
                selector-label="{{'Billing country' | tc:'checkout.platform'}}"
                dropdown-styles="{width: 230, zIndex: 1004, margin: 0}"
                tabindex="0"
                role="combobox"
                aria-label="{{'Billing country' | tc:'checkout.platform'}}">
        </div>
      </td>
    </tr>

Step 2 — Enable toggles in Edit Business → Payment providers → Datatrans Credit Card settings

Country selector note: The billing country field uses Piano's standard country selector component (tp-country-selector). To pre-select a country (e.g. Switzerland or Germany), customize the component in your template. Localization is supported via standard Piano localization strings.

Postal code note: The postal code field is already shown and required by default, in case you previously disabled it in your customized template, re-enabling it alongside these new fields will provide the most complete billing address signal for 3DS.

Cardholder name

Before enabling the collection of the cardholder's name for card payments in the configuration, ensure that your system templates are updated accordingly.

There are numerous ways to update your system template to fetch the latest functionality:

  1. Reset to default (easiest, but depending on your level of customization,n you may need to decide if feasible)

  2. Use the Compare to default feature in the System template editor, and carry new lines of code over to your version

  3. Follow the instructions below to implement the new lines of code in your system template

Go to Manage → Templates → System → Payment Components, and find the component ]]>

Google Pay

<script type="text/ng-template" id="/frontend/providers/components/datatransgooglepay/checkout/component.shtml">
  <!-- https://paymentbutton.datatrans.dev/ -->
  <div id="datatrans-google-pay-options" class="hidden"></div>

  <div class="datatransgooglepay-wrapper new-card-form">
    <div class="row">
      <div class="googlepay-checkout-payment-form" ng-class="{'googlepay-checkout-payment-form--custom-indent': isIndentRequired}">

        <!-- Stored Payment Screen -->
        <div ng-show="isStoredPaymentsScreenShown()">
          <div class="add-credit-card-wrapper">
            <h4><t>Your Google Pay cards</t></h4>
            <a href="javascript:void(0)" class="add-credit-card" ng-click="gotoNewPaymentScreen()" ng-show="stored.length > 0">
              + <t>Add a new card</t>
            </a>
          </div>

          <table ng-if="stored.length > 0" class="googlepay-table">
            <tr class="googlepay-table-row" ng-repeat="upi in stored">
              <td class="googlepay-table-cell googlepay-table-cell--radio">
                <input
                  type="radio"
                  id="radio-{{upi.id}}"
                  name="stored_method"
                  ng-model="data.selectedUpi"
                  ng-change="onUpiChange(upi)"
                  ng-value="upi"
                  class="googlepay-radio"
                />
              </td>
              <td class="googlepay-table-cell googlepay-table-cell--short-logo">
                <div class="datatrans-gpay-short-logo"></div>
              </td>
              <td class="googlepay-table-cell">
                <label for="radio-{{upi.id}}">
                  <t context="checkout.platform">{{upi.display_name}}</t>
                </label>
              </td>
              <td class="googlepay-table-cell payment-method-card-cell-expiration">
                <t>Expires in</t> {{upi.expire_month}}/{{upi.expire_year}}
              </td>
              <td class="payment-method-card-cell payment-method-card-cell--default-payment">
                <div class="payment-method-card-default-payment" ng-show="upi.id === data.defaultPaymentMethodId">
                  <t>Default</t>
                </div>
                <button
                  ng-hide="upi.id === data.defaultPaymentMethodId"
                  ng-click="setAsDefault(upi)"
                  type="button"
                  class="set-as-default-button"
                >
                  <t>Set as default</t>
                </button>
              </td>
            </tr>
          </table>
        </div>

        <!-- New Payment Screen -->
        <div ng-show="isNewPaymentScreenShown()" class="googlepay-add-new-account">
          <div desktop class="go-back-to-cards-wrapper">
            <a href="javascript:void(0)" class="go-back-to-cards" ng-click="gotoStoredPaymentsScreen()" ng-show="isReturnToStoredPaymentsShown()">
              <t>Return to saved cards</t>
            </a>
            <h4><t>Add a new Google Pay card</t></h4>
          </div>

          <div ng-if="!data.newUpi" class="datatrans-gpay-account-wrapper">
            <div class="hint">
              <div class="googleplay-hint-container">
                <t>
                  Add Google Pay as a payment account to pay for your purchases and take the protection of Datatrans with you
                </t>
              </div>
            </div>

            <div class="gpay-container-wrapper">
              <div ng-show="isDtGpayLoading" id="dt-gpay-spinner-wrapper" class="spinner-wrapper">
                <div pn-spinner size="small"></div>
              </div>
              <div
                ng-show="!isDtGpayLoading"
                id="googlepay-pay-button"
                class="pm-login-button googlepay-login-button-wrapper"
                data-e2e="googlepay-login-button">
              </div>
            </div>
          </div>

          <table ng-if="data.newUpi" class="googlepay-table">
            <tr class="googlepay-table-row">
              <td class="googlepay-table-cell googlepay-table-cell--radio">
                <input
                  type="radio"
                  id="gpay-new-payment-method"
                  class="googlepay-radio"
                  name="stored_method"
                  ng-model="data.selectedUpi"
                  ng-value="data.newUpi"
                />
              </td>
              <td class="googlepay-table-cell googlepay-table-cell--short-logo">
                <div class="datatrans-gpay-short-logo"></div>
              </td>
              <td class="googlepay-table-cell">
                <label for="gpay-new-payment-method">
                  <t context="checkout.platform">{{data.newUpi.display_name}}</t>
                </label>
              </td>
              <td class="googlepay-table-cell">
                <div class="googlepay-logged-in">
                  <div ng-click="cancelAndInitNewAccount()" class="googlepay-cancel-button">
                    <t>Cancel</t>
                  </div>
                </div>
              </td>
            </tr>
          </table>
        </div>
      </div>

      <!-- Manage Payment Method -->
      <div class="manage-payment-method-wrapper" ng-show="state.payWithNew">
        <div ng-if="!isSubscription() && isPaymentTerm()">
          <div class="custom-checkbox">
            <input type="checkbox" name="store_in_vault" ng-model="data.store_in_vault" id="remember-my-card-datatrans-gpay" />
            <label for="remember-my-card-datatrans-gpay">
              <t>Remember my card for future payments</t>
            </label>
          </div>
        </div>

        <div ng-if="isSubscription()">
          <input type="hidden" name="store_in_vault" ng-model="data.store_in_vault" />
        </div>

        <div class="custom-checkbox" ng-if="data.store_in_vault">
          <input type="checkbox" name="defaultPaymentMethodId" ng-model="data.defaultPaymentMethodId" id="default-payment-method-cybersource" />
          <label for="default-payment-method-cybersource">
            <t>Apply this payment method to all active subscriptions</t>
          </label>
        </div>
      </div>

      <!-- Consents and Footer -->
      <div consents-list></div>

      <div class="footer-modal" ng-show="canContinue()">
        <div class="auto-renew-purchase" ng-show="isSelectedTermAutoRenewChoiceAvailable()">
          <input class="auto-renew-purchase-checkbox" type="checkbox" ng-model="input.autoRenew" id="auto_renew" />
          <label class="auto-renew-purchase-label" for="auto_renew">
            <t>Automatically renew my subscription when the time comes.</t>
          </label>
        </div>

        <div ng-show="isConfirmStepEnabled()" class="complete-purchase-button" data-e2e="googlepay-complete-purchase-button" goto-confirmation-button title="{{'Complete Purchase' | t}}"></div>

        <div ng-show="!isConfirmStepEnabled()" class="complete-purchase-button" data-e2e="googlepay-complete-purchase-button" complete-purchase-button title="{{'Complete Purchase' | t}}"></div>
      </div>
    </div>
  </div>
</script>

PayPal

<script type="text/ng-template" id="/frontend/providers/components/datatranspaypal/checkout/component.shtml">
<div class="datatranspaypal-wrapper new-card-form">
  <div class="row">

    <div ng-show="isStoredPaymentsScreenShown()" class="paypal-checkout-payment-form">
      <div class="add-credit-card-wrapper">
        <h4>
          <t context="checkout.platform">Your PayPal accounts</t>
        </h4>
        <a href="javascript:void(0)" class="add-credit-card" ng-click="gotoNewPaymentScreen()"
           ng-show="stored.length > 0">
          +
          <t>Add a new account</t>
        </a>
      </div>
      <table ng-if="stored.length" class="paypal-table">
        <tr class="paypal-table-row" ng-repeat="upi in stored">
          <td class="paypal-table-cell--radio">
            <input type="radio"
                   id="radio-{{upi.id}}"
                   name="stored_method"
                   ng-model="data.selectedUpi"
                   ng-value="upi"
                   ng-change="onUpiChange(upi)"
                   radio-track-by="id"
                   class="paypal-radio"/>
          </td>
          <td class="paypal-table-cell-logo">
            <div class="datatrans-paypal-short-logo"></div>
          </td>
          <td class="paypal-table-cell-email">
            <label for="radio-{{upi.id}}">
              {{upi.email}}
            </label>
          </td>
          <td class="payment-method-card-cell payment-method-card-cell--default-payment">
            <div class="payment-method-card-default-payment"
                 ng-show="upi.id === data.defaultPaymentMethodId">
              <t>Default</t>
            </div>
            <button ng-hide="upi.id === data.defaultPaymentMethodId"
                    ng-click="setAsDefault(upi)"
                    type="button"
                    class="set-as-default-button"
            >
              <t>Set as default</t>
            </button>
          </td>
        </tr>
      </table>
    </div>

    <div ng-show="isNewPaymentScreenShown()" class="paypal-checkout-payment-form">
      <div class="go-back-to-cards-wrapper">
        <h4>
          <t>Add a new PayPal account</t>
        </h4>
        <a href="javascript:void(0)" class="go-back-to-cards" ng-click="gotoStoredPaymentsScreen()"
           ng-show="isReturnToStoredPaymentsShown()">
          <t>Return to saved accounts</t>
        </a>
      </div>

      <div ng-if="!data.newUpi" class="datatrans-paypal-account-wrapper">
        <div class="hint">
          <t>Please, log in first.</t>
        </div>
        <div id="paypal-pay-button"
             class="pm-login-button paypal-login-button"
             ng-click="startWithNewAccount()"
             data-e2e="paypal-login-button">
        </div>
      </div>

      <table ng-if="data.newUpi" class="paypal-table">
        <tr class="paypal-table-row">
          <td class="paypal-table-cell--radio">
            <input type="radio"
                   id="paypal-new-payment-method"
                   name="stored_method"
                   ng-model="data.selectedUpi"
                   ng-value="data.newUpi"
                   radio-track-by="id"
                   class="paypal-radio"/>
          </td>
          <td class="paypal-table-cell-logo">
            <div class="datatrans-paypal-short-logo"></div>
          </td>
          <td class="paypal-table-cell-email">
            <label for="paypal-new-payment-method">
              {{data.newUpi.email}}
            </label>
          </td>
          <td class="paypal-table-cell-cancel">
            <div class="paypal-logged-in">
              <div ng-click="cancelNewAccount()" class="paypal-cancel-button">
                <t>Cancel</t>
              </div>
            </div>
          </td>
        </tr>
      </table>
    </div>

    <div class="manage-payment-method-wrapper" ng-show="state.payWithNew">
      <div ng-if="!isSubscription() && isPaymentTerm()">
        <div class="custom-checkbox">
          <input type="checkbox" name="store_in_vault" ng-model="data.store_in_vault"
                 id="remember-my-account-datatrans-paypal"/>
          <label for="remember-my-account-datatrans-paypal">
            <t>Remember my account for future payments</t>
          </label>
        </div>
      </div>
      <div ng-if="isSubscription()">
        <input type="hidden" name="store_in_vault" ng-model="data.store_in_vault"/>
      </div>
      <div class="custom-checkbox" ng-if="data.store_in_vault">
        <input type="checkbox" name="defaultPaymentMethodId" ng-model="data.defaultPaymentMethodId"
               id="default-payment-method-datatrans-paypal"/>
        <label for="default-payment-method-datatrans-paypal">
          <t>Apply this payment method to all active subscriptions</t>
        </label>
      </div>
    </div>

    <div consents-list></div>
    <div class="footer-modal" ng-show="canContinue()">
      <div class="auto-renew-purchase" ng-show="isSelectedTermAutoRenewChoiceAvailable()">
        <input class="auto-renew-purchase-checkbox" type="checkbox" ng-model="input.autoRenew"
               id="auto_renew"/>
        <label class="auto-renew-purchase-label" for="auto_renew">
          <t>Automatically renew my subscription when the time comes.</t>
        </label>
      </div>
      <div ng-show="isConfirmStepEnabled()" class="complete-purchase-button"
           data-e2e="paypal-complete-purchase-button" goto-confirmation-button
           title="{{'Complete Purchase' | t}}"></div>
      <div ng-show="!isConfirmStepEnabled()" class="complete-purchase-button"
           data-e2e="paypal-complete-purchase-button" complete-purchase-button
           title="{{'Complete Purchase' | t}}"></div>
    </div>
  </div>
</div>


</script>

Twint

Go to ManageTemplatesSystemPayment Components, find

Last updated: