Trustly
DocsCurrentLast updated: February 13th 2024, @ 10:53:41 am
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.
Countries | Payment type | Payment flow | Currencies | Minimum amount | Refunds |
---|---|---|---|---|---|
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 redirect | redirect | EUR , DKK , SEK , GBP , NOK | 0.01 EUR (or equivalent) | Up to 365 days |
How it works
Checkout flow
- Your checkout page offers alternative payment methods.
- Buyer provides their personal details and selects an alternative payment method from your checkout page.
- Buyer is transferred from your checkout page to the third-party bank to confirm the purchase.
- Merchant receives the successful payment initiation webhook notification and the payment is in a pending state.
- Buyer authorizes and confirms payment.
- Buyer returns to your site.
- Merchant receives the successful payment completion webhook notification and PayPal moves the funds to the merchant account.
- 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.
Know before you code
The steps to implementing all alternative payment methods using the Orders V2 REST API are similar. If you've implemented an alternative payment method previously, you can likely use that code and adjust it for the specific differences for Trustly.
Make sure you're subscribed to the following webhook events:
PAYMENT.CAPTURE.PENDING
– Listen for this webhook as an indication that payment initialization was successful, the payment is in a pending state, and is waiting for the buyer to complete the payment. You'll act on this webhook in Step 3.PAYMENT.CAPTURE.COMPLETED
– Listen for this webhook as an indication that the buyer has completed the payment, which can take up to seven days. You can ship the order to the buyer at this point. You'll act on this webhook in Step 4.PAYMENT.CAPTURE.DENIED
- Listen for this webhook as an indication that the payer didn't complete the payment on time or the bank has declined the payment. You can cancel the order at this point. You'll act on this webhook in Step 4.
Upon receiving each webhook, fetch the latest order details using Show order details. The
up
HATEOAS link in the webhook payload indicates the order associated with the capture.Set your preference for receiving payments in your PayPal business or merchant account to accept and convert to the currency in your account. In your profile, select Account Settings > Payment preferences > Block payments and choose Update to mark this preference.
When processing Trustly payments, you don't need a call to capture payment for the order.
1. Offer Trustly on your checkout page
You'll need to create the user interface to offer Trustly and collect the buyer's information, then you'll use the API calls described in the remainder of this topic to:
- Create the order with
trustly
as the payment source and the buyer'sfull_name
andcountry_code
. - redirect the buyer to Trustly
Refer to Payment method icons for icons you can use and download locations.
2. Create an order with Trustly as the payment source
Use the buyer information you captured from your user interface to create an order with Trustly as the payment source.
API endpoint used: Create order
- Sample request
- Sample response
1curl -v -X POST 'https://api-m.sandbox.paypal.com/v2/checkout/orders' \2-H 'Content-Type: application/json' \3-H 'Authorization: Bearer ACCESS-TOKEN' \4-H 'PayPal-Request-Id: PAYPAL-REQUESTID' \5-d '{6 "intent": "CAPTURE",7 "purchase_units": [8 {9 "reference_id": "d9f80740-38f0-11e8-b467-0ed5f89f718b",10 "amount": {11 "currency_code": "EUR",12 "value": "100.00"13 }14 }15 ],16 "payment_source": {17 "trustly": {18 "country_code": "NL",19 "name": "Firstname Lastname"20 }21 },22 "processing_instruction": "ORDER_COMPLETE_ON_PAYMENT_APPROVAL",23 "application_context": {24 "locale": "en-NL",25 "return_url": "https://example.com/returnUrl",26 "cancel_url": "https://example.com/cancelUrl"27 }28}'
Modify the code
After you copy the code in the sample request, modify the following:
ACCESS-TOKEN
- Your access token.PayPal-Request-Id
- Replace the sample ID with a unique ID you generate. This ID helps prevent duplicate authorizations in the event that the API call is disrupted. See also: API idempotency.intent
- Set this value toCAPTURE
.payment_source
- Specifytrustly
as the payment method, and include the following:country_code
- the 2-character country code for the payer's location.name
- The payer's full name.
application_context
- Specify the following:locale
- The preferred language for returned errors.return_url
- The URL the buyer is returned to after approving or canceling the purchase with their selected payment method.cancel_url
- The URL is a placeholder for future reference for now.
processing_instruction
- Set this value toORDER_COMPLETE_ON_PAYMENT_APPROVAL
.purchase_units: amount
- Pass thevalue
of the order and thecurrency code
.
Note: Change or add other parameters in the Create order request body to create an order that reflects the actual order details.
Step result
A successful request results in the following:
- A return status code of HTTP
200 OK
. - A JSON response body that contains the order ID. You'll use the order ID and
payer-action
HATEOAS URL in the next step,Redirect buyer to Trustly
. See also:HATEOAS links
.
3. Redirect buyer to Trustly
In your user interface, attach the payer-action
redirect URL returned in the Create order
response to the Trustly payment button.
In the sample, the redirect URL is: "https://www.sandbox.paypal.com/payment/trustly?token=5O190127TN364715T"
.
Step result
- The order status changes to
COMPLETED
, which means the order was created successfully. - A capture with
PENDING
status is present in the response parameterpurchase_units[0].payments.captures[0]
. Theup
HATEOAS link indicates the order associated with this capture. - The
PAYMENT.CAPTURE.PENDING
webhook event is triggered, which indicates that payment initiation was successful, the payment is in a pending state, and is waiting for the buyer to complete the payment. - This sends the buyer to their bank to approve the purchase.
- Wait for the buyer to authorize the payment. Payment completion happens within 7 days of the payment authorization.
Sample PAYMENT.CAPTURE.PENDING webhook
1{2 "id": "WH-4TV11484PJ0099250-1WB8208433136945G",3 "event_version": "1.0",4 "create_time": "2023-10-19T11:50:35.619Z",5 "resource_type": "capture",6 "resource_version": "2.0",7 "event_type": "PAYMENT.CAPTURE.PENDING",8 "summary": "Payment pending for EUR 15.39 EUR",9 "resource": {10 "id": "892032536L382192T",11 "amount": {12 "currency_code": "EUR",13 "value": "15.39"14 },15 "final_capture": true,16 "invoice_id": "Invoice-12345",17 "custom_id": "Custom-1234",18 "status": "PENDING",19 "status_details": {20 "reason": "OTHER"21 },22 "supplementary_data": {23 "related_ids": {24 "order_id": "5O190127TN364715T"25 }26 },27 "payee": {28 "email_address": "payee@example.com",29 "merchant_id": "1111111111111"30 },31 "create_time": "2023-10-19T11:50:31Z",32 "update_time": "2023-10-19T11:50:31Z",33 "links": [34 {35 "href": "https://api-m.sandbox.paypal.com/v2/payments/captures/892032536L382192T",36 "rel": "self",37 "method": "GET"38 },39 {40 "href": "https://api-m.sandbox.paypal.com/v2/payments/captures/892032536L382192T/refund",41 "rel": "refund",42 "method": "POST"43 },44 {45 "href": "https://api-m.sandbox.paypal.com/v2/checkout/orders/5O190127TN364715T",46 "rel": "up",47 "method": "GET"48 }49 ]50 },51 "links": [52 {53 "href": "https://api-m.sandbox.paypal.com/v1/notifications/webhooks-events/WH-4TV11484PJ0099250-1WB8208433136945G",54 "rel": "self",55 "method": "GET"56 },57 {58 "href": "https://api-m.sandbox.paypal.com/v1/notifications/webhooks-events/WH-4TV11484PJ0099250-1WB8208433136945G/resend",59 "rel": "resend",60 "method": "POST"61 }62 ]63}
4. Fulfill the order
Once the buyer authorizes the payment, and the payment completes:
- The buyer is redirected to the
return_url
mentioned in the Create order request. - The capture status changes to
COMPLETED
. - The
PAYMENT.CAPTURE.COMPLETED
webhook event is triggered, which indicates that payment capture was successful. You can ship the order to the buyer at this point.
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.
If the payment is not successful:
- The buyer is redirected to the
return_url
mentioned in the Create order request. - The capture status changes to
DENIED
. - The
PAYMENT.CAPTURE.DENIED
webhook event is triggered, which indicates that the payment capture wasn't successful. You shouldn't fulfill the order.
See Subscribe to checkout webhooks for more information.
Here are some additional resources as you create webhook handler code:
- Webhook Management API - Manage webhooks, list event notifications, and more.
- Webhook events:
- Checkout webhook events - Checkout buyer approval-related webhooks.
- Order webhook events - Other order-related webhooks.
Sample PAYMENT.CAPTURE.COMPLETED webhook
1{2 "id": "WH-81H706078A5332206-4WN94402WA949352E",3 "event_version": "1.0",4 "zts": 1481046241,5 "create_time": "2023-10-19T12:18:27.538Z",6 "resource_type": "capture",7 "resource_version": "2.0",8 "event_type": "PAYMENT.CAPTURE.COMPLETED",9 "summary": "Payment completed for EUR 15.39 EUR",10 "resource": {11 "id": "892032536L382192T",12 "amount": {13 "currency_code": "EUR",14 "value": "15.39"15 },16 "final_capture": true,17 "status": "COMPLETED",18 "status_details": {19 "reason": "OTHER"20 },21 "payee": {22 "email_address": "payee@example.com",23 "merchant_id": "1111111111111"24 },25 "create_time": "2023-10-19T11:50:31Z",26 "update_time": "2023-10-19T12:18:22Z",27 "links": [28 {29 "href": "https://api-m.sandbox.paypal.com/v2/payments/captures/892032536L382192T",30 "rel": "self",31 "method": "GET"32 },33 {34 "href": "https://api-m.sandbox.paypal.com/v2/payments/captures/892032536L382192T/refund",35 "rel": "refund",36 "method": "POST"37 },38 {39 "href": "https://api-m.sandbox.paypal.com/v2/checkout/orders/5O190127TN364715T",40 "rel": "up",41 "method": "GET"42 }43 ]44 },45 "links": [46 {47 "href": "https://api-m.sandbox.paypal.com/v1/notifications/webhooks-events/WH-81H706078A5332206-4WN94402WA949352E",48 "rel": "self",49 "method": "GET"50 },51 {52 "href": "https://api-m.sandbox.paypal.com/v1/notifications/webhooks-events/WH-81H706078A5332206-4WN94402WA949352E/resend",53 "rel": "resend",54 "method": "POST"55 }56 ]57}
Sample PAYMENT.CAPTURE.DENIED webhook
1{2 "id": "WH-1W932300CU741650D-26E32915YU381323H",3 "event_version": "1.0",4 "create_time": "2023-10-19T12:44:23.339Z",5 "resource_type": "capture",6 "resource_version": "2.0",7 "event_type": "PAYMENT.CAPTURE.DENIED",8 "summary": "Payment denied for EUR15.39 EUR",9 "resource": {10 "id": "55X2488039624323N",11 "amount": {12 "currency_code": "EUR",13 "value": "15.39"14 },15 "final_capture": true,16 "invoice_id": "Invoice-12345",17 "custom_id": "Custom-1234",18 "status": "DECLINED",19 "status_details": {20 "reason": "OTHER"21 },22 "supplementary_data": {23 "related_ids": {24 "order_id": "9R480625CB7539041"25 }26 },27 "payee": {28 "email_address": "payee@example.com",29 "merchant_id": "1111111111111"30 },31 "create_time": "2023-10-19T12:43:41Z",32 "update_time": "2023-10-19T12:44:18Z",33 "links": [34 {35 "href": "https://api-m.sandbox.paypal.com/v2/payments/captures/55X2488039624323N",36 "rel": "self",37 "method": "GET"38 },39 {40 "href": "https://api-m.sandbox.paypal.com/v2/payments/captures/55X2488039624323N/refund",41 "rel": "refund",42 "method": "POST"43 },44 {45 "href": "https://api-m.sandbox.paypal.com/v2/checkout/orders/9R480625CB7539041",46 "rel": "up",47 "method": "GET"48 }49 ]50 },51 "links": [52 {53 "href": "https://api-m.sandbox.paypal.com/v1/notifications/webhooks-events/WH-1W932300CU741650D-26E32915YU381323H",54 "rel": "self",55 "method": "GET"56 },57 {58 "href": "https://api-m.sandbox.paypal.com/v1/notifications/webhooks-events/WH-1W932300CU741650D-26E32915YU381323H/resend",59 "rel": "resend",60 "method": "POST"61 }62 ]63}
Note: The order ID from Step 2 should match the
resource.supplementary_data.related_ids.order_id
parameter in the webhook payload.
Alternatively, you can get the order capture result from the Show order details endpoint.
Important: Exercise caution when polling for order capture result using the Show order details endpoint. PayPal enforces rate limits on API requests.
- Sample request
- Sample response
1curl -v -X GET https://api-m.sandbox.paypal.com/v2/checkout/orders/9R480625CB7539041 \2-H "Content-Type: application/json" \3-H "Authorization: Bearer ACCESS-TOKEN"
Step result
A successful request returns the HTTP 200 OK
status code with a JSON response body that returns a COMPLETED
status.
A successfully captured order has the following:
- The order status as
COMPLETED
, which means the order was captured successfully. - A capture with
COMPLETED
status is present in the response parameterpurchase_units[0].payments.captures[0]
. - The
up
HATEOAS link indicates the order associated with this capture.
5. Handle payment responses
This section shows how to handle payment responses.
Successful payment
After a successful payment, notify the buyer of a successful transaction. You can do this by sending a confirmation email.
Unsuccessful payment
If Step 2 is unsuccessful and returns an HTTP 422 UNPROCESSABLE_ENTITY
status code, the JSON response body should contain an error code in the issue
parameter. Use this information to display the appropriate error message to the buyer.
API endpoint used: Create order
- Sample request
- Sample response
1curl -L -X POST 'https://api-m.sandbox.paypal.com/v2/checkout/orders' \2-H 'Content-Type: application/json' \3-H 'Authorization: Bearer ACCESS-TOKEN' \4-H 'PayPal-Request-Id: PAYPAL-REQUESTID' \5--data-raw '{6 "intent": "CAPTURE",7 "purchase_units": [8 {9 "reference_id": "d9f80740-38f0-11e8-b467-0ed5f89f718b",10 "amount": {11 "currency_code": "SEK",12 "value": "100.00"13 }14 }15 ],16 "payment_source": {17 "trustly": {18 "country_code": "NL",19 "name": "Firstname Lastname"20 }21 },22 "processing_instruction": "ORDER_COMPLETE_ON_PAYMENT_APPROVAL",23 "application_context": {24 "locale": "en-NL",25 "return_url": "https://example.com/returnUrl",26 "cancel_url": "https://example.com/cancelUrl"27 }28}'
Step result
An unsuccessful request returns a JSON response body that includes:
- A return status code of
422 Unprocessable Entity
. - An error code in the
details.issue
parameter. - An error description in the
details.description
parameter.
Next steps
- Handle uncaptured payments - Listen for the
CHECKOUT.PAYMENT-APPROVAL.REVERSED
webhook as an indication that an approved order wasn't captured for certain reasons resulting in a cancellation of the order and a refund the buyer's account. Then notify your buyer of the problem and the reversed order. - Test in PayPal sandbox, then go live in PayPal's production environment.