Integrate Your Own Form

On this page:


Your Own Form integration gives you complete control over the checkout experience and keeps PCI requirements to a minimum.


Key benefits include:

  • Helping you to be PCI-DSS compliant using the SAQ-A-EP self-assessment questionnaire.
  • You keep full control over the user experience and the customer journey through checkout.


When you integrate using your Own Form, you must ensure:

  • Your site is secured using TLS (1.2, or the latest version).
  • All communications are over HTTPS.
  • You have your Integration Key and Integration Password in order to authenticate your requests. (Read how to get your Pi credentials).
Important: You must keep your Integration Key and Integration Password secret!
  • You link your payment page to our JavaScript library (sagepay.js) using the following snippet:
    <script src=""></script>

The sagepay.js ensures sensitive card data is transmitted directly from the customer's browser to Opayo without any details passing through your server.

Step 1: Create a merchant session key (MSK)

Generate a Merchant Session Key (merchantSessionKey) using your Integration Key and Integration Password to authenticate your requests.  A valid merchantSessionKey is required to initialise your own form checkout.

The Merchant Session Key is used to create a unique Card Identifier (the tokenised card details). The Merchant Session Key expires:

  • After 400 seconds
  • After 3 failed attempts to create a Card Identifier

A new Merchant Session Key must be created each time you load the payment page, or when an existing Merchant Session Key expires. Send a HTTP POST request to our /merchant-session-keys endpoint using your Integration Key and password to authenticate the request.

Example request

curl  \ -H "Authorization: Basic aEpZeHN3N0hMYm...RqNVVzNXU="  \ -H "Content-type: application/json" \ -X POST \ -d '{


For HTTP Basic Authentication, you must:

  • Format the string as, 'integrationKey:integrationPassword', encode it using Base64 encoding and include it in the Authorization header.
  • Enter your unique Opayo vendor name in the vendorName field.

Example response



  • When a Merchant Session Key is invalid, or when the Merchant Session Key has expired (after 400 seconds), you can create an endpoint on your server that generates a new Merchant Session Key for the current transaction.
  • When you get a HTTP 401 (Unauthorised) response, you can make an AJAX request to the same endpoint and replace the Merchant Session Key in the page with the new one.

Step 2: Include sagepay.js in your payment form

You must include the link to the Sagepay JavaScript library in the code of the page where you collect your customers’ card details as follows:

 <script src=""></script>

Step 3: Load the form and create a card identifier

Your form must collect all of the following card details for the sagepay.js to work correctly:

  • Cardholder name
  • Card number
  • Expiry date (formatted as MMYY) 
  • Security code
Important: To prevent card data being transmitted to your server, ensure you do not set a name attribute on these fields.

When Steps 1 and 2 are complete, you can load the form. You must:

  1. Include the link to sagepay.js on the page.
  2. Embed the merchantSessionKey
  3. Call the Sagepay.tokeniseCardDetails to tokenise the card details.

When your customer submits the form, their payment details are:

  • Validated
  • Tokenised
  • Passed as a hidden field called cardIdentifier, to POST with the form data
Important: You must Submit Payments from Your Server to complete the transaction.

Example payment form:

<!DOCTYPE html>
<html lang="en">
<title>Example Payment Form</title>
<form method="post">
<label for="id1">Name:</label>
<div><input id="id1" data-card-details="cardholder-name"></div>
<label for="id2">Card:</label>
<div><input id="id2" data-card-details="card-number"></div>
<label for="id3">Expiry:</label>
<div><input id="id3" data-card-details="expiry-date"></div>
<label for="id4">CVV:</label>
<div><input id="id4" data-card-details="security-code"></div>
<input type="hidden" name="card-identifier">
<div><button type="submit">Pay Now</button></div>
<script src=""></script>
document.querySelector('[type=submit]') .addEventListener('click', function(e) { e.preventDefault(); // to prevent form submission
 sagepayOwnForm({ merchantSessionKey: 'FC71C349-3AFE-44CF-915D-7E0A46375B41' }) .tokeniseCardDetails({ cardDetails: { cardholderName: document.querySelector('[data-card-details="cardholder-name"]').value,
 cardNumber: document.querySelector('[data-card-details="card-number"]').value,
 expiryDate: document.querySelector('[data-card-details="expiry-date"]').value,
 securityCode: document.querySelector('[data-card-details="security-code"]').value },
 onTokenised : function(result) { if (result.success) { document.querySelector('[name="card-identifier"]').value = result.cardIdentifier;
 document.querySelector('form').submit(); } else { alert(JSON.stringify(result)); } } }); }, false)