Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / Win32

Integrating with PayPal smoothly

4.64/5 (6 votes)
12 Jan 2018CPOL3 min read 10.6K  
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:

  1.  Generate the invoice / sale and via REST API obtain some sort of unique ID for the transaction to come.
  2. Redirect to Paypal web site to a ad-hoc payment page, using the unique ID.
  3. 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.

C++
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.

 

 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)