Managing ACH-Out via the API

ProPay’s API method for a partner or merchant to push funds out of an account, and to the currently on-file bank is quite simple.  All you need to provide are a ProPay account number and the amount of money you want to move.  This API method does NOT allow you to manage the destination bank account.  It is only used to push money to an account once it’s been established.  There area few things you really need to consider:

Batching
One of the things merchants love about sweeps is that ProPay bundles transactions into groups that correspond to bank deposits.  Large, sophisticated merchants expect this functionality and require that deposits are batched and reconcilable.  If you intend to control deposits using your own logic, you will need to reproduce this behavior.  In so doing, you will want to consider all transaction types and that can be tough.  For example:
  • Credit card and eCheck transactions settle into ProPay accounts at a scheduled time each day. This time is configurable for your program.
  • Refunds take effect immediately and impact the balance in a merchant’s ProPay account.
  • Chargebacks and ACH rejects are applied whenever they happen.
Due to these timing differences, it’s difficult if not impossible to create a decent batch.  At the very least, you will want to ensure that record and account for your refunds as well as the transactions initiated through your solution.  You will also want to disable any access, by the merchant to a ProPay-hosted site, or our mobile application.  Finally, you will want to use ProPay’s web hooks for Chargebacks and ACH Rejects so that you are made aware the instant they occur.

Keeping track of the balance
This one is closely related to batching, in that you should use an API call to get the current ProPay balance to act as a ‘checksum’ against the total value of transactions that you intend to batch up.  If your merchants don’t really care about batching, you can simply use this same API method to display the total available amount in a ProPay account prior to moving money via the API.

Accounting for a fee that might exist
Your program’s merchants might be charged a small fee to move the money out of their ProPay accounts.  Think through how you want to display the total available balance, and then make the right amount available for transfer.
How to call this method?

Example Request

Example Response

Implementation Details
Request Submission

Response Handling

Request Submission

Response Handling

Request Submission

Response Handling

Request Submission

Response Handling

Request Values
Response Values
How to call this method?

You should submit a post of XML data to the following URL
 
HTTP URL(s)
Example Request

Example Response

<?xml version='1.0'?>
<!DOCTYPE Request.dtd>
<XMLRequest>
<certStr>My certStr</certStr>
<class>partner</class>
<XMLTrans>
<transType>38</transType>
<amount>100</amount>
<accountNum>123456</accountNum>
</XMLTrans>
</XMLRequest>
<XMLResponse>
<XMLTrans>
<transType>38</transType>
<accountNum>123456</accountNum>
<status>00</status>
<transNum>1820</transNum>
</XMLTrans>
</XMLResponse>
Implementation Details
Request Submission

namespace MSAPI_ProcessTransaction
 {
 using System;
 using System.Collections.Generic;
 using System.IO;
 using System.Linq;
 using System.Net;
 using System.Text;
 using System.Xml;
 using System.Xml.Linq;
 using System.Xml.Serialization;

/*
 ProPay provides the following code “AS IS.”
ProPay makes no warranties and ProPay disclaims all warranties and conditions, express, implied or statutory,
 including without limitation the implied warranties of title, non-infringement, merchantability, and fitness for a particular purpose.
 ProPay does not warrant that the code will be uninterrupted or error free,
 nor does ProPay make any warranty as to the performance or any results that may be obtained by use of the code.
 */
 public class ProcessTransactionTransType38
 {
 public static void ProcessTransaction()
 {
 var processRequest = new XmlTransactionRequest { CertificationString = "YourCertStringGoesHere", TerminalID = "YourTermId", };
 var xmlTransaction = new XmlProcessTransaction
 {
 TransType = "38",
 accountNum = "12345678",
 amount = "100",
 };
 processRequest.Transactions.Add(xmlTransaction);
 string request = XmlSerializer<XmlTransactionRequest>.WriteToString(processRequest);
 SubmitRequest(request);
 }

private static void SubmitRequest(string request)
 {
 byte[] dataToSend = Encoding.UTF8.GetBytes(request);

// Change the following URL to point to production instead of integration
 WebRequest webRequest = WebRequest.Create("https://xmltest.propay.com/API/PropayAPI.aspx");
 webRequest.Method = "POST";
 webRequest.ContentLength = dataToSend.Length;
 webRequest.ContentType = "text/xml";
 Stream dataStream = webRequest.GetRequestStream();
 dataStream.Write(dataToSend, 0, dataToSend.Length);
 dataStream.Close();

string response = string.Empty;

try
 {
 WebResponse apiResponse = webRequest.GetResponse();


using (StreamReader sr = new StreamReader(apiResponse.GetResponseStream()))
 {
 response += sr.ReadToEnd();
 }
 }
 catch (WebException wex)
 {
 HttpWebResponse httpResponse = wex.Response as HttpWebResponse;
 using (Stream responseStream = httpResponse.GetResponseStream())
 using (StreamReader reader = new StreamReader(responseStream))
 {
 response = reader.ReadToEnd();
 }
 }

 ParseResponse(response);
 }

private static void ParseResponse(string response)
 {
 var load = XDocument.Parse(response);
 var transType = Convert.ToInt32(load.Descendants().First(p => p.Name.LocalName == "transType").Value);
 var status = load.Descendants().First(p => p.Name.LocalName == "status").Value;
 var accountNum = load.Descendants().First(p => p.Name.LocalName == "accountNum").Value;
 var transNum = load.Descendants().First(p => p.Name.LocalName == "transNum").Value;
 }
 }

public class XmlProcessTransaction : XmlTransaction
 {
 [XmlElement("accountNum")]
 public string accountNum = string.Empty;
 [XmlElement("amount")]
 public string amount = string.Empty;
 }

public static class XmlSerializer<T>
 {
 public static XmlSerializer Serializer = new XmlSerializer(typeof(T));
 public static string WriteToString(T data)
 {
 return WriteToString(data, Encoding.UTF8);
 }
 public static string WriteToString(T data, Encoding encoding)
 {
 string retVal;
 using (MemoryStream memoryStream = new MemoryStream())
 {
 using (XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, encoding))
 {
 Serializer.Serialize(xmlTextWriter, data);
 }

retVal = encoding.GetString(memoryStream.ToArray());
 }

return retVal;
 }
 }

