Can I do transfer between portfolios with withdraw and deposit APIs? [coinbase-api] - coinbase-api

We cannot use the following APIs to do transfer between portfolios.
“POST /withdrawals/coinbase-account" (url:https://api-public.sandbox.pro.coinbase.com/withdrawals/coinbase-account)
“POST /deposits/coinbase-account” (url:https://api-public.sandbox.pro.coinbase.com/deposit/coinbase-account)
The error msg is as follows:
ApiError(status 403 code=): Invalid scope COINBASE args({'data': '{"amount": 0.1, "currency": "BTC", "coinbase_account_id": "4b08d5e5-fe77-4249-b017-301e8890652a"}', 'headers': {'Content-type': 'application/json', 'CB-ACCESS-KEY': 'XXXXXXXXXXXX', 'CB-ACCESS-SIGN': 'xxxxxxxxxxxxxxxxxxxxxxxxx, 'CB-ACCESS-TIMESTAMP': '1594280190.878908', 'CB-ACCESS-PASSPHRASE': 'xxxxxxxxxxx'}, 'timeout': 30.0})
Let us know if these 2 APIs are for transfer between portfolios or not. However, if the API is ok, could you please demonstrate on the url and request payload for the following 2 use cases:
If I want to do transfer from profile A to profile B, using A's API keys(with transfer access) and A.withdrawals(asset, amount, coinbase_id = B)
If I want to do transfer from profile B to profile A, using A's API keys(with transfer access) and A.deposits(asset, amount, coinbase_id = B)
Especially, Does the coinbase_id stands for profile(potfolio) id or account(asset) id? How to obtain this id by API?

It's already a long time thread, I imagine you already found your answer but if not and for those interested, you can use the /profiles/transfer route to transfer funds between your Coinbase Pro portfolios.
Just you must have an API key created from the "from" portfolio with the transfer permission.
Example:
POST /profiles/transfer
{
"from": "86602c68-306a-4500-ac73-4ce56a91d83c",
"to": "e87429d3-f0a7-4f28-8dff-8dd93d383de1",
"currency": "EUR",
"amount": "100.00"
}

You can obtain an account ID via obtaining an Oauth2 authorization first. Once that is obtained you can use a Coinbase API (NOT PRO) call to obtain an account ID. I will not cover the Oauth2 calls since they are decently documented. The API call using PHP CURL is as follows:
//////////////////////
// IMPORTANT, not covered how to obtain this
// Assuming a variable which contains the Oauth2 access code is passed in
// with a variable name called
// $oauth_provided_access_token
// IMPORTANT
//////////////////////
// Obtain Timestamp
$API_VERSION = '2021-02-26';
$timestamp = json_decode(file_get_contents("https://api.coinbase.com/v2/time"), true)["data"]["epoch"];
// Define request
$req = "/v2/user";
// Define full URL, why Coinbase cannot parse this and obtain the request is strange
$url = "https://api.coinbase.com" . $req;
// Obtain API key/Secret (Do not put this in your PHP code, obtain it via environment variables
// Note that the key and secret are not required in this instance
// but many Coinbase API calls will need them
//$key = $_SERVER["HTTP_MY_COINBASE_API_KEY"];
//$secret = $_SERVER["HTTP_MY_COINBASE_API_SECRET"];
// Set up CURL
$ch = curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, false );
curl_setopt($ch, CURLOPT_USERAGENT,'CoinbaseAPI');
curl_setopt($ch, CURLOPT_HTTPHEADER
, array ( "Authorization: Bearer " . $oauth_provided_access_token
, "CB-VERSION:" . $API_VERSION
, "CB-ACCESS-TIMESTAMP:" . $timestamp
)
);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true );
$response = curl_exec($ch); // Actual account info
$info = curl_getinfo($ch); // Get more debugging info
curl_close($ch);
$response_object=json_decode($response);
echo $response_object->{"data")->{"id"}; // User Account ID

Related

Getting error: Authentication with the CRM provider failed, while creating sfdc instance through cloudelements

I am trying to create an element instance in cloudelements. Have retrieved the code parameter from the url query string, have following codebase:
$ch = curl_init();
$code = $_REQUEST['code'];
$headers = array(
'Content-Type: application/json',
'Accept: application/json',
'Authorization: User xxxxxxxxyyyyyyyyyzzzzzzzzzzz=, Organization ccccccccccccccccccccccccc'
);
$url = 'https://api.cloud-elements.com/elements/api-v2/elements/23/instances';
$curl_post_data = array(
"providerData" => array(
"code" => $code
),
"name" => "salesforce_instance_".date("Y-m-d-H:i:s"),
"configuration" =>
array(
"base.url" => "https://login.salesforce.com",
"filter.response.nulls" => "true"
)
);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($curl_post_data));
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$curl_response = curl_exec($ch);
But, i am getting following error:
Authentication with the CRM provider failed. Please ensure valid authentication values were provided.
This might be an issue with the header part. Please check your 'Authorisation' field in the header. It is a formatted string. So the spaces and commas are countable. It is better to copy-paste from their UI itself.
You can get the authorisation header from their 'api try it out' page. To enter to that screen first login to cloud elements. Then press the 'API Docs' button. It will direct you to the page - https://my.cloudelements.io/api-docs/platform . Then select some option from left side. For example 'Elements'. Then there you can see a set of endpoints over the right side. Select one from there, say /elements/{keyOrId}/instances. Then press on the 'Try it out ' button. On the authorisation field , you can get the header value. Copy- paste it in your code.
Thank you

Batch fetching messages performance

I need to get the last 100 messages in the INBOX (headers only). For that I'm currently using the IMAP extension to search and then fetch the messages. This is done with two requests (SEARCH and then UID FETCH).
What's the Gmail API equivalent to fetching multiple messages in one request?
All I could find is a batch API, which seems way more cumbersome (composing a long list of messages:get requests wrapped in plain HTTP code).
It's pretty much the same in the Gmail API as in IMAP. Two requests: first is messages.list to get the message ids. Then a (batched) message.get to retrieve the ones you want. Depending on what language you're using the client libraries may help with the batch request construction.
A batch request is a single standard HTTP request containing multiple Google Cloud Storage JSON API calls, using the multipart/mixed content type. Within that main HTTP request, each of the parts contains a nested HTTP request.
From: https://developers.google.com/storage/docs/json_api/v1/how-tos/batch
It's really not that hard, took me about an hour to figure it out in python even without the python client libraries (just using httplib and mimelib).
Here's a partial code snippet of doing it, again with direct python. Hopefully it makes it clear that's there's not too much involved:
msg_ids = [msg['id'] for msg in body['messages']]
headers['Content-Type'] = 'multipart/mixed; boundary=%s' % self.BOUNDARY
post_body = []
for msg_id in msg_ids:
post_body.append(
"--%s\n"
"Content-Type: application/http\n\n"
"GET /gmail/v1/users/me/messages/%s?format=raw\n"
% (self.BOUNDARY, msg_id))
post_body.append("--%s--\n" % self.BOUNDARY)
post = '\n'.join(post_body)
(headers, body) = _conn.request(
SERVER_URL + '/batch',
method='POST', body=post, headers=headers)
Great reply!
If somebody wants to use a raw function in php to make batch requests for fetching emails corresponding to message ids, please feel free to use mine.
function perform_batch_operation($auth_token, $gmail_api_key, $email_id, $message_ids, $BOUNDARY = "gmail_data_boundary"){
$post_body = "";
foreach ($message_ids as $message_id) {
$post_body .= "--$BOUNDARY\n";
$post_body .= "Content-Type: application/http\n\n";
$post_body .= 'GET https://www.googleapis.com/gmail/v1/users/'.$email_id.
'/messages/'.$message_id.'?metadataHeaders=From&metadataHeaders=Date&format=metadata&key='.urlencode($gmail_api_key)."\n\n";
}
$post_body .= "--$BOUNDARY--\n";
$headers = [ 'Content-type: multipart/mixed; boundary='.$BOUNDARY, 'Authorization: OAuth '.$auth_token ];
$curl = curl_init();
curl_setopt($curl,CURLOPT_URL, 'https://www.googleapis.com/batch' );
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
curl_setopt($curl,CURLOPT_CONNECTTIMEOUT , 60 ) ;
curl_setopt($curl, CURLOPT_TIMEOUT, 60 ) ;
curl_setopt($curl,CURLOPT_POSTFIELDS , $post_body);
curl_setopt($curl, CURLOPT_RETURNTRANSFER,TRUE);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER,0);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
$tmp_response = curl_exec($curl);
curl_close($curl);
return $tmp_response;
}
FYI the above function gets just the headers for the emails, in particular the From and Date fields, please adjust according to the api documentation https://developers.google.com/gmail/api/v1/reference/users/messages/get
In addition to MaK you can perform multiple batch requests using the google-api-php-client and Google_Http_Batch()
$optParams = [];
$optParams['maxResults'] = 5;
$optParams['labelIds'] = 'INBOX'; // Only show messages in Inbox
$optParams['q'] = 'subject:hello'; // search for hello in subject
$messages = $service->users_messages->listUsersMessages($email_id,$optParams);
$list = $messages->getMessages();
$client->setUseBatch(true);
$batch = new Google_Http_Batch($client);
foreach($list as $message_data){
$message_id = $message_data->getId();
$optParams = array('format' => 'full');
$request = $service->users_messages->get($email_id,$message_id,$optParams);
$batch->add($request, $message_id);
}
$results = $batch->execute();
here is the python version, using the official google api client. Note that I did not use the callback here, because I need to handle the responses in a synchronous way.
from apiclient.http import BatchHttpRequest
import json
batch = BatchHttpRequest()
#assume we got messages from Gmail query API
for message in messages:
batch.add(service.users().messages().get(userId='me', id=message['id'],
format='raw'))
batch.execute()
for request_id in batch._order:
resp, content = batch._responses[request_id]
message = json.loads(content)
#handle your message here, like a regular email object
solution from Walty Yeung is worked partially for my use case.
if you guys tried the code and nothing happens use this batch
batch = service.new_batch_http_request()

