Integrate Trustly using the Orders API
Last updated: Feb 18th, 4:39am
Know before you code
- Request approval to enable Trustly by visiting these sandbox and live links:
- Sandbox: https://www.sandbox.paypal.com/bizsignup/entry?product=trustly&capabilities=TRUSTLY&country.x=<merchant's country>
- Live: https://www.paypal.com/bizsignup/add-product?product=trustly&capabilities=TRUSTLY&country.x=<merchant's country>
- Partners: Be sure to onboard your merchants upfront, before they accept payments. Onboarding after making payments, specifically Progressive Onboarding, isn't supported for alternative payment methods.
- Make sure you're subscribed to the following webhook events:
-
PAYMENT.CAPTURE.PENDING
– Listen for this webhook as an indication that payment initiation 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 the Redirect buyer for purchase approval step. -
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 the Fulfill the order step. -
PAYMENT.CAPTURE.DENIED
- Listen for this webhook as an indication that the Multibanco payment instruction has expired or the payer didn't complete the payment on time. You can cancel the order at this point. You'll act on this webhook in the Fulfill the order step.After you receive 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.
-
- Make sure your preference for receiving payments in your PayPal business or merchant account is set to accept and convert to the currency in your account. In your profile, select Account Settings > Payment preferences > Block payments and click Update to mark this preference.
- When processing Trustly payments, you don't need a call to capture payment for the order.
Offer Trustly on the 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 the buyer's
full_name
,country_code
, andtrustly
as the payment source. - Redirect the buyer to Trustly.
Refer to Payment method icons for icons you can use and download locations.
Create an order
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.email
- The payer's email.
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
.
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 for purchase approval. See also:HATEOAS links
.
Redirect buyer for purchase approval
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}
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
cancel_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
- Sample PAYMENT.CAPTURE.DENIED 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}
- The order ID from Step 2 should match the
resource.supplementary_data.related_ids.order_id
parameter in the webhook payload.
You can get the order capture result from the Show order details endpoint.
A successful request returns the HTTP 200 OK
status code with a JSON response body that returns a COMPLETED
status.
- 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 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.
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.
- Go live in PayPal's production environment.