Use Payment Element across multiple processors
Learn how to collect card details with Payment Element and use them with a third-party processor.
Use Payment Element to build a custom payment flow that allows you to collect card details, create a PaymentMethod, and forward the payment method to a third-party processor.
Request access
To gain access to use Stripe’s forwarding service, contact Stripe support.
Create a PaymentMethod Client-side
Use a Payment Element to collect payment details. If you’re not integrated with the Payment Element, learn how to get started. After the customer submits your payment form, call stripe.createPaymentMethod to create a PaymentMethod. Pass the PaymentMethod ID to the ForwardingRequest endpoint on your server.
checkout.js
// Set your publishable key: remember to change this to your live publishable key in production
// See your keys here: https://dashboard.stripe.com/apikeys
const stripe = Stripe('pk_test_TYooMQauvdEDq54NiTphI7jx');
const options = {
mode: 'payment',
amount: 1099,
currency: 'usd',
paymentMethodCreation: 'manual',
// Fully customizable with appearance API.
appearance: {
theme: 'stripe'
}
};
// Set up Stripe.js and Elements to use in checkout form
const elements = stripe.elements(options);
const paymentElementOptions = {
layout: "tabs",
};
// Create and mount the Payment Element
const paymentElement = elements.create('payment', paymentElementOptions);
paymentElement.mount('#payment-element');
const form = document.getElementById('payment-form');
const submitBtn = document.getElementById('submit');
const handleError = (error) => {
const messageContainer = document.querySelector('#error-message');
messageContainer.textContent = error.message;
submitBtn.disabled = false;
}
form.addEventListener('submit', async (event) => {
// We don't want to let default form submission happen here,
// which would refresh the page.
event.preventDefault();
// Prevent multiple form submissions
if (submitBtn.disabled) {
return;
}
// Disable form submission while loading
submitBtn.disabled = true;
// Trigger form validation and wallet collection
const { error: submitError } = await elements.submit();
if (submitError) {
handleError(submitError);
return;
}
// Create the PaymentMethod using the details collected by the Payment Element
const { error, paymentMethod } = await stripe.createPaymentMethod({
elements,
params: {
billing_details: {
name: 'John Doe',
}
}
});
if (error) {
// This point is only reached if there's an immediate error when
// creating the PaymentMethod. Show the error to your customer (for example, payment details incomplete)
handleError(error);
return;
}
// Call the ForwardingRequest endpoint on your server
const res = await fetch("/create-forwarding-request", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
paymentMethodId: paymentMethod.id,
}),
});
const data = await res.json();
// Handle the response or errors
handleServerResponse(data);
});
Create a ForwardingRequest
Contact Stripe support to configure your destination endpoint and begin forwarding transactions. Send the card details to this test endpoint before you connect your integration with your third-party processor.
app.js
// Don't put any keys in code. See https://docs.stripe.com/keys-best-practices.
const stripe = require("stripe")("sk_test_BQokikJOvBiI2HlWgH4olfQ2");
const express = require('express');
const app = express();
app.set('trust proxy', true);
app.use(express.json());
app.use(express.static("."));
app.post('/create-forwarding-request', async (req, res) => {
try {
const forwardedReq = await stripe.forwarding.requests.create(
{
payment_method: req.body.paymentMethodId,
url: '{{DESTINATION_ENDPOINT}}',
request: {
headers: [{
name: 'Destination-API-Key',
value: '{{DESTINATION_API_KEY}}'
},{
name: 'Destination-Idempotency-Key',
value: '{{DESTINATION_IDEMPOTENCY_KEY}}'
}],
body: JSON.stringify({
"amount": {
"currency": "USD",
"value": 1099
},
"reference": "Your order number",
"card": {
"number": "",
"exp_month": "",
"exp_year": "",
"cvc": "",
"name": ""
}
})
},
replacements: ['card_number', 'card_expiry', 'card_cvc', 'cardholder_name'],
}
);
if (forwardedReq.response_details.status != 200) {
// Return error based on third-party API response code
} else {
// Parse and handle the third-party API response
const forwardedResult = JSON.parse(forwardedReq.response_details.body);
res.json({
status: forwardedReq.response_details.status
});
}
} catch (err) {
res.json({
error: err
});
}
});
app.listen(3000, () => {
console.log('Running on port 3000');
});
Handle the Response Client-side
After you send the request, you must handle the response.
const handleServerResponse = async (response) => {
if (response.error) {
// Show error on payment form
} else if (response.status != 200) {
// Show error based on response code
} else {
// Parse the response body to render your payment form
}
}
