# Python Tutorial
source: https://developer.mastercard.com/transaction-notifications/documentation/developer-tools/reference-app/python-tutorial/index.md

## Overview {#overview}

This tutorial uses the Python reference app
[tn-python-ref-app.zip](https://static.developer.mastercard.com/content/transaction-notifications/uploads/tn-python-ref-app.zip) (29KB) to create Python programs that:

* Create a test transaction (simulates a customer making a payment with the card).
* Receive transaction notifications using a webhook.

<br />

This app is only available for use in the Sandbox environment.

## Prerequisites {#prerequisites}

This tutorial uses **Python 3.6 or higher** and requires the following Python modules:

* [requests](https://requests.readthedocs.io/en/latest/user/quickstart/#make-a-request)
* [mastercard-oauth1-signer](https://github.com/Mastercard/oauth1-signer-python)
* [pyjwt](https://pyjwt.readthedocs.io/en/stable/#installation)

Note: `pyjwt` with RS256 signing requires `cryptography>=3.4.7`.

## API Keys Utility {#api-keys-utility}

The `api_key_util.py` file contains your API keys and two helper functions for handling API keys. Update the three lines with your consumer key and p12 filename and password. For information about creating a Mastercard Developers project, see the [Quick Start Guide](https://developer.mastercard.com/transaction-notifications/documentation/quick-start-guide/index.md).
Note: In a real application, the keys and passwords must be kept secure, for example in an HSM.

```python
import oauth1.authenticationutils as authenticationutils
from oauth1.oauth import OAuth
from OpenSSL import crypto

P12_FILE = 'YOUR .P12 FILE NAME'               # TODO: Update this
KEYSTORE_PASSWORD = 'YOUR KEYSTORE PASSWORD'   # TODO: Update this
CONSUMER_KEY = 'YOUR CONSUMER KEY'             # TODO: Update this

# Load the API signing key
signing_key = authenticationutils.load_signing_key(P12_FILE, KEYSTORE_PASSWORD)

def getPrivateKeyPEM():
    """
    Get the private key from P12 (for use in JWT)
    """
    with open(P12_FILE, "rb") as file:
        p12 = crypto.load_pkcs12(file.read(), KEYSTORE_PASSWORD)
        return crypto.dump_privatekey(crypto.FILETYPE_PEM, p12.get_privatekey())

def getAuthHeader(uri, method='GET', payload=None):
    """
    Create Auth header for an API request
    """
    return OAuth().get_authorization_header(uri, method, payload, CONSUMER_KEY, signing_key)
```

The `api.py` file from the reference app shows how to trigger a test transaction for a card:

```python
#!/usr/bin/env python3
#
# Send a test transaction
#
import requests
import json
from api_key_util import getAuthHeader

BASE_URL = 'https://sandbox.api.mastercard.com/openapis/notifications'

CARD_REF = 'CARD REFERENCE FROM CONSENT FLOW'    # TODO: Replace this with cardReference from consent flow

def defaultTestPayload():
    """Return the default test transaction payload as a JSON string."""
    return json.dumps({
        "cardholderAmount": 9.99,
        "cardholderCurrency": "EUR",
        "cardReference": CARD_REF,
        "merchantName": "Centra"
    }, indent=2)


def createTestTransaction(payload=None):
    uri = f'{BASE_URL}/transactions'

    # The test transaction (as a json string)
    trans = payload if payload else defaultTestPayload()

    # Create OAuth header for this request
    authHeader = getAuthHeader(uri, method='POST', payload=trans)
    headerDict = {
        'Authorization' : authHeader,
        'Content-Type': 'application/json'
    }

    # Call the API
    response = requests.post(uri, headers=headerDict, data=trans, verify=False)
    print(f'response={response.status_code}')
    return response.status_code
```

Warning: `verify=False` disables SSL certificate verification. This is only acceptable in Sandbox testing. Do not use it in production code.

When you run the reference app and call the `/createTestTransaction` endpoint, a transaction event is sent to your notification webhook URL (which was set up during onboarding).
Note: Update `api.py` with the card reference from the consent flow.

## Install and Run {#install-and-run}

Install dependencies and run the tutorial.
* MacOS/Linux
* Windows

```macOS/Linux
pip3 install requests
pip3 install mastercard-oauth1-signer
pip3 install pyjwt
pip3 install flask
```

```Windows
pip install requests
pip install mastercard-oauth1-signer
pip install pyjwt
pip install flask
```

Then start the app:
* MacOS/Linux
* Windows

```macOS/Linux
FLASK_APP=main python3 -m flask run
```

```Windows
set FLASK_APP=main
python -m flask run
```

## Test Transaction {#test-transaction}

To send a test transaction using the reference app:

1. Open <http://localhost:5000/> in a browser. The home page shows two API cards.

   ![The Transaction Notifications reference app home page, showing the Test Transaction API and Undelivered Notifications API cards](https://static.developer.mastercard.com/content/transaction-notifications/uploads/refapp-home.png)
2. Select **Test Transaction API**.

   ![The Test Transaction API form, showing the Test Cases drop-down, Payload field, and Send Test Transaction button](https://static.developer.mastercard.com/content/transaction-notifications/uploads/refapp-test-transaction-form.png)

   The Test Transaction API page shows the **Payload** field, populated with the corresponding JSON. Edit the payload if needed.
3. Select **Send test transaction**. A success message confirms that the notification was created and sent to your registered webhook.

Note: To receive the notification at your webhook endpoint, your webhook endpoint (on which you want to receive the transaction notifications) must be onboarded onto Mastercard Developers. If sandbox webhook delivery is not configured, fetch notifications from the [Undelivered Notifications API](https://developer.mastercard.com/transaction-notifications/documentation/developer-tools/reference-app/python-tutorial/index.md#undelivered-notifications).

### Transaction Notification Receiver (Webhook) Example {#transaction-notification-receiver-webhook-example}

This example shows how to handle transaction events. This service must listen on the configured webhook, set during onboarding, and it must be secured by MTLS ([Transaction Notifications Webhook](https://developer.mastercard.com/transaction-notifications/documentation/api-reference/transaction-notification-webhook/index.md)).

```python
#!/usr/bin/env python3
#
# Program that receives transaction notifications
#
# Python 3 server example
from http.server import BaseHTTPRequestHandler, HTTPServer
import json

hostName = "localhost"
serverPort = 8080

class TransNotificationHandler(BaseHTTPRequestHandler):
    def do_POST(self):
        content_length = int(self.headers['Content-Length'])
        trans = json.loads(self.rfile.read(content_length))
        cardReference = trans['cardReference']
        amount = trans['cardholderAmount']
        currency = trans['cardholderCurrency']
        merchant = trans['merchantName']
        print(f'received transaction for card {cardReference}, amount={amount} {currency} at {merchant}')
        self.send_response(200)
        self.end_headers()

if __name__ == "__main__":
    server = HTTPServer((hostName, serverPort), TransNotificationHandler)

    try:
        server.serve_forever()
    except KeyboardInterrupt:
        pass

    server.server_close()
```

When this is running, a transaction notification is sent as follows:

    received transaction for card 6c9a079c-18dc-4881-9907-467aad648333, amount=10.99 EUR at Merchant Tutorial

## Undelivered Notifications {#undelivered-notifications}

If you did not receive the notification at your webhook endpoint, use the Undelivered Notifications API to fetch it.

The `api.py` file shows how to call the Undelivered Notifications API:

```python
def undeliveredNotifications(undeliveredCursor=0):
    uri = f'{BASE_URL}/undelivered-notifications?after={undeliveredCursor}'

    # Create OAuth header for this request
    authHeader = getAuthHeader(uri, method='GET')
    headerDict = {
        'Authorization' : authHeader,
        'Content-Type': 'application/json'
    }

    # Call the API
    response = requests.get(uri, headers=headerDict, verify=False)
    return response
```

Warning: `verify=False` disables SSL certificate verification. This is only acceptable in Sandbox testing. Do not use it in production code.

To fetch undelivered notifications using the reference app:

1. Open <http://localhost:5000/> in a browser. The home page shows two API cards.

2. Select **Undelivered Notifications API**.

   ![The Undelivered Notifications API form](https://static.developer.mastercard.com/content/transaction-notifications/uploads/refapp-undelivered-transaction-form.png)
3. Optionally, enter a cursor value in the **Next cursor** field to page through results.

   The **Response** field shows the notifications returned by the API.

Sample response:

```json
{
  "nextCursor": 5621260951,
  "data": [
    {
      "notificationSequenceId": "5621260801",
      "cardAcceptorId": "123456",
      "financialNetworkCode": "MCU",
      "recurringTransaction": "false",
      "channel": "ECOM",
      "transactionLocalDate": "2023-09-08",
      "cardReference": "e7917328-983f-410a-9c58-afc83ff5c856",
      "systemDateTime": "2023-09-08T20:46:03+0000"
    }
  ]
}
```

Use the `nextCursor` value in the **Next cursor** field to fetch the next page of results.