cURL error 26 couldn't open file

So, need help.
prePS - code works but not works fine when load test.
So, at all, php code get from user a file and save it on cluster(4 nodes) as tree parts.
so, simple code like.
$user_file = get_full_filename_of_userfile_from_post_array('user_file');
$fin = fopen($user_file,'rb');
$fout1 = fopen(get_uniq_name('p1'),'wb');
$fout2 = fopen(get_uniq_name('p2'),'wb');
$fout3 = fopen(get_uniq_name('p3'),'wb');
while ($part = fread($fin))
{
fwrite($fout1,get_1_part($part));
fwrite($fout2,get_2_part($part));
fwrite($fout3,get_3_part($part));
}
fclose($fin);
fclose($fout1);
fclose($fout2);
fclose($fout3);
$location = get_random_nodes(3,$array_of_existing_nodes);
foreach($location as $key => $node)//key 1..3
{
if(is_local_node($node)
{
save_local_file(get_part_file_name($key));
}
else
{
save_remote_file(get_part_file_name($key),$node);
}
}
//delete tmp files, logs,...etc
save_remote_file() - using cURL sends a file POST method like in docs
$post_data = array(
'md5sum' => $md5sum,
'ctime' => $ctime,
.....
'file' => #.$upload_file_full_name,
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, Config::get('connect_curl_timeout'));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible;)");
curl_setopt($ch, CURLOPT_URL, $URL.'/index.php');
curl_setopt($ch, CURLOPT_PORT, Config::get('NODES_PORT'));
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_FAILONERROR, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
So, during test, I upload 14000 files, a file per request, 10 request per node (parallel).
php code, check file and get answer, and then in background saving file on cluster.
(yes ,I know that it would be nice to create daemon for saving - it is a task for future)
SO, sometime, there may be about 100, or even 200 php processes on node, in background
(use php-fpm function )
ignore_user_abort(true);
set_time_limit(0);
session_commit();
if(function_exists('fastcgi_finish_request'))
fastcgi_finish_request();
A few calculation.
14000 files = 14000*3=42000parts, saveing on random 3 from 4, so 25% parts save locally, 75% -remote
= 0.75*42000 = 31500 remote saveings
during test I gets about 100 errors on all nodes from curl
errno = 26
errer = couldn't open file "##ІИP_zOж
лЅHж"//it is stranger, because origin file name - it is about 124 chars in name. example
/var/vhosts/my.domains.com/www/process/r_5357bc33f3686_h1398258739.9968.758df087f8db9b340653ceb1abf160ae8512db03.chunk0.part2
before code with cURL , I added checks file_exists($upload_file_full_name)
and is_readable($upload_file_full_name); if not - log it.
checks passed good, but curl returns error(100 times from 31500 ones)
also, add code, if error, wait 10secs, try againg, wait 10secs, try, wait 10 try.
always all if first try with error, all next tries with error too, but according logs, at the same time another php processes what are saving other files, good send a part via curl.
So I don't understand, how can I find a reason and fixing it.