[XmlInclude(typeof(XmlProcessTransaction))]
 public class XmlTransaction
 {
 [XmlElement("transType")]
 public string TransType = string.Empty;
 }
 [XmlRoot("XMLRequest")]
 public class XmlTransactionRequest
 {
 [XmlElement("certStr")]
 public string CertificationString = string.Empty;
 [XmlElement("termid")]
 public string TerminalID = string.Empty;
 [XmlElement("XMLTrans")]
 public List<XmlTransaction> Transactions = new List<XmlTransaction>();
 }
 }

Response Handling

Request Submission

/**
 * ProPay provides the following code “AS IS.” ProPay makes no warranties and
 * ProPay disclaims all warranties and conditions, express, implied or
 * statutory, including without limitation the implied warranties of title,
 * non-infringement, merchantability, and fitness for a particular purpose.
 * ProPay does not warrant that the code will be uninterrupted or error free,
 * nor does ProPay make any warranty as to the performance or any results that
 * may be obtained by use of the code.
 */


<?php
class ProPayApi
{
/* change this to the production url for going live after testing https://api.propay.com */
private $_apiBaseUrl = 'https://xmltestapi.propay.com';

/* for xml */
/** @var \SimpleXMLElement */
private $_xmlRequestObject;
/** @var \SimpleXMLElement */
private $_xmlResponseObject;
/** @var string */
private $_xmlUrl;

/**
* sets the xml request object
* @param string $xmlData - containing XML
* @return $this
*/
public function setXMLRequestData($xmlData) {
$this->_xmlRequestObject = simplexml_load_string($xmlData);
return $this;
}

/**
* @param string $xmlData - containing XML
* @return $this
*/
public function setXMLResponseData($xmlData) {
$this->_xmlResponseObject = simplexml_load_string($xmlData);
return $this;
}

/**
* @return mixed
*/
public function getXMLRequestObject() {
return $this->_xmlRequestObject;
}

/**
* @return mixed
*/
public function getXMLResponseObject() {
return $this->_xmlResponseObject;
}

/**
* @param \SimpleXMLElement $xmlObject
* @return $this
*/
public function setXMLRequestObject(\SimpleXMLElement $xmlObject) {
$this->_xmlRequestObject = $xmlObject;
return $this;
}

/**
* @param \SimpleXMLElement $xmlObject
* @return $this
*/
public function setXMLResponseObject(\SimpleXMLElement $xmlObject) {
$this->_xmlResponseObject = $xmlObject;
return $this;
}

/**
* sets the url for the XML request
* @param string $xmlUrl
* @return $this
*/
public function setXMLUrl($xmlUrl) {
$this->_xmlUrl = $xmlUrl;
return $this;
}

/**
* posts XML to the server
* @return $this
*/
public function postXML() {
$header = [
"Content-type:text/xml; charset=\"utf-8\"",
"Accept: text/xml"
];


$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => $this->_xmlUrl,
CURLOPT_TIMEOUT => 30,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $this->_xmlRequestObject->asXML(),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => $header,
CURLOPT_SSL_VERIFYPEER => 0,
CURLOPT_SSL_VERIFYHOST => 0,
CURLOPT_HTTPAUTH => CURLAUTH_ANY
]);
$result = curl_exec($curl);
$this->_xmlResponseObject = simplexml_load_string($result);
curl_close($curl);
return $this;
}
}

$proPayAPI = new ProPayApi();
$data = "<?xml version='1.0'?>
<!DOCTYPE Request.dtd>
<XMLRequest>
</XMLRequest>";
$simpleXML = new \SimpleXMLElement($data);
$simpleXML->addChild('certStr','cert string here');
$simpleXML->addChild('termId','terminal id here');
$simpleXML->addChild('class','partner');
$simpleXML->addChild('XMLTrans');
$simpleXML->XMLTrans->addChild('transType', 38);
$simpleXML->XMLTrans->addChild('amount', 100);
$simpleXML->XMLTrans->addChild('accountNum', 123456789);

// returns XML
$result =
$proPayAPI->setXMLUrl('https://xmltest.propay.com/API/PropayAPI.aspx')
->setXMLRequestData($simpleXML->asXML())
->postXML()
->getXMLResponseObject()->asXML();

// if you prefer a simpleXML object you just retrieve the object back to work with that
$result = $proPayAPI->getXMLResponseObject();

Response Handling

Request Submission

Response Handling

Request Submission

Response Handling

Request Values

Element

Type

Max

Required

Notes

accountNum

Int(32)

 

Required

Assigned to each account by ProPay.

amount

Int(64)

 

Required

The value representing the number of pennies in USD, or the number of [currency] without decimals.

Response Values

Element

Type

Notes

transType

string

Will always return as 38.

status

string

Result of the transaction request. See ProPay Appendix for result code definitions.

accountNum

Int(32)

Echo of the account the API request was made for.

transNum

Int(32)

The ProPay account transaction identifier.

How to call this method?

Example Request

Example Response

Implementation Details
Request Submission

Response Handling

Request Submission

Response Handling

Request Submission

Response Handling

Request Submission

Response Handling

Request Values
Response Values