Trustly

DocsCurrentLast updated: August 18th 2024, @ 11:09:25 am


Trustly logo

With Trustly, buyers can initiate payments directly from their bank accounts. During the online checkout process, customers select their bank, log into their online account, choose their payment method, and verify their purchase.

Trustly integrates with banks to collect funds locally across Europe and offers real-time reconciliation through proprietary integrations. Trustly natively supports payments on merchant checkout and is optimized for most devices. Merchants receive credit notifications after payments are completed. Payment completion happens within 7 days of payment authorization, depending on the bank used for the payment.

CountriesPayment typePayment flowCurrenciesMinimum amountRefunds
Austria (AT)
Germany (DE)
Denmark (DK)
Estonia (EE)
Spain (ES)
Finland (FI)
Great Britain (GB)
Lithuania (LT)
Latvia (LV)
Netherlands (NL)
Norway (NO)
Sweden (SE)
bank redirectredirectEUR, DKK, SEK, GBP, NOK0.01 EUR(or equivalent)Up to 365 days

How it works

Checkout flow

Alternative payment methods diagram

  1. Your checkout page offers alternative payment methods.
  2. Buyer provides their personal details and selects an alternative payment method from your checkout page.
  3. Buyer is transferred from your checkout page to the third-party bank to confirm the purchase.
  4. Merchant receives the successful payment initiation webhook notification and the payment is in a pending state.
  5. Buyer authorizes and confirms payment.
  6. Buyer returns to your site.
  7. Merchant receives the successful payment completion webhook notification and PayPal moves the funds to the merchant account.
  8. Merchant ships the goods.

Eligibility

  • Available to merchants globally, except in Russia, Brazil, Belgium, Czechia, Poland, Slovakia, and Slovenia.
  • Billing agreements, multiple seller payments, and shipping callback aren't supported.
  • Only supports order capture. Doesn't support order authorization. See Payments webhooks.
  • Chargebacks aren't supported.
  • Payment must be an online purchase. Doesn't support in-store payments.

Integrate

There are 2 integration paths you can take:

  • JavaScript SDK: Merchants can use PayPal-hosted UI components, called payment fields, to collect payment information for alternative payment methods.
  • Orders REST API: Integrate directly with the Orders API to fully customize the checkout experience.

  1. JS SDK
  2. Orders API
Use the JavaScript SDK to render payment fields and buttons and process payments with Orders API.

Buyer experience

Know before you code

Note: The integration steps for implementing alternative payment methods are similar. If you've integrated another alternative payment method before, you can likely reuse that code with adjustments for this payment method.
  • Complete the steps in Get started to get your sandbox account information from the Developer Dashboard:
    • Client ID: Authenticates your account with PayPal and identifies an app in your sandbox.
    • Client Secret: Authorizes an app in
your sandbox. Keep this secret safe
and don't share it.
    • Business account credentials
  • Make sure the preference for receiving payments in your PayPal business account is set to accept and convert them to the default currency. To verify, in your profile select Account Settings > Payment preferences > Block payments and select Update to mark this preference.
  • This client-side and server-side integration uses the following:
  • Make sure you're subscribed to the following webhook events:
    • Listen for the CHECKOUT.ORDER.APPROVED webhook in order to retrieve order details.
    • Listen for the PAYMENT.CAPTURE.PENDING, PAYMENT.CAPTURE.COMPLETED, and PAYMENT.CAPTURE.DENIED webhooks, which indicate payment capture status.
  • Request approval to enable this payment method by visiting these Sandbox and Live links. Replace MERCHANT-COUNTRY in the URL with the 2-character country code for the merchant's country of operation. Replace PRODUCT and CAPABILITY with the corresponding payment method:
    • Sandbox: https://www.sandbox.paypal.com/bizsignup/entry?product=PRODUCT&capabilities=CAPABILITY&country.x=MERCHANT-COUNTRY
    • Live: https://www.paypal.com/bizsignup/entry?product=PRODUCT&capabilities=CAPABILITY&country.x=MERCHANT-COUNTRY

  • Use Postman to explore and test PayPal APIs.

1. Add PayPal JavaScript SDK

Add or update the JavaScript SDK script on your web page.

1<script src="https://www.paypal.com/sdk/js?client-id=YOUR_CLIENT_ID&components=buttons,payment-fields,marks,funding-eligibility&enable-funding=trustly&currency=EUR"></script>

