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

## Introduction {#introduction}

In this tutorial we will create python programs that:

* Create a test transaction (simulates customer making a payment with the card).
* Transaction Notification Receiver (Webhook) Example.

## Prerequisites {#prerequisites}

First you need to create a project on `developer.mastercard.com` as described in [API Setup](https://developer.mastercard.com/transaction-notifications/documentation/tutorials/setup/api-setup/index.md). From that you should
have a .p12 key file and a consumer key.

This tutorial uses **python 3.6**.

You will need the following python modules installed:

* [requests](https://requests.readthedocs.io/en/latest/user/quickstart/#make-a-request)
* [mastercard-oauth1-signer](https://github.com/Mastercard/oauth1-signer-java)
* [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 from reference app will contain your API keys and a couple of helper functions
for handling API keys.

Note: In a real application the keys/passwords must be kept secure, for example in a HSM.

<br />

```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)
```

Update the three lines with your consumer key and p12 filename and password.

The `api.py` file from 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'

uri = f'{BASE_URL}/notifications/transactions'

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

# The test transaction (as a json string)
trans = json.dumps({
    "cardholderAmount": 9.99,
    "cardholderCurrency": "EUR",
    "cardReference": CARD_REF,
    "cardLastNumbers": 2323,
    "merchantName": "Centra"
})

# 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)

print(f'response={response.status_code}')
```

When we run the reference app and call `/createTestTransaction` endpoint, a transaction event will be sent to your notification webhook URL (which was set
up during onboarding).
Note: The file `api.py` needs to be updated with card reference from consent flow.

## Run {#run}

Install dependencies and run the tutorial:

```bash
pip3 install requests
pip3 install mastercard-oauth1-signer
pip3 install pyjwt
pip3 install flask
```

```bash
FLASK_APP=main python3 -m flask run
```

## Test Transaction {#test-transaction}

Call `/createTestTransaction` endpoint of the application.

`curl http://localhost:5000/createTestTransaction`

In the application logs, you should see the request and response (200 OK) from the test transaction API call.

To receive the notification at your webhook endpoint:

1. Your webhook endpoint (on which you want to receive the transaction notifications) must have been onboarded on to our system.
2. You must have enrolled the card through consent flow for which you are calling a test transaction notification API.

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

This is a very basic example of handling transaction events. This service needs to be listening on the
configured webhook, set during onboarding, and it needs to be secured by MTLS (see
[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=9.99 EUR at Centra

