Statuscode error 406 & Invalid signature with POST transactions send

Hello, hope someone can shed some light on this problem I have with trying to send BTC to an address. I get authentication error/invalid signature. I use PHP. I searched and tried lots of things including what I found here to no avail. It seems no matter what I try I keep on getting invalid signature. I also recreated a new API key and secret to be sure and I got all the options (rights) enabled. I am able to get the exchange rates by the way.

	$apiKey = 'anapikey';
	$apiSecret = 'anapisecret';

	$apiVersion = '2023-07-21';

	

	// Recipient's Bitcoin address and memo
	$recipientAddress = 'awalletaddress'; 

	$amount = 0.0001; //my account should have this amount in bitcoins

	// Coinbase API endpoint
	$baseUrl = 'https://api.coinbase.com/v2/';
	$endpoint = 'accounts/myaccountid/transactions';

	// Generate a unique nonce for the request
	$nonce = json_decode(file_get_contents('https://api.coinbase.com/v2/time'), true)['data']['epoch'];//time(); 
//https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-transactions#send-money


	$postfields = json_encode([
	'type' => 'send',
	'to' => $recipientAddress,
	'amount' => $amount,
	'currency' => 'BTC',
	//'description' => $memo,
	'idem' => 'unique tekst'
	
	]);
	

	// Create the message to sign
	$message = $nonce . 'POST/' . $endpoint . $postfields;

	// Sign the message using the API secret
	//$signature = base64_decode(hash_hmac('sha256', $message, $apiSecret,true));
	//$signature = hash_hmac('sha256', $message, $apiSecret,false);

	$secret = base64_decode($apiSecret); // decode the secret from base64
	$key = hash('sha256', $secret, true); // create a sha256 hmac with the secret
	$hmac = hash_hmac('sha256', $message, $key, true); // sign the required message with the hmac

	$cb_access_sign = base64_encode($hmac); // base64 encode the result

	// Base64 encode the signature
	//$signatureEncoded = base64_encode($signature);

	// Set up the request headers
	$headers = [
	"Accept: application/json",
    "Content-Type: application/json",
	"CB-ACCESS-KEY: " . $apiKey,
	"CB-ACCESS-SIGN: " . $cb_access_sign,
	"CB-ACCESS-TIMESTAMP: " . $nonce,
	"CB-VERSION: " . $apiVersion,
	//"CURLOPT_CUSTOMREQUEST: POST",
	];
	
	// Prepare the request payload
	$data = [
	'type' => 'send',
	'to' => $recipientAddress,
	'amount' => $amount,
	'currency' => 'BTC'
	];

	// Send the request to Coinbase API
	
	$ch =  curl_init($baseUrl . $endpoint);
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
	curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
	//curl_setopt($ch, CURLOPT_ENCODING, "");
	//curl_setopt($ch, CURLOPT_MAXREDIRS, "");
	//curl_setopt($ch, CURLOPT_TIMEOUT, 30);
	//curl_setopt($ch, CURLOPT_USERAGENT, "API Explorer");
	//curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
//	curl_setopt($ch, CURLOPT_POST, true);
	//curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($postfields));
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); // important
	curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);  // important
	curl_setopt($ch, CURLOPT_CUSTOMREQUEST,'POST');
	$response = curl_exec($ch);
	
	// Check for errors
	if (curl_errno($ch)) {
		echo 'Error: ' . curl_error($ch);
	} else {
		$statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
		if ($statusCode === 201) {
			echo 'Payment sent successfully!';
		} else {
			echo 'Payment failed ' . $response . ' with status code: ' . $statusCode;
		}
	}

	// Close the request
	curl_close($ch);

Secret is not base64 encoded and you should not encode signature either.

Also signature should be in hex, so binary parameter for hash_hmac should be false.

1 Like

Though I get another error 400 invalid header value, you are correct! Maybe I was closer in an earlier stage and after that I followed the documentation that made me come up with the previous code Exchange REST API Authentication | Coinbase Cloud

With the header error maybe I have seen someone recommended to add a useragent but then I get the authentication error back. You know this too? But anyway I am most greatful for your help. Cheers.

Post updated code, if you still have problems.

Above code has commented out section that should set body/postfields and if it would be uncommented then you are json_encode-ing $postfields again.

It got better, only now I get statuscode 406. I put my code below. [EDIT] At the moment I can’t find what this error code is supposed to mean.

$apiVersion = '2023-07-21';

	

	// Recipient's Bitcoin address and memo
	$recipientAddress = 'address'; //bitvavo

	$file = $app_id . '_paypalpayout_' . strtolower($langcode) . '.txt';
	$myfolder = '../payout/';
	$file = $myfolder .$file;

	if (!file_exists($file)) {
	
		$file = $myfolder . $app_id . '_paypalpayout_en.txt';

	}
	

	// Amount to send in BTC
	$amount = 0.0001;

	// Coinbase API endpoint
	$baseUrl = 'https://api.coinbase.com/v2/';
	$endpoint = 'accounts/myaccountid/transactions';

	// Generate a unique nonce for the request
	$nonce = json_decode(file_get_contents('https://api.coinbase.com/v2/time'), true)['data']['epoch'];
//https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-transactions#send-money


	$postfields = json_encode([
	'type' => 'send',
	'to' => $recipientAddress,
	'amount' => $amount,
	'currency' => 'BTC',
	//'description' => $memo,
	'idem' => $batchid
	
	]);
	

	// Create the message to sign
	$message = $nonce . 'POST/' . $endpoint . $postfields;

	// Sign the message using the API secret
	
	$secret = $apiSecret; //base64_decode($apiSecret); // decode the secret from base64
	$key = hash('sha256', $secret, true); // create a sha256 hmac with the secret
	$hmac = hash_hmac('sha256', $message, $key, false); // sign the required message with the hmac


	// Set up the request headers
	$headers = [
	"Content-Type: 'application/json'",
	"CB-ACCESS-KEY: " . $apiKey . "",
	"CB-ACCESS-SIGN: " . $hmac. "",
	"CB-ACCESS-TIMESTAMP: " . $nonce . "",
	//"CB-VERSION: '" . $apiVersion . "'",
	//"Accept: 'application/json'",
    
	//"User-Agent: 'UnityApp/1.1'",
	
	];

	// Prepare the request payload
	$data = [
	'type' => 'send',
	'to' => $recipientAddress,
	'amount' => $amount,
	'currency' => 'BTC'
	];

	// Send the request to Coinbase API
	
	$ch =  curl_init($baseUrl . $endpoint);
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
	curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
	//curl_setopt($ch, CURLOPT_ENCODING, "");
	//curl_setopt($ch, CURLOPT_MAXREDIRS, "");
	//curl_setopt($ch, CURLOPT_TIMEOUT, 30);
	//curl_setopt($ch, CURLOPT_USERAGENT, "API Explorer");
	//curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
	curl_setopt($ch, CURLOPT_POST, true);
	curl_setopt($ch, CURLOPT_POSTFIELDS, $postfields);
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); // important
	curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);  // important
	//curl_setopt($ch, CURLOPT_CUSTOMREQUEST,'POST');
	$response = curl_exec($ch);
	
	// Check for errors
	if (curl_errno($ch)) {
		echo 'Error: ' . curl_error($ch);
	} else {
		$statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
		if ($statusCode === 201) {
			echo 'Payment sent successfully!';
		} else {
			echo 'Payment failed ' . $response . ' with status code: ' . $statusCode;
		}
	}

	// Close the request
	curl_close($ch);
1 Like