Last active
April 17, 2024 17:41
-
-
Save sandervdo/ae253bc88789f4beb68a6ef08f8d1534 to your computer and use it in GitHub Desktop.
Example php script that let's you connect to the bunq API without the use of the SDKs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* This scripts gives a quick example on how to connect to the bunq API without the SDKs. | |
* For documentation on the endpoints / API in general, please see https://doc.bunq.com | |
* | |
* Please use the official channels for support; | |
* - bunq Together (community forum): https://together.bunq.com | |
* - In-app support: https://bunq.com/link/support | |
* - Email support: support@bunq.com | |
* - API support: apisupport@bunq.com | |
* | |
* @author Sander van den Oever <sandervdo@gmail.com> | |
* @date 2018-09-11 | |
* @license https://opensource.org/licenses/GPL-3.0 | |
*/ | |
/** | |
* Constants. | |
*/ | |
const URL_API = 'https://public-api.sandbox.bunq.com'; | |
/** | |
* @return resource[] | |
*/ | |
function generateKeys(): array | |
{ | |
$opensslKeyPair = openssl_pkey_new( | |
[ | |
'digest_alg' => 'sha512', | |
'private_key_bits' => 2048, | |
'private_key_type' => OPENSSL_KEYTYPE_RSA, | |
] | |
); | |
if ($opensslKeyPair === false) { | |
die('Error in generating keypair.'); | |
} | |
return [ | |
'private' => openssl_pkey_get_private($opensslKeyPair), | |
'public' => openssl_pkey_get_details($opensslKeyPair)['key'], | |
]; | |
} | |
/** | |
* @param resource $publicKey | |
* | |
* @return string[] | |
*/ | |
function callInstallation($publicKey): array | |
{ | |
$resource = '/v1/installation'; | |
$requestId = uniqid(); | |
$body = [ | |
'client_public_key' => $publicKey, | |
]; | |
// Initialize. | |
$curl = curl_init(); | |
// Set request parameters. | |
curl_setopt($curl, CURLOPT_URL, URL_API . $resource); | |
curl_setopt($curl, CURLOPT_VERBOSE, 1); | |
curl_setopt($curl, CURLOPT_HEADER, 1); | |
curl_setopt( | |
$curl, | |
CURLOPT_HTTPHEADER, | |
[ | |
"Cache-Control: no-cache", | |
"User-Agent: test", | |
"X-Bunq-Geolocation: 0 0 0 0 NL", | |
"X-Bunq-Language: en_US", | |
"X-Bunq-Region: en_US", | |
"X-Bunq-Client-Request-Id: " . $requestId, | |
] | |
); | |
curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($body)); | |
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); | |
// Execute. And save response. | |
$response = curl_exec($curl); | |
$sizeHeader = curl_getinfo($curl, CURLINFO_HEADER_SIZE); | |
// Close connection. | |
curl_close($curl); | |
$bodyRaw = substr($response, $sizeHeader); | |
echo $bodyRaw . PHP_EOL . PHP_EOL; | |
$bodyJson = json_decode($bodyRaw, true); | |
return [ | |
'header' => substr($response, 0, $sizeHeader), | |
'body' => [ | |
'id' => $bodyJson['Response'][0]['Id']['id'], | |
'token' => $bodyJson['Response'][1]['Token'], | |
'server-public-key' => $bodyJson['Response'][2]['ServerPublicKey']['server_public_key'], | |
], | |
]; | |
} | |
/** | |
* @param resource $privateKey | |
* @param string $tokenInstallation | |
* @param string $apiKey | |
* | |
* @return string[] | |
*/ | |
function callDeviceServer($privateKey, string $tokenInstallation, string $apiKey): array | |
{ | |
$method = 'POST'; | |
$resource = '/v1/device-server'; | |
$requestId = uniqid(); | |
$body = json_encode( | |
[ | |
'description' => 'Simple test script', | |
'secret' => $apiKey, | |
'permitted_ips' => [], | |
] | |
); | |
$signature = getSignatureString($privateKey, $method, $resource, $requestId, $tokenInstallation, $body); | |
// Initialize. | |
$curl = curl_init(); | |
// Set request parameters. | |
curl_setopt($curl, CURLOPT_URL, URL_API . $resource); | |
curl_setopt($curl, CURLOPT_VERBOSE, 1); | |
curl_setopt($curl, CURLOPT_HEADER, 1); | |
curl_setopt( | |
$curl, | |
CURLOPT_HTTPHEADER, | |
[ | |
"Cache-Control: no-cache", | |
"User-Agent: test", | |
"X-Bunq-Client-Authentication: " . $tokenInstallation, | |
"X-Bunq-Client-Request-Id: " . $requestId, | |
"X-Bunq-Client-Signature: " . $signature, | |
"X-Bunq-Geolocation: 0 0 0 0 NL", | |
"X-Bunq-Language: en_US", | |
"X-Bunq-Region: en_US", | |
] | |
); | |
curl_setopt($curl, CURLOPT_POSTFIELDS, $body); | |
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); | |
// Execute. And save response. | |
$response = curl_exec($curl); | |
$sizeHeader = curl_getinfo($curl, CURLINFO_HEADER_SIZE); | |
// Close connection. | |
curl_close($curl); | |
$bodyRaw = substr($response, $sizeHeader); | |
echo $bodyRaw . PHP_EOL . PHP_EOL; | |
$bodyJson = json_decode($bodyRaw, true); | |
return [ | |
'header' => substr($response, 0, $sizeHeader), | |
'body' => [ | |
'id' => $bodyJson['Response']['Id']['id'], | |
], | |
]; | |
} | |
/** | |
* @param resource $privateKey | |
* @param string $tokenInstallation | |
* @param string $apiKey | |
* | |
* @return string[] | |
*/ | |
function callSessionServer($privateKey, string $tokenInstallation, string $apiKey): array | |
{ | |
$method = 'POST'; | |
$resource = '/v1/session-server'; | |
$requestId = uniqid(); | |
$body = json_encode( | |
[ | |
'secret' => $apiKey, | |
] | |
); | |
$signature = getSignatureString($privateKey, $method, $resource, $requestId, $tokenInstallation, $body); | |
// Initialize. | |
$curl = curl_init(); | |
// Set request parameters. | |
curl_setopt($curl, CURLOPT_URL, URL_API . $resource); | |
curl_setopt($curl, CURLOPT_VERBOSE, 1); | |
curl_setopt($curl, CURLOPT_HEADER, 1); | |
curl_setopt( | |
$curl, | |
CURLOPT_HTTPHEADER, | |
[ | |
"Cache-Control: no-cache", | |
"User-Agent: test", | |
"X-Bunq-Client-Authentication: " . $tokenInstallation, | |
"X-Bunq-Client-Request-Id: " . $requestId, | |
"X-Bunq-Client-Signature: " . $signature, | |
"X-Bunq-Geolocation: 0 0 0 0 NL", | |
"X-Bunq-Language: en_US", | |
"X-Bunq-Region: en_US", | |
] | |
); | |
curl_setopt($curl, CURLOPT_POSTFIELDS, $body); | |
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); | |
// Execute. And save response. | |
$response = curl_exec($curl); | |
$sizeHeader = curl_getinfo($curl, CURLINFO_HEADER_SIZE); | |
// Close connection. | |
curl_close($curl); | |
$bodyRaw = substr($response, $sizeHeader); | |
echo $bodyRaw . PHP_EOL . PHP_EOL; | |
$bodyJson = json_decode($bodyRaw, true); | |
return [ | |
'header' => substr($response, 0, $sizeHeader), | |
'body' => [ | |
'id' => $bodyJson['Response'][0]['Id']['id'], | |
'token' => $bodyJson['Response'][1]['Token']['token'], | |
'user-company' => isset($bodyJson['Response'][2]['UserCompany']) ? $bodyJson['Response'][2]['UserCompany'] : null, | |
'user-person' => isset($bodyJson['Response'][2]['UserPerson']) ? $bodyJson['Response'][2]['UserPerson'] : null, | |
'user-api-key' => isset($bodyJson['Response'][2]['UserApiKey']) ? $bodyJson['Response'][2]['UserApiKey'] : null, | |
], | |
]; | |
} | |
/** | |
* @param resource $privateKey | |
* @param int $userId | |
* @param string $tokenSession | |
* | |
* @return string[] | |
*/ | |
function callMonetaryAccountListing($privateKey, int $userId, string $tokenSession): array | |
{ | |
$method = 'GET'; | |
$resource = '/v1/user/' . $userId . '/monetary-account'; | |
$requestId = uniqid(); | |
$body = json_encode([]); | |
$signature = getSignatureString($privateKey, $method, $resource, $requestId, $tokenSession, $body); | |
// Initialize. | |
$curl = curl_init(); | |
// Set request parameters. | |
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method); | |
curl_setopt($curl, CURLOPT_URL, URL_API . $resource); | |
curl_setopt($curl, CURLOPT_VERBOSE, 1); | |
curl_setopt($curl, CURLOPT_HEADER, 1); | |
curl_setopt( | |
$curl, | |
CURLOPT_HTTPHEADER, | |
[ | |
"Cache-Control: no-cache", | |
"User-Agent: test", | |
"X-Bunq-Client-Authentication: " . $tokenSession, | |
"X-Bunq-Client-Request-Id: " . $requestId, | |
"X-Bunq-Client-Signature: " . $signature, | |
"X-Bunq-Geolocation: 0 0 0 0 NL", | |
"X-Bunq-Language: en_US", | |
"X-Bunq-Region: en_US", | |
] | |
); | |
curl_setopt($curl, CURLOPT_POSTFIELDS, $body); | |
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); | |
// Execute. And save response. | |
$response = curl_exec($curl); | |
$sizeHeader = curl_getinfo($curl, CURLINFO_HEADER_SIZE); | |
// Close connection. | |
curl_close($curl); | |
$bodyRaw = substr($response, $sizeHeader); | |
echo $bodyRaw . PHP_EOL . PHP_EOL; | |
$bodyJson = json_decode($bodyRaw, true); | |
return [ | |
'header' => substr($response, 0, $sizeHeader), | |
'body' => $bodyJson, | |
]; | |
} | |
/** | |
* @param resource $privateKey | |
* @param string $method | |
* @param string $resource | |
* @param string $requestId | |
* @param string $authentication | |
* @param string $bodyJson | |
* | |
* @return string | |
*/ | |
function getSignatureString( | |
$privateKey, | |
string $method, | |
string $resource, | |
string $requestId, | |
string $authentication, | |
string $bodyJson | |
): string { | |
$stringToSign = <<<SIGNING_TEMPLATE | |
$method $resource | |
Cache-Control: no-cache | |
User-Agent: test | |
X-Bunq-Client-Authentication: $authentication | |
X-Bunq-Client-Request-Id: $requestId | |
X-Bunq-Geolocation: 0 0 0 0 NL | |
X-Bunq-Language: en_US | |
X-Bunq-Region: en_US | |
$bodyJson | |
SIGNING_TEMPLATE; | |
openssl_sign($stringToSign, $signature, $privateKey, OPENSSL_ALGO_SHA256); | |
return base64_encode($signature); | |
} | |
/*********************************************************************************************** | |
* API KEY BELOW * | |
***********************************************************************************************/ | |
$apiKey = '---INSERT YOUR API KEY HERE---'; | |
/*********************************************************************************************** | |
* API KEY ABOVE * | |
***********************************************************************************************/ | |
// STEP 1: Key-exchange. | |
$keypair = generateKeys(); | |
$responseInstallation = callInstallation($keypair['public']); | |
// Info necessary for next call. | |
$bunqPublicKey = $responseInstallation['body']['server-public-key']; | |
$tokenInstallation = $responseInstallation['body']['token']['token']; | |
// STEP 2: Create Device Server. | |
$responseDeviceServer = callDeviceServer($keypair['private'], $tokenInstallation, $apiKey); | |
// STEP 3: Create Session Server. | |
$responseSessionServer = callSessionServer($keypair['private'], $tokenInstallation, $apiKey); | |
$tokenSession = $responseSessionServer['body']['token']; | |
if (isset($responseSessionServer['body']['user-company'])) { | |
// Business accounts. | |
$userId = $responseSessionServer['body']['user-company']['id']; | |
} elseif (isset($responseSessionServer['body']['user-person'])) { | |
// Personal accounts. | |
$userId = $responseSessionServer['body']['user-person']['id']; | |
} elseif (isset($responseSessionServer['body']['user-api-key'])) { | |
// This user type is used for OAuth connections. | |
$userId = $responseSessionServer['body']['user-api-key']['id']; | |
} else { | |
die(vsprintf('Unexpected User type for session: "%s"', [$responseSessionServer['body']['id']])); | |
} | |
// Run your API calls, e.g. retrieve all monetary accounts. | |
$responseMonetaryAccountListing = callMonetaryAccountListing($keypair['private'], $userId, $tokenSession); | |
var_dump($responseMonetaryAccountListing); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment