Strategic partner distribution integration guide
DocsLast updated: November 25th 2024, @ 6:06:17 pm
Overview
This Strategic Partner Distribution Integration Guide is for merchants that want to implement Fastlane either with their current Payment Service Provider or their ecommerce partner platform.
Prerequisites
Fastlane is available to integrate for merchants in the USA:
- Fastlane supports payments using desktop and mobile web browsers.
- If the merchant's current checkout process doesn't collect a billing address, you need to collect it to use Fastlane.
Fastlane profiles
Fastlane supports 2 main types of profiles or personas:
- Non-Accelerated User: A guest user who doesn't have a Fastlane profile.
- Accelerated User: An existing PayPal or Fastlane user that we can recognize and accelerate.
Generate Client Token
You first need to generate a client token to initialize the JavaScript SDK. Client tokens are expected to be cached and reused for the merchant and payment partner combination they are processing until the token expires. You need to generate and include an auth assertion JSON Web Token (JWT).
Generate with Client and Secret
curl -s -X POST "https://api-m.sandbox.paypal.com/v1/oauth2/token" \
-u "CLIENT_ID:CLIENT_SECRET" \
-H "Content-Type: application/x-www-form-urlencoded" \
-H "PayPal-Request-Id: YOUR-PAYPAL-REQUEST-ID" \
-H "PayPal-Auth-Assertion: PAYPAL-AUTH-ASSERTION" \
-H "PayPal-Partner-Attribution-Id: BN-CODE" \
-d "grant_type=client_credentials" \
-d "response_type=client_token" \
-d "intent=sdk_init" \
-d "domains[]=example.com,example2.com"
Generate with an access token
curl -s -X POST "https://api-m.sandbox.paypal.com/v1/oauth2/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-H "Authorization: Bearer ACCESS-TOKEN" \
-H "PayPal-Request-Id: YOUR-PAYPAL-REQUEST-ID" \
-H "PayPal-Auth-Assertion: PAYPAL-AUTH-ASSERTION" \
-H "PayPal-Partner-Attribution-Id: BN-CODE" \
-d "grant_type=token_exchange" \
-d "response_type=client_token" \
-d "intent=sdk_init" \
-d "domains[]=example.com,example2.com"
Modify the code
- Copy the sample request code.
- Change the
ACCESS-TOKENto yoursandbox-access-token. - Change
REQUEST_IDto a unique alphanumeric set of characters, such as a time stamp. - Add
AUTH-ASSERTION-TOKENto yourPayPal-Auth-Assertiontoken if transacting on behalf of another merchant. ThePayPal-Auth-Assertionheader is optional for a client token generation call, but you can include it when you are processing transactions on behalf of another merchant. - Add the BN Code associated with your PayPal account.
Step result
A successful result returns the following:
- An HTTP response code of
200or201. Returns200for an idempotent request. - An access token.
| Rel | Method | Description |
|---|---|---|
| confirm | Post | Make a POST request to generate the access token. |
Response
{
"access_token": "eyJraW...",
"app_id": "APP-80W2...",
"expires_in": 32400,
"nonce": "2024-01...",
"scope": "...",
"token_type": "Bearer"
}
- Send domain name in client token generate call: When generating a client token, you need to send a domain name where Fastlane will be displayed to customers to protect against cross-site scripting attacks.
- Provide the root domain name: You must provide the base or root domain name. For example, if https://checkout.example.com is the URL where you are loading Fastlane components, pass the root domain name example.com.
| URL | Root Domain Name |
|---|---|
| https://www.paypal.com | paypal.com |
| https://checkout.paypal.com | paypal.com |
| https://www.paypal.co.uk | paypal.co.uk |
| https://developer.paypal.com | paypal.com |
| https://www.paypal.ca | paypal.ca |
- If you specify subdomains, wildcards or protocols, the system return an error.
The following list explains the limitations you need to follow when passing domain names for your Fastlane integration:
- No subdomains: Don't include subdomains, such as sub.example.com.
- No wildcards: Don't use wildcard characters, such as *.example.com.
- No protocols: Don't include the
HTTPorHTTPSprotocols in the domain name. For example: https://example.com.
Error Handling: If you specify subdomains, wildcards, or protocols, the system generates an error.
Load SDK
Initialize the PayPal JavaScript (JS) SDK with your client ID and the client token from the previous step. If you are using the namespace feature of the JavaScript SDK to load buttons and Fastlane separately, review the documentation here.
<script
src="https://www.paypal.com/sdk/js?client-id=<CLIENT_ID>>&components=buttons,fastlane"
data-sdk-client-token="<SDK_CLIENT_TOKEN>">
</script>
Dynamically load SDK
If you want to fetch the client token async, you can load the JavaScript SDK using a function similar to the one below.
function loadSDK(clientId, clientToken) {
return new Promise((resolve, reject) => {
const pyplScript = document.createElement('script');
pyplScript.setAttribute('src', `https://www.paypal.com/sdk/js?client-id=${clientId}&components=buttons,fastlane`);
pyplScript.setAttribute('data-user-id-token', clientToken);
pyplScript.onload = () => { resolve(); };
document.head.appendChild(pyplScript);
});
}
Initialize SDK
The following code gets the identity and profile objects from the JavaScript SDK needed to integrate the consumer experience. For alpha merchants, the JavaScript SDK supports only Visa and Mastercard payments.
const {
identity,
profile,
FastlaneConsentComponent,
} = await window.paypal.Fastlane();
Look up email address
const email = document.getElementById('email').value;
const { customerContextId } = await identity.lookupCustomerByEmail(email);
Integrate consumer persona
The response of the lookupCustomerByEmail function shows the type of User persona.
| Persona | customerContextId |
|---|---|
| Fastlane guest | Empty string |
| Fastlane member | string |
Integrate Fastlane member
Trigger authentication
const authResponse = await identity.triggerAuthenticationFlow(
customerContextId
);
Example response
{
"authenticationState": "succeeded",
"profileData": {
"shippingAddress": {
"company": "PayPal",
"streetAddress": "123 Fake St, Suite 100",
"locality": "Springfield",
"region": "IL",
"postalCode": "62701",
"countryCodeAlpha2": "US",
"firstName": "Alice",
"lastName": "Johnson",
"phoneNumber": "14155559876"
},
"card": {
"id": "21b800c9-8568-15c5-8df6-0d67d9f46771",
"paymentSource": {
"card": {
"brand": "MasterCard",
"expiry": "2025-12",
"lastDigits": "1234",
"name": "Jane Doe",
"billingAddress": {
"streetAddress": "123 Fake St, Suite 100",
"locality": "Springfield",
"region": "IL",
"postalCode": "62701",
"countryCodeAlpha2": "US"
}
}
}
},
"name": {
"firstName": "Alice",
"lastName": "Johnson"
}
}
}
Address selector modal
Use the profile object from the JavaScript SDK initialization step to render the address selector. Render your HTML element to invoke the address selector.
document.getElementById('changeAddress').addEventListener('click', async (event) => {
const { selectionChanged, selectedAddress } = await profile.showShippingAddressSelector();
if (selectionChanged) {
// use selectedAddress in your own UI
}
});
Card selector modal
Use the profile object from the JavaScript SDK initialization step to render the card selector. Render your HTML element to invoke the card selector.
document.getElementById('changeCard').addEventListener('click', async (event) => {
const {
selectionChanged,
selectedCard
} = await profile.showCardSelector();
if (selectionChanged) {
// Use selectedCard in your UI
}
});
Initialize consent component
To determine whether to show consent, the payment services provider must call the initialize consent component.
const consent = await axoSdk.ConsentComponent();
consent.getRenderState()
Object returned by getRenderState
return {
showConsent: true | false,
defaultToggleState: true | false,
termsAndConditionsLink: string,
privacyPolicyLink: string,
termsAndConditionsVersion: string
};
The showConsent parameter determines whether to show custom consent. If showConsent is false, no other properties will be returned.
Note:
showConsent,termsAndConditions, andversionare required when creating the profile.
Token Exchange
The Token Exchange endpoint is leveraged by partners during a transaction that is being accelerated by Fastlane. In other words, when a Fastlane member has been authenticated and is leveraging their profile for checkout, we will provide the partner with a client-safe token that can then be swapped for a network token and cryptogram.
Send the token returned to your server. We are sharing an example of the Fastlane token.
Front end
const paymentToken = paymentToken.id;
const headers = new Headers();
headers.append("Content-Type", "application/json");
const body = JSON.stringify({
token: paymentToken,
});
const response = await fetch("/<MERCHANT ENDPOINT FOR TOKEN GENERATION>", {
method: "POST",
headers,
body,
});
return await response.json();
Back end
const url = `${PAYPAL_API_BASE_URL}/v3/vault/payment-method-credentials`;
const auth = `Bearer ${accessToken}`;
const requestId = new Date().getTime();
const metadataId = '0fd1215774704ad8b1080ef79bb64950';
const authAssertion = getAuthAssertionToken(
PAYPAL_CLIENT_ID,
PAYPAL_MERCHANT_ID,
);
const headers = new Headers();
headers.append('Authorization', auth);
headers.append('PayPal-Request-Id', requestId);
headers.append('PayPal-Auth-Assertion', authAssertion);
headers.append('PayPal-Partner-Attribution-Id', PAYPAL_BN_CODE);
headers.append('PayPal-Client-Metadata-Id', metadataId);
const body = {
token: {
id: accessToken,
type: 'SINGLE_USE_TOKEN',
},
};
const options = {
method: 'POST',
headers,
body: JSON.stringify(body),
};
const response = await fetch(url, options);
const data = await response.json();
Modify the code
- Copy the sample request code.
- Use the bearer token that you get from the token generate call.
- Change
REQUEST_IDto a unique alphanumeric set of characters, such as a time stamp. - Add
AUTH-ASSERTION-TOKENto your PayPal-Auth-Assertion token if transacting on behalf of another merchant. - Add the BN Code associated with your PayPal account.
Step result
A successful result returns the following :
- An HTTP response code of
200or201. Returns200for an idempotent request. - An access token.
| Rel | Method | Description |
|---|---|---|
| confirm | Post | Make a POST request to generate the access token. |
Expected response
{
"card": {
"network_token": {
"id": "NDg5NTM3MDAxMzM0Njk2Nw==",
"expiry": "2025-11",
"cryptogram": "eyJjcmVkZW50aWFsIjoiU2FEQTBHdzljUjM3ajh4clpQNlZGQ0pwWiIsImVjb21tZXJjZV9pbmRpY2F0b3IiOiIwNyJ9"
},
"last_digits": "2643",
"expiry": "2030-10",
"brand": "VISA"
}
}
Errors
If you see errors, use these codes and their descriptions to troubleshoot:
| Issue | Response Code | Description |
|---|---|---|
INTERNAL_SERVER_ERROR | 500 | An internal server error occurred |
NETWORK_TOKEN_NOT_SUPPORTED | 422 | Support for network token is unavailable for the provided token ID |
TOKEN_NOT_FOUND | 422 | The specified token id does not exist. |
INVALID_TOKEN_REFERENCE | 422 | The internal reference ID linked to the provided token could not be located. Please contact PayPal account manager for assistance. |
INVALID_TOKEN_STATE | 422 | Token provided is not usable due to its invalid state. Please contact PayPal account manager for assistance. |
NOT_ENABLED_FOR_TOKENIZATION | 403 | You do not have permission to access or perform operations on this resource. Please contact PayPal account manager for assistance. |
PERMISSION_DENIED | 403 | You do not have permission to access or perform operations on this resource. |
AUTHENTICATION_FAILURE | 401 | Authentication failed due to missing Authorization header, or invalid authentication credentials. |
MISSING_REQUIRED_PARAMETER | 400 | A required field / parameter is missing. |
INVALID_STRING_LENGTH | 400 | The value of a field is either too short or too long. |
INVALID_PARAMETER_SYNTAX | 400 | The value of a field does not conform to the expected format. |
INVALID_PARAMETER_VALUE | 400 | The value of a field is invalid. |
Process Payment
The network Token and cryptogram can now be used to process the payment on your existing payment infrastructure.
Integrate Fastlane guest
You will write the UI exactly as what has been agreed upon by Fastlane and your design teams. The lookupCustomerByEmail function executed above will return some additional data, which will direct your functionality in the consent UI.
If we have this response:
{
customerContextId: string;
}
If we have a customerContextId, it means we have a saved Fastlane profile, and if we don't have a customerContextId, it means we are a guest user.
Process Payment
Since you own the card fields that collected the card information, you can collect and process it as you do today.
Create profile
After a successful transaction you will execute the create profile API if the consent toggle is on. So you will want to send the results of the consent UI to the server. If details toggle is True:
curl -v -k -X POST 'https://api-m.sandbox.qa.paypal.com:18582/v3/vault/customers' \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ACCESS-TOKEN" \
-H "PayPal-Request-Id: REQUEST-ID" \
-H "PayPal-Auth-Assertion: AUTH-ASSERTION-TOKEN" \
-H "PayPal-Client-Metadata-Id: 0fd1215774704ad8b1080ef79bb64950" \
-d '{
"email": "[email protected]",
"name": {
"given_name": "Gary",
"surname": "Guest"
},
"phones": [
{
"national_number": "3398240084",
"country_code": "1"
}
],
"product_type": "FASTLANE",
"payment_tokens": [
{
"payment_source": {
"card": {
"number": "4111111111111111",
"expiry": "2027-02",
"name": "Gary Guest",
"billing_address": {
"address_line_1": "2211 N First Street",
"address_line_2": "Building 17",
"admin_area_1": "CA",
"admin_area_2": "San Jose",
"country_code": "US",
"postal_code": "95131"
}
}
}
}
],
"addresses": [
{
"name": {
"given_name": "Gary",
"surname": "Guest"
},
"address_line_1": "2211 N First Street",
"address_line_2": "Building 17",
"admin_area_1": "CA",
"admin_area_2": "San Jose",
"country_code": "US",
"postal_code": "95131"
}
],
"legal_agreements": [
{
"type": "ACCELERATED_CHECKOUT_USER_AGREEMENT",
"major_version": 3,
"minor_version": 2
}
]
}'
Modify the code
- Copy the sample request code.
- Change the
ACCESS-TOKENto yoursandbox-access-token. - Change
REQUEST_IDto a unique alphanumeric set of characters, such as a time stamp. - Add
AUTH-ASSERTION-TOKENto yourPayPal-Auth-Assertiontoken if transacting on behalf of another merchant.
| Issue | Response Code | Description |
|---|---|---|
INTERNAL_SERVER_ERROR | 500 Internal Server Error | An internal server error occurred. |
UNPROCESSABLE_ENTITY | 422 Unprocessable Entity | The requested action could not be performed, semantically incorrect, or failed business validation. |
UNSUPPORTED_COUNTRY | Non US billing Address | |
NOT_AUTHORIZED | 403 | Authorization failed due to insufficient permissions. |
AUTHENTICATION_FAILURE | 401 | Authentication failed due to missing Authorization header, or invalid authentication credentials. |
INVALID_REQUEST | 400 | The request is not well-formed, is syntactically incorrect, or violates schema. |
INVALID_PARAMETER_SYNTAX | ||
MISSING_REQUIRED_PARAMETER | ||
INVALID_STRING_LENGTH | ||
INVALID_STRING_MAX_LENGTH |
Step result
A successful result returns the following:
- An HTTP response code of
200or201. Returns200for an idempotent request. - The access token should be returned.
| Rel | Method | Description |
|---|---|---|
| confirm | Post | Make a POST request to generate the access token. |
Response
HTTP status code: 201 CREATED
HTTP Headers:
"Content-Type": "application/json"
Response payload:
{
"create_time": "2024-07-26T15:28:23Z",
"name": {
"given_name": "Gary",
"surname": "Guest"
},
"email": "[email protected]",
"phones": [
{
"country_code": "1",
"national_number": "3398240084"
}
],
"id": "5WGAQJMNUJXKS",
"payment_tokens": [
{
"ordinal": 1,
"payment_source": {
"card": {
"name": "Gary Guest",
"last_digits": "1111",
"brand": "VISA",
"expiry": "2027-02",
"billing_address": {
"address_line_1": "2211 N First Street",
"address_line_2": "Building 17",
"admin_area_2": "San Jose",
"admin_area_1": "CA",
"postal_code": "95131",
"country_code": "US"
}
}
}
}
],
"addresses": [
{
"id": "7KA64580FB957254X",
"create_time": "2024-07-26T15:28:23Z",
"address_line_1": "2211 N First Street",
"address_line_2": "Building 17",
"admin_area_2": "San Jose",
"admin_area_1": "CA",
"postal_code": "95131",
"country_code": "US",
"name": {
"given_name": "Gary",
"surname": "Guest"
},
"phone_number": {
"country_code": "1",
"national_number": "3398240084"
},
"ordinal": 1
}
]
}
Integrate Network Token usage event
Any time there is an email lookup and a customer checkout for both a Fastlane Guest and a Fastlane Member whether successful or not, you need to send us a network token usage event.
curl -s -X POST "https://api-m.sandbox.paypal.com/v1/notifications/events" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ACCESS-TOKEN" \
-H "PayPal-Request-Id: YOUR-PAYPAL-REQUEST-ID" \
-H "PayPal-Auth-Assertion: PAYPAL-AUTH-ASSERTION" \
-H "PayPal-Partner-Attribution-Id: BN-CODE" \
-d "{
"event_name": "FASTLANE_PARTNER_TX_PROCESSED",
"session_id": string, // Fastlane CMID (customerMetadataId - unique identifier //of Buyer session in browser)
"partner_merchant_id": string, // Partner's ID for merchant
"partner_merchant_name": string, // Optional name of merchant as stored in //Partners' systems
"payment_method_credential_token_id": string, // Payment Method Credential ID //as set by Vault
"transaction_amount": string, // Amount of transaction request
"transaction_currency_code": string, // Currency code of transaction request
"transaction_id": string, // Id of transaction in PSP system
"transaction_status": transactionStatus,
"transaction_timestamp": string, // Epoch time
"processing_code": string, // By default, "ISO8583" processing code used for //txn processing
"processing_code_version": string, // Either "ISO8485:1987" or "ISO8485:1993" R //equired if "processing_code" is not ISO8583
"fastlane_customer_id": string // Required if network token used in txn was //acquired using Fastlane profile
"fastlane_consent_shown": boolean, // Required for both guest and member use //cases.
"fastlane_consent_given": boolean // Optional - provided if //fastlane_consent_shown = true
"version": string // Follows semantic versioning specifications
}
transactionStatus: {
'PROCESSED',
'DECLINED',
'FAILED'
}"
Modify the code
- Copy the sample request code.
- Change the
ACCESS-TOKENto yoursandbox-access-token. - Change
REQUEST_IDto a unique alphanumeric set of characters, such as a time stamp. - Add
AUTH-ASSERTION-TOKENto yourPayPal-Auth-Assertiontoken if transacting on behalf of another merchant. - Add the BN Code associated with your PayPal account.
Step result
A successful result returns the following:
- An HTTP response code of
200or201. Returns200for an idempotent request. - An access token.
| Rel | Method | Description |
|---|---|---|
| confirm | Post | Make a POST request to generate the access token. |
Response
{
"event_name": "FASTLANE_PARTNER_TRANSACTION_PROCESSED",
"session_id": "123456789",
"partner_merchant_id": "123456789",
"partner_merchant_name": "Fastlane",
"payment_method_credential_token_id": "abc123xyz",
"transaction_amount": "100.00",
"transaction_currency_code": "USD",
"transaction_id": "987654321",
"transaction_status": "PROCESSED",
"transaction_timestamp": "1577836800",
"processing_code": "ISO8583",
"processing_code_version": "ISO8485:1993",
"fastlane_customer_id": "123456789",
"fastlane_consent_shown": true,
"fastlane_consent_given": true,
"version": "0.1.0"
}