Michael Haephrati
Michael Haephrati

Reputation: 4245

Integrating with PayPal with no web site

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.

Upvotes: 1

Views: 52

Answers (1)

Michael Haephrati
Michael Haephrati

Reputation: 4245

We finally found a way, which is why I publish this answer along with some code (a POC) we have developed. This is 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 can use the Sandbox to test the API

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.

This 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:

// Send string to PayPal server
WinHttpClient WinClient1(ExpChkoutStr.GetBuffer());
WinClient1.SetRequireValidSslCertificates(false);
WinClient1.SendHttpRequest(L"GET");
httpResponseContent1 = WinClient1.GetResponseContent();
CString strTransactionRet = UrlDecode(httpResponseContent1.c_str());

The WinHTTP class was developed by Cheng Shi.

The Express Checkout String (ExpChkoutStr) is generated by another function which uses the member variables' values and the transaction details 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";

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;

We then programatically open this one-time web page using the default web browser:

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.

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;
}

Upvotes: 1

Related Questions