How read and write to cloudant using PHP

I have been trying to use the Curl examples on cloundant using PHP. However, nothing I try works. All I want to do is simply read, write, search data on cloundant using PHP. However, there doesn't seem to be a simple way for a beginning developer to do this.
Code here:
//Get DB's
$returned_content = get_data('https://**InstanceName**:**Password**#**InstanceName**.cloudant.com/_all_dbs');
function get_data($url)
{
$ch = curl_init();
$timeout = 5;
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
$data = curl_exec($ch);
curl_close($ch);
return $data;
}
The error I get is:
{"error":"unauthorized","reason":"Name or password is incorrect"}
According to How do I make a request using HTTP basic authentication with PHP curl?, you need to set the basic auth credentials outside the URL. Adapting their example to your variable names:
curl_setopt($ch, CURLOPT_USERPWD, $username . ":" . $password);
If your using PHP to interact with your Cloudant database you may want to check out the SAG api library. This makes things fairly easy to do. There are some great examples on how to use this API on their site. Hope this helps.
You may also want to check out IBM's new Bluemix environment where they have Cloudant as one of the available services. The integration between Cloudant and Bluemix is excellent.
http://www.saggingcouch.com/
http://www.bluemix.net
I have used Node.js & NodeExpress with Cloudant. You could do similar stuff for PHP. See if these 2 posts help
A Cloud Medley with IBM Bluemix, Cloudant & Node.js
Rock N'Roll with Bluemix, Cloudant & NodeExpress
// this is how I get cloudant api keys in PHP
$username='yourusername';
$password='yourpassword';
$URL='https://yourusername.cloudant.com/_api/v2/api_keys';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$URL);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
//curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_MAXREDIRS, 10);
curl_setopt($ch, CURLOPT_RETURNTRANSFER,true);
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
curl_setopt($ch, CURLOPT_USERPWD, "$username:$password");
//$status_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); //get status code
$response=curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
//$httpCode = 303; // test a fail code
if($httpCode == 201) {
$json = json_decode($response, true);
if($json['ok'] == 1) {
$cloudantkey = $json['key'];
$cloudantpassword = $json['password'];
echo "Obtained Cloud Api Keys.. <br />";
} else {
echo("error $httpCode");
die();
}
} else {
echo("error $httpCode");
die();
}
if(curl_error($ch)){
echo("curl error");
die();
}
curl_close ($ch);

