I think you can register for demo access to Currency Cloud without being a client, but to activate webhooks on this you'd need to contact a "Solutions Consultant".
From /developers/cookbooks/authenticating/ every request to the Currency Could API needs to be accompanied by an X-Auth-Token: header, this expires after 30 minutes of inactivity. I've taken the view to simply request a new one with every instantiation of the Class (done on the Constructor) and add it to an array of headers maintained in the Class.
From /developers/cookbooks/push-notifications/ you can set up integrations that correspond with 'notifications' from Currencycloud. If you choose to do this there are 3 layers of security that should be implemented:
<?php require_once(AUTH_FILE); require_once(CLASS_FILE); $CurrencyCloud = new CurrencyCloud(); echo $CurrencyCloud->generateHMAC(); ?> # php x.php 4233d40827244a688adcd1d404e7e1e5cc95b1e61fc6c09a
This is an example of a webhook script for (say) https://domain.example/web-hook/
<?php require_once(AUTH_FILE); $valid = 0; if (in_array($_SERVER['REMOTE_ADDR'], CCAllowedIPs) === true) { if ($_SERVER['REQUEST_METHOD'] == 'POST') { $rxBody = file_get_contents("php://input"); $rxHeaderArr = getallheaders(); if (array_key_exists('X-Hmac-Digest-Sha-512', $rxHeaderArr)) { if ($rxHeaderArr['X-Hmac-Digest-Sha-512'] == hash_hmac('sha512', $rxBody, CCHMACKey)) { $valid = 1; // do something with $rxBody echo 'OK'; exit(0); } } } } header("HTTP/1.0 400 Bad Request"); exit(1); ?>
Seperating authentication data from the main Class allows (1) AUTH files to be located where permissions/access is suitably restricted, (2) the Class file to be under version control, without the risk of credentials leaking and (3) only one line of a program needs to change shift a program from Demo to Live.
const CCReqHeaders = array('User-Agent: HelloWorld Agent', 'Accept: application/json'); const CCBaseURL = 'https://directdemo.currencycloud.com'; const CCAllowedIPs = array('52.214.236.241','52.214.33.127','52.215.88.1','52.56.108.189','52.56.108.195','35.157.104.248','35.157.113.98','35.157.98.135','108.128.119.77','52.215.246.166','63.33.40.150','52.214.236.241','52.214.33.127','35.177.158.89', '35.178.90.97', '92.207.224.178', '2.217.100.92'); const CCHMACKey = "your HAMC key'; const CCAuthArr = array( 'login_id' => 'your email address', 'api_key' => 'your API key' );
class CurrencyCloud { private $responseHeaders = array(); private $reqHeaders = CCReqHeaders; private $respHeaders = array(); public function __construct() { $resp = $this->callAPI('/v2/authenticate/api', CCAuthArr, 'POST'); if (is_null($resp)) { throw new Exception("Currency Cloud: Response is not valid JSON"); } if (!array_key_exists('auth_token', $resp)) { throw new Exception("Currency Cloud: auth_token not found in response"); } $this->reqHeaders[] = 'X-Auth-Token: '. $resp['auth_token']; } public function generateHMAC() { $resp = $this->callAPI('/v2/contacts/generate_hmac_key', array(), 'POST'); return $resp["hmac_key"]; } public function getAllClients() { /* this will take time to run, ideally don't call it on the UI thread and be aware that more results per page would be coded better (I've gone for POC- simple) */ $Clients = array(); $page = 0; do { $page++; $resp = $this->callAPI('/v2/accounts/find?per_page=1&page=' . $page); if (array_key_exists('accounts', $resp)) { if (array_key_exists(0, $resp['accounts'])) { $Clients[] = $resp['accounts'][0]; } } if (array_key_exists('pagination', $resp)) { if (!array_key_exists('total_entries', $resp['pagination'])) { throw new Exception("Currency Cloud: getAllClients() unable to complete, total_entries missing"); } } else { throw new Exception("Currency Cloud: getAllClients() unable to complete, no pagination"); } } while ($page <= ($resp['pagination']['total_entries'])); return $Clients; } public function getClient($guid) { $resp = $this->callAPI('/v2/accounts/' . $guid); return $resp; } public function getBene($guid) { $resp = $this->callAPI('/v2/beneficiaries/' . $guid); return $resp; } private function callAPI($url, $arr = array(), $method='GET') { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, CCBaseURL . $url); if ($method == 'POST') { curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($arr)); } curl_setopt($ch, CURLOPT_HTTPHEADER, $this->reqHeaders); curl_setopt($ch, CURLINFO_HEADER_OUT, true); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_HEADERFUNCTION, array(&$this, 'header')); $body = curl_exec($ch); /* Outbound Debug $info = curl_getinfo($ch); var_dump($info); */ $resp = json_decode($body,true); curl_close ($ch); return $resp; } private function header($curl, $hl) { $tmp = explode(':', $hl, 2); if (count($tmp)==2) { $this->respHeaders[$tmp[0]] = trim($tmp[1]); } return strlen($hl); } }