Click here to Skip to main content
15,884,099 members
Articles / Desktop Programming / Win32

Integrating with PayPal smoothly

Rate me:
Please Sign up or sign in to vote.
4.64/5 (6 votes)
12 Jan 2018CPOL3 min read 9.8K   6   10
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)


Written By
CEO Secured Globe, Inc.
United States United States
Michael Haephrati is a music composer, an inventor and an expert specializes in software development and information security, who has built a unique perspective which combines technology and the end user experience. He is the author of a the book Learning C++ , which teaches C++ 20, and was published in August 2022.

He is the CEO of Secured Globe, Inc., and also active at Stack Overflow.

Read our Corporate blog or read my Personal blog.





Comments and Discussions

 
QuestionCan't understand Pin
Member 1477334316-Dec-21 0:31
Member 1477334316-Dec-21 0:31 
AnswerRe: Can't understand Pin
Michael Haephrati16-Dec-21 0:54
professionalMichael Haephrati16-Dec-21 0:54 
GeneralRe: Can't understand Pin
Member 1477334316-Dec-21 2:00
Member 1477334316-Dec-21 2:00 
AnswerRe: Can't understand Pin
Michael Haephrati16-Dec-21 2:08
professionalMichael Haephrati16-Dec-21 2:08 
GeneralRe: Can't understand Pin
Member 1477334316-Dec-21 2:11
Member 1477334316-Dec-21 2:11 
AnswerRe: Can't understand Pin
Michael Haephrati16-Dec-21 2:14
professionalMichael Haephrati16-Dec-21 2:14 
GeneralRe: Can't understand Pin
Member 1477334316-Dec-21 2:20
Member 1477334316-Dec-21 2:20 
GeneralRe: Can't understand Pin
Michael Haephrati16-Dec-21 2:28
professionalMichael Haephrati16-Dec-21 2:28 
GeneralRe: Can't understand Pin
Member 1477334316-Dec-21 2:34
Member 1477334316-Dec-21 2:34 
GeneralRe: Can't understand Pin
Michael Haephrati16-Dec-21 4:21
professionalMichael Haephrati16-Dec-21 4:21 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.