Web pages and mobile applications for digital sales are very necessary with more and more companies beginning to require them for their stores. Within any project of this type, a payment gateway that accepts different payment methods and cards is needed.
Each payment gateway has its process and structure with different functions to be able to integrate with your application. But, the similarities between all are the public and private credentials. Public credentials are used in functions on the client-side, while private credentials are used in functions that should only be utilized on the server-side.
All the functions that must be deployed in our “server” do not necessarily have to be in a physical server or a virtual machine in the cloud. Google Cloud offers us a service called Cloud Functions where we can deploy the necessary functions for the backend of the payment gateway without the need to configure any server, without having maintenance costs and with these functions being scalable regardless of the number of operations carried out.
Mercado Pago is a payment gateway present in several Latin American countries. It offers us different payment methods, a very competitive price and different ways of integration.
We are going to make the integration through the Mercado Pago API.
The flow to integrate Mercado Pago is as follows:
A customer account must be created for the user who wants to purchase in the store. This can be done automatically by integrating with the Mercado Pago API. This part is done on the server-side.
The user adds the details of the card with which he is going to make the payment. This data is sent directly to the Mercado Pago API on the client-side to generate a card token with which the following operations can be carried out on our backend without the need to have all the card data.
With the generated card token, the card is linked with the user’s customer account. This part is done on the server-side.
The corresponding payment is made with the payment amount, the card token and the user’s customer account. This part is done on the server-side.
All the code is in GitHub Repository
Google Cloud is a cloud provider that offers us computational, database, and machine learning services, among others. gcloud
is the command-line tool that allows us to create projects in Google Cloud and configure the different services. We will use these tools to deploy the functions to the cloud.
Before continuing we have to install the tool and create our project:
To install gcloud
you can follow the documentation below: https://cloud.google.com/sdk/docs/install#deb
To create the project in Google Cloud you can follow this documentation: https://cloud.google.com/resource-manager/docs/creating-managing-projects#gcloud
Before we can program the functions, we have to obtain the access codes for our Mercado Pago account.
We go to the Mercado Pago Developers page and log into our account. If we don’t have one, we sign up.
Then we go to the top right in the button with our profile and we go to the dashboard.
Here it tells us that we do not have an application created. We create one.
We add the name and description of our application.
We leave the next screen as is and finish creating the application.
At that moment, with the application created, it redirects us to the credentials page. Here we go to the test credentials that are used in development and testing (no charges are made). To bring the application into production you need to activate and use the production credentials.
In the test credentials, the publication key is shown, which can be used on the client-side in some functions of the Mercado Pago API. Also, the Access Token is shown to us. This last credential is the one that we are going to use in the different cloud functions.
This Google Cloud service offers us the ability to deploy serverless functions that are executed through HTTP events, Firestore, Storage or Pub/Sub events. For this tutorial, we will use Python3 to program the functions.
Within the payment flow of Mercado Pago, different actions must be carried out on the server-side to keep our credentials secure. These actions are listed below with a description and the name of the cloud function that it will have throughout this tutorial:
Create Mercado Pago user (createMPuser): Each user within the store must have an account created within our Mercado Pago application.
Link credit card with the user (linkMPcard): To generate the payment, it is necessary to link the credit card with the user’s Mercado Pago account. For this action, it is not necessary to transmit the card data, but only a card token that can be generated without problems on the client-side.
Delete credit card from the user (deleteMPcard): Delete the user’s credit card.
Payment (MPpayment): The function that makes the payment. This function receives the user’s id, the credit card token and all the payment data. This is also where the logic of the store is placed when the payment is approved or denied.
All these functions will be called through an HTTP event, therefore, they will have the same initial structure. This structure handles errors, verifies that parameters are complete, and returns a response to a request to verify CORS. It will be the following:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import json
import sys
def nameOfFunction(request):
# Part 1
if request.method == 'OPTIONS':
headers = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'POST',
'Access-Control-Allow-Headers': 'Content-Type',
'Access-Control-Max-Age': '36000'
}
return ('', 204, headers)
headers = {
'Access-Control-Allow-Origin': '*'
}
try:
# Part 2
request_args = request.get_json(silent = True)
if verifyJson(request_args):
pass
# Part 3
# The logic of the
function here
else:
return ("Malformed JSON", 400, headers)
except:
# Part 4
print(sys.exc_info()[0])
print(sys.exc_info()[1])
print(sys.exc_info()[2])
return ("Error", 400, headers)
def verifyJson(request_args):
# Part 5
# Function to verify the arguments of the
function
return True
Here we have the following:
Part 1: The function receives the HTTP request in the request
variable. The following is a response in case the request needs a CORS confirmation.
Part 2: In this part the arguments are obtained to later verify if they are correct.
Part 3: If the arguments are correct then the function logic proceeds, if they are not correct, an error response is returned.
Part 4: This part handles any error that occurs anywhere in the function. The error is printed on the console and an error response is returned.
Part 5: The validations of the arguments are placed here.
With this structure we can begin to program the functions:
For this function, we are going to use the Mercado Pago entry point to Create user. You can use several parameters to have a user with a more complete profile, but we are only going to use the following:
first_name: The name of the user.
email: The user’s email.
With this we have the following function:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import requests
import json
import sys
import os
ENTRY_POINT = "https://api.mercadopago.com/v1/customers?access_token="
EMAIL = 'email'
NAME = 'first_name'
MP_ID = 'id'
def createMPuser(request):
if request.method == 'OPTIONS':
headers = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'POST',
'Access-Control-Allow-Headers': 'Content-Type',
'Access-Control-Max-Age': '36000'
}
return ('', 204, headers)
headers = {
'Access-Control-Allow-Origin': '*'
}
try:
request_args = request.get_json(silent = True)
if verifyJson(request_args):
email = request_args[EMAIL]
name = request_args[NAME].split(' ')[0]
url = ENTRY_POINT + os.environ.get('ACCESS_TOKEN', 'Invalid Token')
postData = {
'email': email,
'firstName': name,
}
response = requests.post(url, json = postData)
resData = json.loads(response.text)
# Here you can save the mercado pago user id in your data base
# write(resData[MP_ID])
return (resData[MP_ID], 200, headers)
else:
return ("Malformed JSON", 400, headers)
except:
print(sys.exc_info()[0])
print(sys.exc_info()[1])
print(sys.exc_info()[2])
return ("Error", 400, headers)
def verifyJson(request_args):
if request_args and EMAIL in request_args and NAME in request_args:
return True
return False
The function verifies that all the parameters are in request
, then the request that will be sent to the Mercado Pago API is set up. The function returns the customer id of the created user.
One important thing here is that the API access token is obtained from the environment variables. To display the function you can use the following command:
1
> gcloud beta functions deploy createMPuser--region = us - east1--memory = 128 M--runtime python37--trigger - http--set - env - vars ACCESS_TOKEN = <access-token> --source=./createMPuser
Replace <access-token>
with the access token of your Mercado Pago application.
For this function, we are going to use the Mercado Pago entry point to Save a card. To use this entry point we need the customer id of the user to be able to build the URL. Also, the card details are needed in the form of a token.
To generate the token, you need to use the following Mercado Pago entry point:
Here we place the public key of our Mercado Pago application. And the following parameters are passed to it:
card_number
expiration_year
expiration_month
security_code: It is the CVV or CVC of the credit card
This function can be called on the client-side without any concern.
With this we have the following function:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
import requests
import sys
import os
BASE_ENTRY_POINT = "https://api.mercadopago.com/v1/customers/"
CARD_ENTRY_POINT = "/cards?access_token="
CUSTOMER_ID = 'customerId'
CARD_TOKEN = 'cardToken'
MP_CARD_TOKEN = 'token'
SUCCESS_STATUS_CODE = 201
ALREADY_EXISTS_CODE = 200
def linkMPcard(request):
if request.method == 'OPTIONS':
headers = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'POST',
'Access-Control-Allow-Headers': 'Content-Type',
'Access-Control-Max-Age': '36000'
}
return ('', 204, headers)
headers = {
'Access-Control-Allow-Origin': '*'
}
try:
request_args = request.get_json(silent = True)
if verifyJson(request_args):
customerId = request_args[CUSTOMER_ID]
cardToken = request_args[CARD_TOKEN]
accessToken = os.environ.get('ACCESS_TOKEN', 'Invalid Token')
url = BASE_ENTRY_POINT + customerId + CARD_ENTRY_POINT + accessToken
data = {
MP_CARD_TOKEN: cardToken
}
response = requests.post(url, json = data)
resData = response.json()
if response.status_code == SUCCESS_STATUS_CODE or\
response.status_code == ALREADY_EXISTS_CODE:
return (response.text, 200, headers)
return ("Error", response.status_code, headers)
else:
return ("Malformed JSON", 401, headers)
except:
print(sys.exc_info()[0])
print(sys.exc_info()[1])
print(sys.exc_info()[2])
return ("Error", 400, headers)
def verifyJson(request_args):
if request_args and CUSTOMER_ID in request_args\
and CARD_TOKEN in request_args:
return True
return False
In the same way as the previous function, the access token is obtained from the environment variables. The customerId
and the card token are verified and obtained to create the request to the Mercado Pago API. The API response is returned if the card was created correctly or if it had already been created before. To deploy the function you can use the following command:
1
> gcloud beta functions deploy linkMPcard--region = us - east1--memory = 128 M--runtime = python37--trigger - http--set - env - vars ACCESS_TOKEN = <access-token> --source=./linkMPcard
Replace <access-token>
with the access token of your Mercado Pago application.
For this function we are going to use the Mercado Pago entry point to Delete a card. To use this entry point we need the customer id of the user to be able to build the URL. Also, the id of the card obtained in the response of the previous function is needed.
With this we have the following function:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import requests
import os
import sys
BASE_ENTRY_POINT = 'https://api.mercadopago.com/v1/customers/'
CARD_ENTRY_POINT = '/cards/'
AC_ENTRY_POINT = '?access_token='
CUSTOMER_ID = 'customerId'
CARD_ID = 'cardId'
SUCCESS_STATUS_CODE = 201
SECOND_SUCCESS_STATUS_CODE = 200
def deleteMPcard(request):
if request.method == 'OPTIONS':
headers = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'POST',
'Access-Control-Allow-Headers': 'Content-Type',
'Access-Control-Max-Age': '36000'
}
return ('', 204, headers)
headers = {
'Access-Control-Allow-Origin': '*'
}
try:
request_args = request.get_json(silent = True)
if verifyJson(request_args):
customerId = request_args[CUSTOMER_ID]
cardId = request_args[CARD_ID]
accessToken = os.environ.get('ACCESS_TOKEN', 'Invalid Token')
url = BASE_ENTRY_POINT + customerId + CARD_ENTRY_POINT + cardId + \
AC_ENTRY_POINT + accessToken
response = requests.delete(url)
if response.status_code == SUCCESS_STATUS_CODE\
or response.status_code == SECOND_SUCCES_STATUS_CODE:
return ("", 200, headers)
return ("Error", response.status_code, headers)
else:
return ("Malformed JSON", 400, headers)
except:
print(sys.exc_info()[0])
print(sys.exc_info()[1])
print(sys.exc_info()[2])
return ("Error", 400, headers)
def verifyJson(request_args):
if request_args and CUSTOMER_ID in request_args and CARD_ID in request_args:
return True
return False
In the same way as the previous function, the access token is obtained from the environment variables. The customerId
and thecardId
are verified and obtained to assemble the request to the Mercado Pago API. In this case, only the response status code is returned. To deploy the function you can use the following command:
1
> gcloud beta functions deploy deleteMPcard--region = us - east1--memory = 128 M--runtime = python37--trigger - http--set - env - vars ACCESS_TOKEN = <access-token> --source=./deleteMPcard
Replace <access-token>
with the access token of your Mercado Pago application.
For this function, we are going to use the Mercado Pago entry point to Create a payment. Various parameters can be used to create a more complex payment, but we will only use the following:
id: It is the id of the Mercado Pago user who is going to make the payment.
email: It is the email of the Mercado Pago user who is going to make the payment.
token: It is the token generated from the card with which the payment will be made.
transaction_amount: It is the amount of the payment to be made.
description: It is the description of the payment.
installments: It is the number of installments of the payment.
payment_method_id: It is the payment method used that includes the type of the card.
binary_mode: It is a boolean that, if true, indicates whether the payment is rejected or accepted at the moment, there are no intermediate states.
With this we have the following function:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
import requests
import sys
ENTRY_POINT = "https://api.mercadopago.com/v1/payments?access_token="
CUSTOMER_ID = 'customerId'
CUSTOMER_EMAIL = 'email'
CARD_TOKEN = 'cardToken'
MOUNT = 'mount'
PAYMENT_METHOD = 'method'
DESCRIPTION = 'description'
INSTALLMENTS = 'installments'
SUCCESS_STATUS_CODE = 201
def MPpayment(request):
if request.method == 'OPTIONS':
headers = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'POST',
'Access-Control-Allow-Headers': 'Content-Type',
'Access-Control-Max-Age': '36000'
}
return ('', 204, headers)
headers = {
'Access-Control-Allow-Origin': '*'
}
try:
request_args = request.get_json(silent = True)
if verifyJson(request_args):
customerId = request_args[CUSTOMER_ID]
email = request_args[CUSTOMER_EMAIL]
cardToken = request_args[CARD_TOKEN]
mount = round(request_args[MOUNT], 2)
paymentMethod = request_args[PAYMENT_METHOD]
description = 'Mercado Pago payment'
installments = 1
if DESCRIPTION in request_args:
description = request_args[DESCRIPTION]
if INSTALLMENTS in request_args:
installments = request_args[INSTALLMENTS]
url = ENTRY_POINT + os.environ.get('ACCESS_TOKEN', 'Invalid Token')
postData = {
'token': cardToken,
'transaction_amount': mount,
'description': description,
'installments': installments,
'payment_method_id': paymentMethod,
'binary_mode': True,
'payer': {
'id': customerId,
'email': email,
},
}
response = requests.post(url, json = postData)
if response.status_code != SUCCESS_STATUS_CODE:
# Here you can add the logic of an error in the payments
return ("Error", response.status_code, headers)
# Here you can add the login of a success payment
return (response.text, 200, headers)
else:
return ("Malformed JSON", 401, headers)
except:
print(sys.exc_info()[0])
print(sys.exc_info()[1])
print(sys.exc_info()[2])
return ("Error", 400, headers)
def verifyJson(request_args):
if request_args and CUSTOMER_ID in request_args and CARD_TOKEN in request_args
and MOUNT in request_args and PAYMENT_METHOD in request_args\
and CUSTOMER_EMAIL in request_args:
return True
return False
The function verifies and obtains the parameters to build the request for the Mercado Pago API. The amount is rounded to avoid errors in decimals. After sending the request, the answer is obtained as to whether the payment was made correctly or not. If it is correct, the logic of sending the product or the one that our store requires is followed. If the payment was rejected, within the response data is the cause of the rejection, which can be returned to the customer to inform him about the rejection. To display the function you can use the following command:
1
> gcloud beta functions deploy MPpayment--region = us - east1--memory = 128 M--runtime = python37--trigger - http--set - env - vars ACCESS_TOKEN = <access-token> --source=./MPpayment
Replace <access-token>
with the access token of your Mercado Pago application.
Google Cloud Functions allows us to implement the backend of a payment gateway without the need to configure or maintain any type of servers. Also, this backend is fully scalable regardless of the number of users or operations that are being carried out at the moment.
The functions seen in this article can be integrated into any type of client, both a web page and a mobile application. Besides, these functions can be integrated with other Google Cloud services, such as Firestore, cloud storage or cloud SQL to be able to update data such as the user’s customer id or the payment result.