SMS Verify API - Tutorial: Implement PSD2 SCA for payments in Python

This Python tutorial teaches you how to implement Strong Customer Authentication (SCA) for a purchase transaction, as part of complying with the latest version of Europe's Payment Services Directive (PSD2).

You might be an e-commerce platform, helping the merchant conduct payment verification or you might be a payment service provider (PSP) on the buyer's phone, helping keep their purchase secure. In both cases the verification flow is largely the same.

Even if your business is not based in Europe, it's a good idea to comply with PSD2 both because you may have European customers (making you subject to the regulation) and because it introduces some good security best practices.

This tutorial walks you through using the Telesign SMS Verify API SDK to code a practice integration, while also pointing out places where you'll modify the code for your production environment.

You can also skip straight to the sample code in GitHub.

Before you begin

Make sure you have the following before you start.

  • Authentication credentials: Your Customer ID and API Key. If you need help finding these items, go to the support article How do I find my Customer ID and API Key.
  • Testing device: A mobile phone on which you can receive SMS.
  • (Optional) Verify Plus enabled: Confirm with our Customer Support Team that this feature has been enabled for your account.
  • (Optional) SIM Swap for SMS Verify enabled: Confirm with our Customer Support Team that this feature has been enabled for your account.

Verify Plus and SIM Swap aren't required for verification, but provide an extra layer of security for both "friendly" fraud and real fraud, respectively.

📘

NOTE:

This tutorial uses Python 3.8.1. Please modify accordingly if you are using a different version of Python.

Step 1: Download the SDK

  1. Create a directory on your machine where you want to download the Telesign Python SDK. This should not be in the same directory as where you build your integration.
cd ~/code/repos
mkdir telesign_sdks
cd telesign_sdks
  1. In the new directory you created, clone the SDK from GitHub. A new directory should appear called python_telesign_enterprise.
git clone https://github.com/TeleSign/python_telesign_enterprise.git

Step 2: Set up your project

  1. Create another directory where you want this integration to go (must be outside of the SDK directory you just created). In this example I've created a series of directories to further organize things.
cd ~/code/repos/telesign_integrations/python/sdk/sms_verify
mkdir psd2
cd psd2
  1. Install the SDK in this new directory using the command below. It references the path to where you downloaded the SDK. Once the SDK is installed, you should see Successfully installed telesignenterprise in the terminal.
pip install -e ~/code/repos/telesign_sdks/python_telesign_enterprise/
  1. Create a new file in your integration folder called verify_with_own_code.py and open it in your editor.
touch verify_with_own_code.py

Step 3: Create code to send the SMS

  1. Specify the encoding of the file; this must be on line 1. This is important for proper processing of various currency symbols.

verify_with_own_code.py

# -*- coding: utf-8 -*-
  1. Add code to import dependencies.

verify_with_own_code.py

from telesignenterprise.verify import VerifyClient
from telesign.util import random_with_n_digits
import os
  1. Define variables to store your authentication credentials; either replace the defaults below or set them as environment variables.

verify_with_own_code.py

customer_id = os.getenv('CUSTOMER_ID', 'FFFFFFFF-EEEE-DDDD-1234-AB1234567890')
api_key = os.getenv('API_KEY', 'ABC12345yusumoN6BYsBVkh+yRJ5czgsnCehZaOYldPJdmFh6NeX8kunZ2zU1YWaUw/0wV6xfw==')
  1. Define a variable to hold the end-user's phone number you want to send a verification code to. For this tutorial, replace the default below with a hardcoded phone number for a device you can use for testing.

verify_with_own_code.py

phone_number = os.getenv('PHONE_NUMBER', '+447975777666')

📘

NOTE:

In your production integration, have phone_number pull from input for this buyer or an end user database instead of hardcoding it.

  1. Randomly generate your verification code. We will use a Telesign SDK utility for this. The parameter value 5 specifies the number of digits generated:

verify_with_own_code.py
verify_code = random_with_n_digits(5)

  1. This is where we fulfill PSD2's requirement for dynamic linking. Part of PSD2's requirements is "the payer is made aware of the amount of the payment transaction and of the payee". To comply with PSD2, you must invalidate the verification code if either of these two elements changes. So, the code is "linked" to these elements.

📘

NOTE:

We used €40 as the example value here because PSD2's threshold for using SCA is €30. You can choose either to perform SCA for all transactions or check whether the amount is greater than €30 first.

verify_with_own_code.py

transaction_payee = "Viatu"
transaction_amount = "€40"

📘

NOTE:

In your production integration, have transaction_payee and transaction_amount pull from the initiating transaction instead of hardcoding them.

  1. Specify the language. This triggers the service to use one of our pre-written PSD2/SCA templates. A full list of supported languages can be found on SMS Verify - Supported languages.

verify_with_own_code.py

lang = "en-GB"

📘

NOTE:

If your desired language is not represented in our PSD2/SCA templates, you can still use SMS Verify API for SCA. You just need to provide the text of your template in the request. Contact our Customer Support Team for more details.

  1. Instantiate a verification object with your authentication credentials.

verify_with_own_code.py

verify = VerifyClient(customer_id, api_key)
  1. Send a verification SMS to the end-user and store the response. Behind the scenes, this sends an HTTP request to the Telesign SMS Verify API. TeleSign then sends an SMS with the code to the end-user. If SIM Swap indicates likelihood of real fraud or Score indicates likelihood of friendly fraud, the verification code is not sent.

verify_with_own_code.py

response = verify.sms(phone_number, verify_code=verify_code, transaction_payee=transaction_payee, transaction_amount=transaction_amount, language=lang)
  1. Display your response body in the console for debugging purposes.

verify_with_own_code.py

print(f"\nResponse:\n{response.body}\n")

📘

Note:

In your production integration, you would remove this debugging statement.

  1. Collect the potential verification code entered by the end-user in your application. In this tutorial, we will simulate this by prompting for input from the command line.

verify_with_own_code.py

user_entered_verify_code = input("Please enter the verification code you were sent: ")

📘

NOTE:

In your production implementation, you will listen for input from your website or other application where the end-user is trying to make a purchase.

  1. Determine if the user-entered code matches your verification code, and resolve the purchase attempt accordingly. In this tutorial, we just report whether the codes match.

verify_with_own_code.py

if verify_code == user_entered_verify_code.strip():
    print("Your code is correct.")
else:
    print("Your code is incorrect.")

Step 4: Test your integration

  1. Switch from your editor to the terminal and run verify_with_own_code.py.
python verify_with_own_code.py
  1. You should receive an SMS on your phone that looks like this.

A screenshot of a SMS message containing a one time passcode displayed on a phone.

  1. In the terminal, you should see a prompt to enter a code. Enter the code from your phone to test a successful verification.

Bash

Please enter the verification code you were sent: 43353
Your code is correct.
  1. Now let's test an unsuccessful verification. Run verify_with_own_code.py again. You should receive a new and different SMS code on your phone. Enter something else though in the command prompt, and you should get a message that verification failed.

Bash

Please enter the verification code you were sent: 55555
Your code is incorrect.

The complete sample code for this tutorial can be found on GitHub.

Alternate sample code