Integrating with PayPal smoothly






4.64/5 (6 votes)
How to easily integrate and interface with PayPal Express Checkout API from a Windows c++ application
Introduction
This article was written following a need to integrate PayPal Express Checkout in a c++ Win32 application.
Background
I was thinking about integration in the background without any website other than the payment page as part of a desktop application in c++. Would it be possible to following the following scenario:
- Generate the invoice / sale and via REST API obtain some sort of unique ID for the transaction to come.
- Redirect to Paypal web site to a ad-hoc payment page, using the unique ID.
- In the background, check every few minutes, via REST API, if the payment was made.
The Solution
I have found a way and created a POC for a built-in payment processing engine which allows you to accept payments from any credit card holder (regardless of being a PayPal customer) and pay for unlocking a software product or for specific features.
To process payments you need to apply as a PayPal developer and obtain your own PayPal credentials. You will then receive 2 sets of credentials. One for tests ("sandbox") and the other for real life.
First you should test the Sandbox to test the API.
I have created a PayPal class with one "init()" used for both "sandbox" and real life transactions.
Void InitPayPal(BOOL Sandbox, LPTSTR User, LPTSTR password, LPTSTR signature, LPTSTR successUrl, LPTSTR failedURL)
Sandbox – indicates whether you are testing your integration using PayPal's Sandbox account, or going live.
User – your PayPal user name
Password – your PayPal password
Signature – you PayPal signature
successUrl – a url leading to a web page which you wish to be shown after successful payment.
failedURL – a url leading to a web page which you wish to be shown after failed / cancalled payment.
The InitPayPal() function is straight forward:
void InitPayPal(BOOL Sandbox, LPTSTR User, LPTSTR password, LPTSTR signature, LPTSTR successUrl, LPTSTR failedURL, LPWSTR ProductName) { m_sandbox = Sandbox; m_user = User; m_password = password; m_signature = signature; m_SuccessURL = successUrl; m_FailureURL = failedURL; m_ProductName = ProductName; CUR_CHAR = L"$"; SYSTEMTIME st; GetSystemTime(&st); g_tPayStart = CTime(st); InitilizedPaypal = TRUE; }
Initiating a payment
When you wish to initiate a payment from your program, you call the following function which I wrote which generally build a string (ExpChkoutStr) and use the following PayPal API call:
For all HTTP communication, I used The WinHTTP class was developed by Cheng Shi.
Here is how I send the initial request to the PayPal servers:
// Send string to PayPal server WinHttpClient WinClient1(ExpChkoutStr.GetBuffer()); WinClient1.SetRequireValidSslCertificates(false); // Now we get PayPal's response: WinClient1.SendHttpRequest(L"GET"); httpResponseContent1 = WinClient1.GetResponseContent(); CString strTransactionRet = UrlDecode(httpResponseContent1.c_str());
As you can see we are sending PayPal a long string we generate using another function. This function combined the credentials, the nature of the requested transaction, additional details all into a single string.
CString result; result = (m_sandbox) ? PAYPAL_SANDBOX_HTTPS : PAYPAL_REAL_HTTPS; result += Q_USER; result += m_user; result += AND_PASSWORD; result += m_password; result += AND_SIGNATURE; result += m_signature; result += AND_PAYMENTAMOUNT; result += strAmount; result += L"&METHOD=SetExpressCheckout"; result += AND_RETURN_URL; result += m_SuccessURL; result += AND_CANCEL_URL; result += m_FailureURL; result += AND_VERSION; result += L"&NOSHIPPING=1"; result += L"&ADDROVERRIDE=0&BRANDNAME=Secured Globe, Inc."; result += L"&PAYMENTREQUEST_0_DESC="; result += L"Item name: " + strUnits + L"(" + UnitName + L") "; result += L"Price: " + strAmount; result += L"&NOTETOBUYER=Here you can add a note to the buyer";
Now, result will hold the string to be sent in the previous code block.
We then examine the result we have received back from PayPal:
The result from the PayPal server is a "token" used to figure out a one-time web page (LinkToOpen ) that must be opened in order for the end user to confirm the purchase:
// Extract token from response CString sToken = ExtractElement(strTransactionRet, L"TOKEN"); if (sToken == L"") { wprintf(L"Internal error: (Paypal): no token was generated (%s)", strTransactionRet); MessageBox(NULL, L"Internal payment processing error", L"", MB_OK); return FALSE; } CString LinkToOpen = (m_sandbox) ? SANDBOX_PAYPAL_CHECKOUT : REAL_PAYPAL_CHECKOUT; LinkToOpen += L"&token="; LinkToOpen += sToken;
To extract elements from the PayPal server response, we wrote this small function:
CString ExtractElement(CString EntireString, CString ElementName) { CString result = L""; CString WhatToFind = ElementName + L"="; int foundToken = EntireString.Find(WhatToFind); if (foundToken > -1) { int EndToken = EntireString.Find(L"&", foundToken); if (EndToken != -1) { result = EntireString.Mid(foundToken + ElementName.GetLength()+1, EndToken - foundToken - ElementName.GetLength()-1); } } return result; }
Invoking a one-time web page
The next step is to open the default web browser with a one-time generated secure web page hosted by the PayPal server:
STARTUPINFO si; PROCESS_INFORMATION pi; ZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); ZeroMemory(&pi, sizeof(pi)); CString command_line; command_line.Format(L"cmd.exe /c start \"link\" \"%s\" ", LinkToOpen); // LinkToOpen if (!CreateProcess(NULL, // No module name (use command line) command_line.GetBuffer(), NULL, // Process handle not inheritable NULL, // Thread handle not inhberitable FALSE, // Set handle inheritance to FALSE NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW, // No creation flags NULL, // Use parent's environment block NULL, // Use parent's starting directory &si, // Pointer to STARTUPINFO structure &pi) // Pointer to PROCESS_INFORMATION structure ) { wprintf(L"CreateProcess failed (%d).\n", GetLastError()); // At this stage you would want to mark this transaction as "failed" return FALSE; }
Then the rest is to maintain a small database of all pending transactions and follow up each of them until it is either succeed, failed, cancelled or if a timeout has passed.
User Interface
We have used a minimal UX integrated in our small DRM component, which looks like this:
Then the one-time web page will look like this:
Examples are from a real product Datattoo Recovery.