How to make the libcurl send digest authentication header in each http packet?

I have the following function http_send_message() wich I use each time I want to send a http message:
http_send_message(char *msg_out, char **msg_in)
{
CURLcode res;
CURL *curl;
curl = curl_easy_init();
if (!curl) return -1;
curl_easy_setopt(curl, CURLOPT_URL, "http://192.168.1.133:8080/tawtaw");
curl_easy_setopt(curl, CURLOPT_USERNAME, "tawtaw");
curl_easy_setopt(curl, CURLOPT_PASSWORD, "tawtaw");
curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC|CURLAUTH_DIGEST);
.
.
.
curl_easy_cleanup(curl);
}
But I remarked in each time the function send the http message, it try to send a request without the digest authentication header and then it send it with the digest authentication header. In normal case It should do this behaviour only in the first message. And for the subsequent messages it should remeber the authentication header and send it in each message
To obtain such a behavior you need to re-use you curl handle for the subsequent calls to take full advantage of persistent connections and Digest Access Authentication request counter:
[...] the client may make another request, reusing the server nonce value (the server only issues a new nonce for each "401" response) but providing a new client nonce (cnonce). For subsequent requests, the hexadecimal request counter (nc) must be greater than the last value it used
In practice do not clean up your curl handle. Instead maintain it and as soon as you need to perform another request:
reset it with the curl_easy_reset function: curl_easy_reset(curl);
then re-set your options.
If you use the CURLOPT_VERBOSE option you will see that for the subsequent requests you will have an Authorization header with an increasing request counter (nc=00000002, nc=00000003, etc).

Resources