This table lists the parameters you pass to the JavaScript SDK.

Query param Default Description
client-id none Your PayPal REST client ID. This identifies your PayPal account and determines where transactions are paid.
components buttons A comma-separated list of components to enable. The buttons, payment-fields, marks, and funding-eligibility components are required for payment fields components.
enable-funding none The enabled payment methods to show in buttons and marks. 

Note: By default, PayPal JavaScript SDK provides smart logic to display only appropriate marks and buttons for the current buyer. This optional parameter bypasses the buyer country check for desired payment methods.

For example: src="https://www.paypal.com/sdk/js?client-id=YOUR_CLIENT_ID&enable-funding=venmo"

currency USD This is the currency for the payment. This value needs to match the currency used when creating the order.
locale automatic The locale renders components. By default PayPal detects the correct locale for the buyer based on their geolocation and browser preferences. It is recommended to pass this parameter with a supported locale if you need the PayPal buttons to render in the same language as the rest of your site.
intent capture The intent for the transaction. This determines whether the funds are captured immediately while the buyer is present on the page.
commit true This indicates that the final amount won't change after the buyer returns to your site from PayPal.
vault false Whether the payment information in the transaction will be saved. Save your customers' payment information for billing agreements, subscriptions, or recurring payments. Marking this parameter false shows all funding sources, including payment methods that can't be saved.

See additional, optional parameters.

2. Render payment mark

You can use a mark integration for payment field components to present the buyer's payment method options as radio buttons.

1paypal.Marks({
2 fundingSource: paypal.FUNDING.TRUSTLY
3}).render('#trustly-mark')

3. Render payment fields

Integrate payment fields to collect payment information from buyers. Fields dynamically render based on the selected payment source. You can customize the fields to align with your brand.

Choose from a single page checkout flow or a multi-page checkout flow.

  1. Single page
  2. Multi-page
The Trustly payment fields collect first name and last name.

If there are validation errors in the input fields, they'll show when the buyer selects the button.

1paypal.PaymentFields({
2 fundingSource: paypal.FUNDING.TRUSTLY,
3 /* style object (optional) */
4 style: {
5 /* customize field attributes (optional) */
6 variables: {},
7 /* set custom rules to apply to fields classes (optional) */
8 rules: {},
9 },
10 fields: {
11 /* fields prefill info (optional) */
12 name: {
13 value: "John Doe",
14 },
15 }
16})
17.render("#trustly-container")

For style parameters, please reference this style page: Custom style for payment fields

4. Render payment button

paypal.Buttons({
  fundingSource: paypal.FUNDING.TRUSTLY,
  style: {
    label: "pay",
  },
  createOrder() {
    return fetch("/my-server/create-paypal-order", {
      method: "post",
      // use the "body" param to optionally pass additional order information
      // like product skus and quantities
      body: JSON.stringify({
        cart: [
          {
            sku: "YOUR_PRODUCT_STOCK_KEEPING_UNIT",
            quantity: "YOUR_PRODUCT_QUANTITY",
          },
        ],
      }),
    })
    .then((response) => response.json())
    .then((order) => order.id);
  },
  onApprove(data) {
    // You do not need to capture the order, as the order is already captured
    // You can show a "Thank you" message and listen for the PAYMENT.CAPTURE.COMPLETED or PAYMENT.CAPTURE.DENIED webhooks to get the capture status
    // To show a "Thank you" message you can do
    // const element = document.getElementById('paypal-button-container');
    // element.innerHTML = '<h3>Thank you for your payment!</h3>';
    // Or go to another URL:  window.location.href = 'thank_you.html';
  },
  onCancel(data, actions) {
    /* Incomplete checkout. Buyer closed the window before order confirmation. */
    /* Show a message to restart the checkout process. */
    console.log(`Order Canceled - ID: ${data.orderID}`);
  },
  onError(err) {
    console.error(err);
  }
}).render("#trustly-btn");

Use paypal.Buttons().isEligible() to check if the payment source is eligible.

1var mark = paypal.Marks({
2 fundingSource: paypal.FUNDING.TRUSTLY
3})
4var fields = paypal.PaymentFields({
5 fundingSource: paypal.FUNDING.TRUSTLY,
6})
7var button = paypal.Buttons({
8 fundingSource: paypal.FUNDING.TRUSTLY
9})
10if(button.isEligible()) {
11 mark.render('#trustly-mark');
12 fields.render("#trustly-container");
13 button.render("#trustly-btn");
14}

