Create a file (name it e.g. pap.php) in the /includes/hooks/ directory of your installation of WHMCS and use the following code there. 
 
NOTE: Do not forget to follow the instructions in the code below   (see them after the double slash // ) in the first few lines.
 
<?php
include_once '/PATH_TO_PAP/api/PapApi.class.php'; // Change to correct path 
add_hook("AfterShoppingCartCheckout",20,"pap_Track","");
add_hook("InvoicePaid",0,"pap_InvoicePaid","");
add_hook("InvoiceUnpaid",0,"pap_InvoiceDenied","");
add_hook("InvoiceCancelled",0,"pap_InvoiceDenied","");
add_hook("InvoiceRefunded",0,"pap_InvoiceRefunded","");


class WHMCSPap {
	protected $pap_url = 'http://example.com/affiliate/'; // Change to correct URL leading to PAP
	protected $pap_user = 'merchant@example.com'; // Change to correct merchant username
	protected $pap_password = 'merchant'; // Change to correct merchant password
	protected $logfile = '/tmp/pap.log'; // Path to log file
	protected $debug = false;

	protected function pap_log($message) {
		$log = fopen($this->logfile,'a');
		fwrite($log, date('Y-m-d H:i:s').' : '.$message."\n");
		fclose($log);
	}

public function track($vars) {
    if ($this->debug) $this->pap_log('Tracking order');
    
    $invoiceid = $vars['InvoiceID'];
    $total_query = mysql_query("SELECT userid,type,description,amount,taxed FROM tblinvoiceitems WHERE invoiceid='$invoiceid'");

    if($this->debug) $this->pap_log("Creating sale for $invoiceid at URL: " . $this->pap_url);

    $i = 1;
    while ($row = mysql_fetch_assoc($total_query)) {
  		$saleTracker = new Pap_Api_SaleTracker($this->pap_url.'scripts/sale.php');
  		$sale = $saleTracker->createSale();
  		$sale->setTotalCost($row['amount'] - $row['taxed']);
  		$sale->setOrderID($invoiceid.'_'.$i);
  		$sale->setProductId($row['type']);
  		$sale->setData1($row['userid']);
  		$sale->setData2($row['description']);
  		$sale->setStatus('P');
  		$saleTracker->register();
  		
  		$i++;
		  if ($this->debug) $this->pap_log('Order '.$invoiceid.'_'.$i.' tracked');
    }
		
		return;
	}

	public function refund($vars) {
		$orderid = $vars['InvoiceID'];
		$session = new Pap_Api_Session($this->pap_url . 'scripts/server.php');
		if(!$session->login($this->pap_user, $this->pap_password)) {
			if($this->debug) $this->pap_log('Cannot login. Message: '.$session->getMessage());
			return;
		}
		
		$request = new Pap_Api_TransactionsGrid($session);
		$request->addFilter('orderid', Gpf_Data_Filter::LIKE, '%'.$orderid.'_%'); // find all transactions (123_1, 123_2, ...)
		$request->setSorting('orderid', false);
		$request->sendNow();
		$grid = $request->getGrid();
		
		if ($grid->getTotalCount() > 0) {
  		$recordset = $grid->getRecordset();
  		foreach($recordset as $rec){
  			$sale = new Pap_Api_Transaction($session);
  			$sale->setTransid($rec->get('transid'));
    		try {
  			  if(!$sale->load()) {
  				  if($this->debug) $this->pap_log('Cannot load transaction for'.$rec->get('transid').' error: '.$sale->getMessage());
  			    continue;
    		  }
          else {
  			  	$sale->refund();
  			  	if($this->debug) $this->pap_log('Transaction '.$rec->get('transid').' refunded');
  			  }
  			}
        catch(Exception $e){
  				if($this->debug) $this->pap_log('Exception: '.$e->getMessage());
  				return;
  			}
  		}
		}
	}

	public function changePAP4status($invoiceid,$approved) {
    if (empty($invoiceid)) {
      if ($this->debug) $this->pap_log("Invoice empty! Ending.");
      return;
    }
		if ($this->debug) $this->pap_log("Changing PAP4 status of invoice $invoiceid to status: $approved");
		
		$pap_query = mysql_query("SELECT id FROM tblorders WHERE invoiceid='$invoiceid'");
		$pap_query = mysql_fetch_array($pap_query);
		$orderid = $pap_query['id'];
		if (empty($orderid)) {
      if($this->debug) $this->pap_log("This seems to be a recurring order...");
			$this->recurringCommission($invoiceid);
			return;
		}
		
		if ($this->debug) $this->pap_log("Found orderid $orderid for invoice $invoiceid");
		
		$session = new Pap_Api_Session($this->pap_url . 'scripts/server.php');
		if(!$session->login($this->pap_user, $this->pap_password)) {
		  if($this->debug) $this->pap_log('Cannot login. Message: '.$session->getMessage());
		  return;
		}
		
		//Get all orders with same order id
		$request = new Pap_Api_TransactionsGrid($session);
  	$request->addFilter('orderid', Gpf_Data_Filter::LIKE, '%'.$orderid.'_%');
  	$request->sendNow();
    $grid = $request->getGrid();
		$recordset = $grid->getRecordset();
	    
    foreach ($recordset as $rec) {
			$sale = new Pap_Api_Transaction($session);
			$sale->setTransid($rec->get('transid'));
  		try {
			  if(!$sale->load()) {
				  if($this->debug) $this->pap_log('Cannot load transaction ' . $rec->get('transid') . ', error: '. $sale->getMessage());
			    continue;
  		  }
        else {
  				if($this->debug) $this->pap_log('PAP4 transaction ' . $sale->getTransid() . ' loaded');
  				$status = $sale->getStatus();
  				if ($approved) {
  					if ($status == 'P') {
  						$sale->setStatus('A');
  						$sale->save();
  						if($this->debug) $this->pap_log('Transaction approved.');
    				}
            else {
  						if($this->debug) $this->pap_log("Status was $status, so it's left unchanged.");
  					}
  				}
          else {
  					if ($status != 'D') {
  						$sale->setStatus('D');
  						$sale->save();
  						if($this->debug) $this->pap_log('Transaction declined.');
  					}
            else {
  						if($this->debug) $this->pap_log("Status was $status, so it's left unchanged.");
  					}
  				}
			  }
			}
      catch (Exception $e) {
			  if($this->debug) $this->pap_log('Exception: '.$e->getMessage());
		    continue;
			}
  	}
	}
	
	public function recurringCommission($invoiceid) {
    if($this->debug) {
      $this->pap_log("Starting tracking a recurring order $invoiceid...");
    }

    $pap_query = mysql_query("SELECT userid,type,description,amount,taxed FROM tblinvoiceitems WHERE invoiceid='$invoiceid'");

    $i = 1;
    while ($row = mysql_fetch_assoc($pap_query)) {
      if ($row['type'] == 'Invoice') { // mass payment, no new commission, we have to approve existing one
        $oldInvoiceId = substr($row['description'],strpos($row['description'],'#')+1); // e.g. Invoice #1234
        $this->changePAP4status($oldInvoiceId,1);
        continue;
      }

  		$saleTracker = new Pap_Api_SaleTracker($this->pap_url."scripts/sale.php");
  		$sale = $saleTracker->createSale();
  		$sale->setTotalCost($row['amount'] - $row['taxed']);
  		$sale->setOrderID($invoiceid.'_'.$i);
  		$sale->setProductId($row['type']);
  		$sale->setData1($row['userid']);
  		$sale->setData2($row['description']);
  		$sale->setStatus('A');
  		$saleTracker->register();
  		$i++;
		  if($this->debug) $this->pap_log("Order $invoiceid tracked");
    }
		return;
  }
}

function pap_InvoiceDenied($vars) {
	// marking the transaction as approved on PAP4
	$pap = new WHMCSPap();
	$pap->changePAP4status($vars['InvoiceID'],0);
}

function pap_InvoicePaid($vars) {
	// marking the transaction as disapproved on PAP4
	$pap = new WHMCSPap();
	$pap->changePAP4status($vars['InvoiceID'],1);
}

function pap_InvoiceRefunded($vars) {
	// marking the transaction as approved on PAP4
	$pap = new WHMCSPap();
	$pap->refund($vars);
}

function pap_Track($vars) {
	// marking the transaction as approved on PAP4
	$pap = new WHMCSPap();
	$pap->track($vars);
}
?>