I am trying to incorporate the BTC-e.com API in to a google docs spreadsheet.
The API documentation is here: https://btc-e.com/api/documentation
The method name is sent via POST parameter method.
As the URLFetchApp requires me to set the type of request as POST by a parameter method and I then have another parameter called method to be set as getInfo.
How can I go about setting the fetch method as POST and have the API parameter method as getInfo.
Below is the function this relates too. Also I am sure there a more issues in my work I am yet to find.
function inventory() {
var nonce=Number(SpreadsheetApp.getActiveSheet().getRange('K2').getValue());
var token=SpreadsheetApp.getActiveSheet().getRange('K1').getValue();
var tokenEndpoint = "https://btc-e.com/tapi";
var sign= 'TEMP'
var head = {
'Content-Type': 'application/x-www-form-urlencoded',
'Key': token,
'Sign': sign
}
var params = {
method : "POST",
method : "getInfo",
headers: head,
contentType: 'application/x-www-form-urlencoded',
method : "getInfo",
nonce: nonce
}
var request = UrlFetchApp.getRequest(tokenEndpoint, params);
var response = UrlFetchApp.fetch(tokenEndpoint, params);
var response2=String(response);
SpreadsheetApp.getActiveSheet().getRange('K2').setValue(nonce+1);
SpreadsheetApp.getActiveSheet().getRange('I16').setValue(response2);
SpreadsheetApp.getActiveSheet().getRange('I17').setValue(nonce);
}
This just yields the error
Attribute provided with invalid value: method
Thanks,
Steve
PS: First time posting, I tried to get the format correct.
I made the following Google JavaScript function to do POST access to BTC-e. You can find this function in action in the example spreadsheet I made to demonstrate the BTC-e API functions.
function btceHttpPost(keyPair, method, params, nonce) {
if (keyPair === undefined) {
return "{'error':'missing key pair'}"
}
if (params === undefined) {
params = '';
}
// Cleanup keypair, remove all \s (any whitespace)
var keyPair = keyPair.replace(/[\s]/g, '');
// Keypair example: "AFE730YV-S9A4FXBJ-NQ12HXS9-CA3S3MPM-CKQLU0PG,96a00f086824ddfddd9085a5c32b8a7b225657ae2fe9c4483b4c109fab6bf1a7"
keyPair = keyPair.split(',');
var pubKey = keyPair[0];
var privKey = keyPair[1];
// As specified on the BTC-e api (https://btc-e.com/api/documentation) the
// nonce POST parameter must be an incrementing integer (>0). The easiest
// implementation is the use of a timestamp (TS), so there is no need
// for persistant storage. Preferable, the resolution of the TS should be
// small enough the handle the desired call-frequency (a sleep of the TS
// resolution can fix this but I don't like such a waste). Another
// consideration is the sizeof the nonce supported by BTC-e. Experiments
// revealed this is a 32 bit unsigned number. The native JavaScript TS,
// stored in a float, can be 53 bits and has a resolution of 1 ms.
if (nonce === undefined)
// This time stamp counts amount of 200ms ticks starting from Jan 1st, 2014 UTC
// On 22 Mar 2041 01:17:39 UTC, it will overflow the 32 bits and will fail
// the nonce key for BTC-e
var nonce = Math.floor((Date.now() - Date.UTC(2014,0)) / 200);
// Construct payload message
var msg = 'nonce=' + nonce + '&method=' + method + params;
var msgSign = Utilities.computeHmacSignature(Utilities.MacAlgorithm.HMAC_SHA_512, msg, privKey);
// Convert encoded message from byte[] to hex string
for (var msgSignHex = [], i = 0; i < msgSign.length; i++) {
// Doing it nibble by nibble makes sure we keep leading zero's
msgSignHex.push(((msgSign[i] >>> 4) & 0xF).toString(16));
msgSignHex.push((msgSign[i] & 0xF).toString(16));
}
msgSignHex = msgSignHex.join('');
var httpHeaders = {'Key': pubKey, 'Sign': msgSignHex};
var fetchOptions = {'method': 'post', 'headers': httpHeaders, 'payload': msg};
var reponse = UrlFetchApp.fetch('https://btc-e.com/tapi', fetchOptions);
return reponse.getContentText();
};
The problem looks to be with your params object . You have method set thrice in the same object, which is a source of confusion.
Next, take a look at the documentation for UrlFetchApp.fetch() ( https://developers.google.com/apps-script/reference/url-fetch/url-fetch-app#fetch(String,Object) ) . The method can take a value of post, get, delete, put.
The getInfo should probably be appended to your URL to make it
var tokenEndpoint = "https://btc-e.com/tapi/getInfo"
Per the docs, you also have to put in more parameters to the request, nonce, api key etc. Use this as a starting point, revisit the documentation and get back to SO if you still have trouble
Related
I am trying to write a script in google sheets to update my 3commas bots. The API requires a number of mandatory fields are passed even when there's only 1 item that needs to be updated.
The code I have is below and it uses the values already read from the platform updating only the base_order_volume value. This works perfectly except for when the pairs value is long (more the 2k chars) and then I get an error from the UrlFetchApp call because the URL is too long.
var sheet = SpreadsheetApp.getActiveSheet();
var key = sheet.getRange('F4').getValue();
var secret = sheet.getRange('F5').getValue();
var baseUrl = "https://3commas.io";
var editBots = "/ver1/bots/"+bots[botCounter].id+"/update";
var patchEndPoint = "/public/api"+editBots+"?";
.
.
[loop around values in sheet]
.
.
var BaseOrder=Number(sheet.getRange(rowCounter,12).getValue().toFixed(2));
var botParams = {
"name": bots[botCounter].name,
"pairs": bots[botCounter].pairs,
"max_active_deals": bots[botCounter].max_active_deals,
"base_order_volume": BaseOrder,
"take_profit": Number(bots[botCounter].take_profit),
"safety_order_volume": bots[botCounter].safety_order_volume,
"martingale_volume_coefficient": bots[botCounter].martingale_volume_coefficient,
"martingale_step_coefficient": Number(bots[botCounter].martingale_step_coefficient),
"max_safety_orders": bots[botCounter].max_safety_orders,
"active_safety_orders_count": Number(bots[botCounter].active_safety_orders_count),
"safety_order_step_percentage": Number(bots[botCounter].safety_order_step_percentage),
"take_profit_type": bots[botCounter].take_profit_type,
"strategy_list": bots[botCounter].strategy_list,
"bot_id": bots[botCounter].id
};
var keys = Object.keys(botParams);
var totalParams = keys.reduce(function(q, e, i) {
q += e + "=" + encodeURIComponent(JSON.stringify(botParams[e])) + (i != keys.length - 1 ? "&" : "");
return q;
},endPoint);
var signature = Utilities.computeHmacSha256Signature(totalParams, secret);
signature = signature.map(function(e) {return ("0" + (e < 0 ? e + 256 : e).toString(16)).slice(-2)}).join("");
var headers = {
'APIKEY': key,
'Signature': signature,
};
try {
var params = {
'method': 'PATCH',
'headers': headers,
'muteHttpExceptions': true
};
var response = JSON.parse(UrlFetchApp.fetch(baseUrl + totalParams, params).getContentText());
I have tried to set the botParams as a payload in the params but when I do the signature is incorrect.
I anyone knows how to use sheets to make a call using extensive length of parameters I'd appreciate any help at all
Some sample data for the bots array would be
{
"name": "TestBot",
"base_order_volume": 0.001,
"take_profit": 1.5,
"safety_order_volume": 0.001,
"martingale_volume_coefficient": 2,
"martingale_step_coefficient": 1,
"max_safety_orders": 1,
"active_safety_orders_count": 1,
"safety_order_step_percentage": 2.5,
"take_profit_type": "total",
"stop_loss_percentage": 0,
"cooldown": 0,
"pairs": ["BTC_ADA","BTC_TRX"],
"trailing_enabled":"true",
"trailing_deviation":0.5,
"strategy_list": [{"strategy":"cqs_telegram"}]
}
Thanks in advance
I'd consider using a Cloud Function to either do the heavy lifting, or, if you're worried about costs, use it as a proxy. You can then call the cloud function from Google Sheets. Cloud Functions can be written in whatever language you're most comfortable with, including Node.
Check the GCP pricing calculator to see what the cost would be. For many cases it would be completely free.
This should give you a sense of how to use cloud functions for CSV creation:
https://codelabs.developers.google.com/codelabs/cloud-function2sheet#0
Here is a SO question with an answer that explains how to query cloud functions with authentication.
As i can get the query params by using ActivatedRoute which is get request. but how can i get request body by using ActivatedRoute from post request. If ActivatedRoute is not right option to get then how should i get request body
This is my jsp code:-
var res = "url which i am creating";
var url =res[0];
var mapForm = document.createElement("form");
mapForm.target = "Test";
mapForm.method = "post";
mapForm.action = url;
//Splitting parameters from url to add into body
var res1 =res[1].split("=");
var name = res1[0];
var value = res1[1];
mapInput3 = document.createElement("input");
mapInput3.type = "hidden";
mapInput3.name =name;
mapInput3.value = value;
mapForm.appendChild(mapInput3);
document.body.appendChild(mapForm);
map = window.open("", "Test", "menubar,
toolbar, location, directories, status, scrollbars,
resizable, dependent, width=1200, height=600,
left=0,top=0");
if (map) {
mapForm.submit();
}
this is my angular code:-
this.activeRoute.queryParams.subscribe(params => {
this.authKey = params['auth_key'];
});
Now if I sent parameter through get method from jsp, I am able to get it from above angular code.
but if i sent params through post method then i get message as " Cannot post"
If I got you right you want to get the body of the query.
You can use snapshot.get and when declare a it with a value something like this ->
const t = this.route.snapshot.mapedQuery.get()
The value of- t is your query body.
Answered from my phone so I can’t format the code
I'm trying to pull data from the Crunchbase Open Data Map to a Google Spreadsheet. I'm following Ben Collins's script but it no longer works since the upgrade from v3 to v3.1. Anyone had any luck modifying the script for success?
var USER_KEY = 'insert your API key in here';
// function to retrive organizations data
function getCrunchbaseOrgs() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Organizations');
var query = sheet.getRange(3,2).getValue();
// URL and params for the Crunchbase API
var url = 'https://api.crunchbase.com/v/3/odm-organizations?query=' + encodeURI(query) + '&user_key=' + USER_KEY;
var json = getCrunchbaseData(url,query);
if (json[0] === "Error:") {
// deal with error with fetch operation
sheet.getRange(5,1,sheet.getLastRow(),2).clearContent();
sheet.getRange(6,1,1,2).setValues([json]);
}
else {
if (json[0] !== 200) {
// deal with error from api
sheet.getRange(5,1,sheet.getLastRow(),2).clearContent();
sheet.getRange(6,1,1,2).setValues([["Error, server returned code:",json[0]]]);
}
else {
// correct data comes back, filter down to match the name of the entity
var data = json[1].data.items.filter(function(item) {
return item.properties.name == query;
})[0].properties;
// parse into array for Google Sheet
var outputData = [
["Name",data.name],
["Homepage",data.homepage_url],
["Type",data.primary_role],
["Short description",data.short_description],
["Country",data.country_code],
["Region",data.region_name],
["City name",data.city_name],
["Blog url",data.blog_url],
["Facebook",data.facebook_url],
["Linkedin",data.linkedin_url],
["Twitter",data.twitter_url],
["Crunchbase URL","https://www.crunchbase.com/" + data.web_path]
];
// clear any old data
sheet.getRange(5,1,sheet.getLastRow(),2).clearContent();
// insert new data
sheet.getRange(6,1,12,2).setValues(outputData);
// add image with formula and format that row
sheet.getRange(5,2).setFormula('=image("' + data.profile_image_url + '",4,50,50)').setHorizontalAlignment("center");
sheet.setRowHeight(5,60);
}
}
}
This code no longer pulls data as expected.
I couldn't confirm about the error messages when you ran the script. So I would like to show about the clear difference point. It seems that the endpoint was changed from https://api.crunchbase.com/v/3/ to https://api.crunchbase.com/v3.1/. So how about this modification?
From :
var url = 'https://api.crunchbase.com/v/3/odm-organizations?query=' + encodeURI(query) + '&user_key=' + USER_KEY;
To :
var url = 'https://api.crunchbase.com/v3.1/odm-organizations?query=' + encodeURI(query) + '&user_key=' + USER_KEY;
Note :
From your script, I couldn't also find query. So if the script doesn't work even when you modified the endpoint, please confirm about it. You can see the detail of API v3 Compared to API v3.1 is here.
References :
API v3 Compared to API v3.1
Using the API
If this was not useful for you, I'm sorry.
I need a way to search via the eventbrite api past events, by organizer, that are private, but I also need to be able to limit the date range. I have not found a viable solution for this search. I assume the organizer_list_events api would be the preferred method, but the request paramaters don't seem to allow for the date range, and I am getting FAR too many returns.
I'm having some similar issues I posted a question to get a response about parsing the timezone, here's the code I'm using to get the dates though and exclude any events before today (unfortunately like you said I'm still getting everything sent to me and paring things out client side)
Note this is an AngularJS control but the code is just using the EventBrite javascript API.
function EventCtrl($http, $scope)
{
$scope.events=[];
$scope.noEventsDisplay = "Loading events...";
Eventbrite({'app_key': "EVC36F6EQZZ4M5DL6S"}, function(eb){
// define a few parameters to pass to the API
// Options are listed here: http://developer.eventbrite.com/doc/organizers/organizer_list_events/
//3877641809
var options = {
'id' : "3588304527",
};
// provide a callback to display the response data:
eb.organizer_list_events( options, function( response ){
validEvents = [];
var now = new Date().getTime();
for(var i = 0; i<response.events.length; i++)
{
var sd = response.events[i].event.start_date;
var ed = response.events[i].event.end_date;
var parsedSD = sd.split(/[:-\s]/);
var parsedED = ed.split(/[:-\s]/);
var startDate = new Date(parsedSD[0], parsedSD[1]-1, parsedSD[2], parsedSD[3], parsedSD[4], parsedSD[5]);
var endDate = new Date(parsedED[0], parsedED[1]-1, parsedED[2], parsedED[3], parsedED[4], parsedED[5]);
if(endDate.getTime()<now)
continue;
response.events[i].event.formattedDate = date.toDateString();
validEvents.push(response.events[i])
}
if(validEvents.length == 0)
{
$scope.$apply(function(scope){scope.noEventsDisplay = "No upcoming events to display, please check back soon.";});
}
else
{
$scope.$apply(function(scope){scope.noEventsDisplay = "";});
}
$scope.$apply(function(scope){scope.events = validEvents;});
//$('.event_list').html(eb.utils.eventList( response, eb.utils.eventListRow ));
});
});
}
I have a good start on a technique similar to this in Express 3
http://notjustburritos.tumblr.com/post/22682186189/socket-io-and-express-3
the idea being to let me grab the session object from within a socket.io connection callback, storing sessions via connect-redis in this case.
So, in app.configure we have
var db = require('connect-redis')(express)
....
app.configure(function(){
....
app.use(express.cookieParser(SITE_SECRET));
app.use(express.session({ store: new db }));
And in the app code there is
var redis_client = require('redis').createClient()
io.set('authorization', function(data, accept) {
if (!data.headers.cookie) {
return accept('Sesssion cookie required.', false)
}
data.cookie = require('cookie').parse(data.headers.cookie);
/* verify the signature of the session cookie. */
//data.cookie = require('cookie').parse(data.cookie, SITE_SECRET);
data.sessionID = data.cookie['connect.sid']
redis_client.get(data.sessionID, function(err, session) {
if (err) {
return accept('Error in session store.', false)
} else if (!session) {
return accept('Session not found.', false)
}
// success! we're authenticated with a known session.
data.session = session
return accept(null, true)
})
})
The sessions are being saved to redis, the keys look like this:
redis 127.0.0.1:6379> KEYS *
1) "sess:lpeNPnHmQ2f442rE87Y6X28C"
2) "sess:qsWvzubzparNHNoPyNN/CdVw"
and the values are unencrypted JSON. So far so good.
The cookie header, however, contains something like
{ 'connect.sid': 's:lpeNPnHmQ2f442rE87Y6X28C.obCv2x2NT05ieqkmzHnE0VZKDNnqGkcxeQAEVoeoeiU' }
So now the SessionStore and the connect.sid don't match, because the signature part (after the .) is stripped from the SessionStore version.
Question is, is is safe to just truncate out the SID part of the cookie (lpeNPnHmQ2f442rE87Y6X28C) and match based on that, or should the signature part be verified? If so, how?
rather than hacking around with private methods and internals of Connect, that were NOT meant to be used this way, this NPM does a good job of wrapping socket.on in a method that pulls in the session, and parses and verifies
https://github.com/functioncallback/session.socket.io
Just use cookie-signature module, as recommended by the comment lines in Connect's utils.js.
var cookie = require('cookie-signature');
//assuming you already put the session id from the client in a var called "sid"
var sid = cookies['connect.sid'];
sid = cookie.unsign(sid.slice(2),yourSecret);
if (sid == "false") {
//cookie validation failure
//uh oh. Handle this error
} else {
sid = "sess:" + sid;
//proceed to retrieve from store
}