3D Secure for Fastlane
Last updated: Dec 4th, 4:27pm
Use Fastlane's 3D Secure (3DS) to authenticate cardholders through card issuers. 3DS reduces fraud for supported cards and improves transaction performance. For more details, see 3D Secure authentication.
Fastlane provides two options for performing 3DS:
- Orders v2 API: Run 3DS one time for each transaction when you integrate 3DS using the 3DS Orders v2 API. If the customer closes the modal or fails authentication, the Orders v2 API cannot issue a new challenge. Process the payment, request a new card, or complete another 3DS verification with the JavaScript SDK 3DS component.
- PayPal JavaScript SDK 3DS component: Use this component to complete 3DS verification. If you do not receive results, repeat 3DS verification, request a different card, or use Orders v2 to process the transaction.
How it works
Follow these steps to make a 3DS call.
- Generate an access token.
- Render the checkout page to collect payment information.
- Verify the credit card amount.
- Authenticate the customer if required by the issuer or local regulations.
If authentication succeeds or is not required, process the payment with the returned payment token or save the payment method for future transactions.
3DS with JavaScript SDK
Use PayPal’s JavaScript SDK or perform a server-side call with the Orders v2 API to support 3DS.
Generate access token
Generate an access token to authenticate PayPal API requests.
Request
1curl -s -X POST "https://api-m.sandbox.paypal.com/v1/oauth2/token" \2 -u CLIENT_ID:CLIENT_SECRET \3 -H "Content-Type: application/x-www-form-urlencoded" \4 -d "grant_type=client_credentials" \5 -d "response_type=client_token" \6 -d "intent=sdk_init" \7 -d "domains[]=example.com,example2.com"
Modify the code
- Get your client ID and secret from your Developer Dashboard.
- Copy the sample code. Replace
CLIENT_IDwith your client ID. - Replace
CLIENT_SECRETwith your client secret. - Replace
example.com,example2.comwith your domains. - Provide the root domain name only.
Note: Do not use subdomains, wildcards, or protocols.
Response
1{2 "scope": "https://uri.paypal.com/services/invoicing https://uri.paypal.com/services/disputes/read-buyer https://uri.paypal.com/services/payments/realtimepayment https://uri.paypal.com/services/disputes/update-seller https://uri.paypal.com/services/payments/payment/authcapture openid https://uri.paypal.com/services/disputes/read-seller https://uri.paypal.com/services/payments/refund https://api-m.paypal.com/v1/vault/credit-card https://api-m.paypal.com/v1/payments/.* https://uri.paypal.com/payments/payouts https://api-m.paypal.com/v1/vault/credit-card/.* https://uri.paypal.com/services/subscriptions https://uri.paypal.com/services/applications/webhooks",3 "access_token": "<access_token>",4 "token_type": "Bearer",5 "app_id": "<APP-ID>",6 "expires_in": 31668,7 "nonce": "<NONCE_FROM_FASTLANE_INTEGRATION>"8}
Initialize PayPal JavaScript SDK and Fastlane
Add the SDK script tag.
1<script>2 src="https://www.paypal.com/sdk/js?client-id=<CLIENT_ID>>&components=buttons,fastlane,three-domain-secure"3 data-sdk-client-token="<SDK_CLIENT_TOKEN>"4</script>
Load the Fastlane component.
1// instantiates the Fastlane module2const fastlane = await window.paypal.Fastlane({ });3// Convenience parameters for calling later on4const { identity,5 profile,6 FastlaneCardComponent,7 FastlaneWatermarkComponent,8 } = fastlane;9 fastlane.setLocale('en_us'); // Sets customer's country and language
Check 3DS eligibility
Initialize 3DS after receiving the payment token and order amount.
1// Check eligibility2const threeDomainSecureComponent = window.paypal.ThreeDomainSecureClient;
After you receive a payment token and the order amount, verify your eligibility.
1const threeDomainSecureParameters = {2 amount: '12.00',3 currency: 'USD',4 nonce: NONCE_FROM_FASTLANE_INTEGRATION,5 threeDSRequested: SCA_ALWAYS | SCA_WHEN_REQUIRED in the eligibility API request, otherwise defaults to SCA_WHEN_REQUIRED6 transactionContext: {7 experience_context: {8 brand_name: "YourBrandName",9 locale: "en-US",10 return_url: "https://example.com/returnUrl",11 cancel_url: "https://example.com/cancelUrl",12 },13 // Optional14 transaction_context: {15 soft_descriptor: "Card verification hold",16 },17 },18};19const isThreeDomainSecureEligible = await threeDomainSecureComponent.isEligible(20 threeDomainSecureParameters,21);
Customer attempts 3DS authentication
When the customer selects the submit button, trigger the authentication step and handle the result.
1const submitButton = document.getElementById("submit-button");2submitButton.addEventListener("click", async () => {3 if (isThreeDomainSecureEligible) {4 const {5 liabilityShift, // "no", "unknown", "possible"6 authenticationState, // "success", "cancelled", "errored"7 nonce, //Enriched nonce or the original nonce8 } = await threeDomainSecureComponent.show();9 if (authenticationState === "success") {10 // Check the liability shift and decide on continuing the transaction11 } else {12 // Cancelled or errored, merchant can choose to send the customer back to 3DS or submit a payment and or vault the payment token.13 }14 }15})
Client-side response parameters
The JavaScript SDK returns the following parameters after authentication.
| Parameter | Value | Description | Action |
liabilityShift |
POSSIBLE |
Liability might shift to issuer | Continue with authorization |
liabilityShift |
NO |
Liability stays with merchant | Do not continue with authorization |
liabilityShift |
UNKNOWN |
Authentication system unavailable | Do not continue, request cardholder retry |
authenticationState |
success |
Customer successfully authenticated | No action needed |
authenticationState |
cancelled |
Customer cancelled the authentication | No action needed |
authenticationState |
errored |
Error occurred during authentication | No action needed |
Process the payment using the Orders v2 API to validate the endrollmentStatus of the user.
3DS with Orders v2 API
After Fastlane generates a payment token and the customer places the order, call the Orders v2 API to check 3DS eligibility.
Use the returned URL to redirect the customer for authentication. Use the following API call for single-step 3DS verification.
1curl -v -k -X POST 'https://api-m.sandbox.paypal.com/v2/checkout/orders' \2 -H 'PayPal-Request-Id: UNIQUE_ID' \3 -H 'Authorization: Bearer PAYPAL_ACCESS_TOKEN' \4 -H 'Content-Type: application/json' \5 -H 'PayPal-Client-Metadata-Id: <CM_ID>' \6 -d '{7 "intent": "CAPTURE",8 "payment_source": {9 "card": {10 "single_use_token": "1h371660pr490622k", //paymentToken from the client11 "attributes": {12 "verification": {13 "method": "SCA_WHEN_REQUIRED"14 }15 }16 }17 },18 "experience_context": {19 "brand_name": "YourBrandName",20 "locale": "en-US",21 "return_url": "https://example.com/returnUrl",22 "cancel_url": "https://example.com/cancelUrl"23 },24 "transaction_context": {25 "soft_descriptor": "Card verification hold"26 },27 "purchase_units": [28 {29 "amount": {30 "currency_code": "USD",31 "value": "50.00",32 "breakdown": {33 "item_total": {34 "currency_code": "USD",35 "value": "40.00"36 },37 "shipping": {38 "currency_code": "USD",39 "value": "10.00"40 }41 }42 },43 "items": [44 {45 "name": "Coffee",46 "description": "1 lb Kona Island Beans",47 "sku": "sku03",48 "unit_amount": {49 "currency_code": "USD",50 "value": "40.00"51 },52 "quantity": "1",53 "category": "PHYSICAL_GOODS",54 "image_url": "https://example.com/static/images/items/1/kona_coffee_beans.jpg",55 "url": "https://example.com/items/1/kona_coffee_beans",56 "upc": {57 "type": "UPC-A",58 "code": "987654321015"59 }60 }61 ],62 "shipping": {63 "type": "SHIPPING",64 "name": {65 "full_name": "<FULL_NAME>"66 },67 "address": {68 "address_line_1": "123 Main St.",69 "admin_area_2": "Anytown",70 "admin_area_1": "CA", //must be sent in 2-letter format71 "postal_code": "12345",72 "country_code": "US"73 },74 "phone_number": {75 "country_code": "1",76 "national_number": "5555555555"77 }78 }79 }80 ]81}'
Redirect customer for authentication
Redirect the buyer to the rel: payer-action HATEOAS link before authorizing or capturing the order. Add redirect_url as a query parameter, so PayPal returns the payer to your checkout page after authentication. The following is a sample URL: https://example.com/webapp/myshop?action=verify&flow=3ds&cart_id=ORDER-ID&redirect_uri=MERCHANT-LANDING-PAGE.
Verify 3DS status
After the customer returns, check the verification status of the order by passing the order ID in a GET call to /v2/checkout/orders/{id}. A successful call returns an HTTP 200 response with the following content.
- Request
- Response
1curl -v -X GET https://api-m.sandbox.paypal.com/v2/checkout/orders/ORDER_ID \2-H 'Authorization: Bearer Bearer <Access-Token>'
Server-side response parameters
When using the Orders v2 API, you receive comprehensive 3DS parameters on the server side.
LiabilityShift
| Parameter | Value | Description | Action |
LiabilityShift |
POSSIBLE |
Liability may shift to the issuer | Continue with authorization |
LiabilityShift |
NO |
Liability stays with the merchant | Do not continue with authorization |
LiabilityShift |
UNKNOWN |
Authentication system unavailable | Request cardholder retry |
EnrollmentStatus
| Parameter | Value | Description | Action |
EnrollmentStatus |
Y |
Card and bank ready for 3DS | Proceed with authentication |
EnrollmentStatus |
N |
Not ready for 3DS | Do not proceed with authentication |
EnrollmentStatus |
U |
System unavailable | Request cardholder retry |
EnrollmentStatus |
B |
System bypassed authentication | Proceed with order |
Authentication_Status
| Parameter | Value | Description | Action |
Authentication_Status |
Y |
Successful authentication | No action needed |
Authentication_Status |
N |
Failed authentication | No action needed |
Authentication_Status |
R |
Rejected authentication | No action needed |
Authentication_Status |
A |
Attempted authentication | No action needed |
Authentication_Status |
U |
Unable to complete | No action needed |
Authentication_Status |
C |
Challenge required | No action needed |
Parameter availability
The Orders v2 API provides all three parameters on the server side, LiabilityShift, EnrollmentStatus, and Authentication_Status. The JavaScript SDK provides only liabilityShift and authenticationState. It does not provide EnrollmentStatus.
| Parameter | Orders v2 API | JavaScript SDK |
liabilityShift |
Yes | Yes |
enrollmentStatus |
Yes | No |
authenticationState |
Yes | Yes |
Complete the transaction
After 3DS authentication, you can complete the transaction using one of two methods: processing the payment or saving the payment method.
Process payment
You can capture the payment using a single-step or multi-step API request.
- In a single-step flow, after the 3DS contingency is resolved during the create order response, call the authorize order and capture order endpoints with empty payloads.
- In a multi-step flow, if the 3DS contingency occurs during an authorize order or capture order request, resolve the contingency, then call those endpoints again with empty payloads.
Save payment method
To save the customer’s payment method for future use after 3DS authentication, use the Payment Method Tokens v3 API.
- To process the current payment and vault the payment method for future transactions, use the single payment with vault option.
- To save the payment method without processing an immediate payment, use the vault-only option.
Capture the payment
After successful 3DS authentication, capture the authorized payment using the Orders v2 API capture endpoint.
- Capture request (Server-side)
- Capture response
1curl -v -X POST https://api-m.sandbox.paypal.com/v2/checkout/orders/{order_id}/capture \2 -H 'Authorization: Bearer PAYPAL_ACCESS_TOKEN' \3 -H 'Content-Type: application/json' \4 -H 'PayPal-Request-Id: UNIQUE_REQUEST_ID'
Handle capture status
Check the capture status in the response to determine next steps.
| Status | Description | Action |
COMPLETED |
Payment successfully captured | Fulfill the order and provide goods or services |
DECLINED |
Payment declined by issue | Notify the customer to use a different payment method |
PENDING |
Payment under review | Do not ship until the status is COMPLETED |
FAILED |
Capture failed | Review the error details and retry if appropriate |
Ensure all fulfillment or follow-up actions align with the current status of the payment capture response from the Orders v2 API.
Payment integration samples
The following code samples demonstrate how to initiate payment requests and manage payment methods using the Orders v2 API and Payment Method Tokens API.
- Payment
- Save payment method
- Vault
1curl -v -k -X POST https://api-m.sandbox.paypal.com/v2/checkout/orders \2 -H 'PayPal-Request-Id: UNIQUE_ID' \3 -H 'Authorization: Bearer PAYPAL_ACCESS_TOKEN' \4 -H 'Content-Type: application/json' \5 -H 'PayPal-Client-Metadata-Id: YOUR_CMID' \6 -d '{7 "intent": "CAPTURE",8 "payment_source": {9 "card": {10 "single_use_token": "1h371660pr490622k" // Payment token from the client11 }12 },13 "purchase_units": [14 {15 "amount": {16 "currency_code": "USD",17 "value": "50.00",18 "breakdown": {19 "item_total": {20 "currency_code": "USD",21 "value": "40.00"22 },23 "shipping": {24 "currency_code": "USD",25 "value": "10.00"26 }27 }28 },29 "items": [30 {31 "name": "Coffee",32 "description": "1 pound of coffee beans",33 "sku": "sku03",34 "unit_amount": {35 "currency_code": "USD",36 "value": "40.00"37 },38 "quantity": "1",39 "category": "PHYSICAL_GOODS",40 "image_url": "https://example.com/static/images/items/1/coffee_beans.jpg",41 "url": "https://example.com/items/1/coffee_beans",42 "upc": {43 "type": "UPC-A",44 "code": "987654321015"45 }46 }47 ],48 "shipping": {49 "type": "SHIPPING",50 "name": {51 "full_name": "Firstname Lastname"52 },53 "address": {54 "address_line_1": "123 Main St.",55 "admin_area_2": "Anytown",56 "admin_area_1": "CA", // Must be sent in 2-letter format57 "postal_code": "12345",58 "country_code": "US"59 },60 "phone_number": {61 "country_code": "1",62 "national_number": "5555555555"63 }64 }65 }66 ]67}'
Sandbox testing
To trigger 3DS in Sandbox, add a valid BIN test card to your Fastlane profile. Use the following recommended test card.
| Card network | Card number | Expiration date | CVV |
| Mastercard |
5186459910794125 | Any future date | 123 |