createOrder

Implement the createOrder function to allow the JavaScript SDK to submit buyer information and set up the transaction when the buyer selects the button.

Note: Create Trustly orders in the EUR, DKK, SEK, GBP, or NOK currency. This currency must match the currency parameter passed in the JavaScript SDK <script> tag during Add PayPal JavaScript SDK.

Use your server-side Create order call to set up the details of a one-time transaction, such as the amount, line item details, and shipping information.

If order creation fails, the Orders API can return an error in the console.

After order creation, orders are confirmed with the buyer's selected payment source. If the order can't be processed with the selected payment source, the relevant errors show up in the console.

onCancel

Implement the optional onCancel() function to show a cancellation page or return to the shopping cart.

onError

Implement the optional onError() function to handle errors and display a generic error message or page to the buyer. This error handler is a catch-all. Errors at this point aren't expected to be handled beyond showing a generic error message or page.

5. Handle webhook events

Set up a webhook handler on your server to manage and respond to any webhooks that hit your listener URL.

  • CHECKOUT.ORDER.APPROVED - Listen for this webhook to retrieve order details. Order capture is performed automatically. No additional code required.
  • PAYMENT.CAPTURE.PENDING - Listen for this webhook to confirm that payment initialization was successful, the payment is pending, and the buyer needs to complete the transaction. Note that the funds have not yet been credited to the payee's PayPal account.
  • PAYMENT.CAPTURE.COMPLETED - Listen for this webhook to confirm that the money for this payment was credited to the payee's PayPal account. The buyer completed the transaction, and you can ship the order at this point.
  • PAYMENT.CAPTURE.DENIED - Listen for this webhook to confirm that the money couldn't be captured. The buyer didn't complete the payment before the voucher's expiration, or the bank declined the payment. You can cancel the order at this point.

See Subscribe to checkout webhooks for more information.

Here are some additional resources as you create webhook handler code:

Note: Once the buyer authorizes the payment, payment completion happens within 7 days, depending on the bank used for the payment. You should wait until payment completion to ship the goods.

6. Display the appropriate error message to the buyer

If createOrder in Step 4 is unsuccessful and returns an HTTP 422 UNPROCESSABLE_ENTITY status code, the JSON response body should contain an error code in the issue parameter.

Sample request

API endpoint used: Create order

curl --location --request POST 'https://api-m.sandbox.paypal.com/v2/checkout/orders' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer ACCESS-TOKEN' \
--header 'PayPal-Request-Id: PAYPAL-REQUESTID' \
--data-raw '{
    "intent": "CAPTURE",
    "purchase_units": [
        {
            "reference_id": "d9f80740-38f0-11e8-b467-0ed5f89f718b",
            "amount": {
                "currency_code": "SEK",
                "value": "100.00"
            }
        }
    ],
    "payment_source": {
        "trustly": {
            "country_code": "NL",
            "name": "John Doe"
        }
    },
    "processing_instruction": "ORDER_COMPLETE_ON_PAYMENT_APPROVAL",
    "application_context": {
        "locale": "en-NL",
        "return_url": "https://example.com/returnUrl",
        "cancel_url": "https://example.com/cancelUrl"
    }
}'

Step result

An unsuccessful request results in the following:

A return status code of HTTP 422 Unprocessable Entity. A JSON response body that contains an error code in the issue parameter and the error description in the description parameter.

Sample response

1{
2 "name": "UNPROCESSABLE_ENTITY222",
3 "details": [
4 {
5 "issue": "CURRENCY_NOT_SUPPORTED_BY_PAYMENT_SOURCE",
6 "description": "The currency_code provided in the order cannot be processed by the provided payment source."
7 }
8 ],
9 "message": "The requested action could not be performed, semantically incorrect, or failed business validation.",
10 "debug_id": "eccdbdf073eea",
11 "links": [
12 {
13 "href": "https://developer.paypal.com/docs/api/orders/v2/#error-CURRENCY_NOT_SUPPORTED_BY_PAYMENT_SOURCE",
14 "rel": "information_link",
15 "method": "GET"
16 }
17 ]
18}

Sample integration

See a sample Trustly integration in the PayPal GitHub repository.

Next steps