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