Coinbase transfer between accounts returns "Not found" - node.js

I'm trying to transfer BTC and BCH between accounts. Looking through the documentation I have found the following:
https://developers.coinbase.com/api/v2#transfer-money-between-accounts
First off I believe there is an error in their example, as the "currency" property is mandatory, it gives an error when not providing it.
But after adding the currency, every request I make returns with "Not found".
I'm using the node client, but I think the problem is higher up.
This is the request I'm doing:
const Client = require('coinbase').Client;
let client = new Client({'apiKey': 'xxxx', 'apiSecret': 'xxx'});
client.getAccounts({}, function(err, accounts) {
let btc_account = null;
let bch_account = null;
for(account of accounts) {
if(account.currency == "BTC") {
btc_account = account;
} else if(account.currency == "BCH") {
bch_account = account;
}
}
var options = {'to': bch_account.id, 'amount': btc_account.balance.amount, 'currency': "BTC"};
btc_account.transferMoney(options, function(err, tx) {
if(err) {
console.log("ERROR during transfer", err);
return
}
console.log(tx);
});
});
Doing this returns me with:
ERROR during transfer NotFound: Not found
After doing some debugging, I found it tries to do the request with the following options:
url: 'https://api.coinbase.com/v2/accounts/xxx/transactions'
body: '{"to":"xxx","amount":"0.00072256","currency":"BTC","type":"transfer"}'
(obfuscated the actual account.id's)
And the actual response from their API is:
{"errors":[{"id":"not_found","message":"Not found"}]}
Can anybody tell me what I'm doing wrong here?

Related

NodeJS insert voucher code to first person who calls API

I don't know if this has a solution already but I can't find it or I don't know what to search.
I have a rest api which returns a list of products and I want to add a voucher code to the response of the first person who calls the api. I'm using redis to cache the information of the user who received the code, that expires within 15 mins.
async function addVoucherCode(response, userId) {
try {
const key = "KEY_VOUCHER_CODE";
let cachedData = await redis.get(key);
if (cachedData) {
if (cachedData.userId === userId) response.voucherCode = cachedData.voucherCode;
return;
}
const voucherCode = await createVoucherCode(userId); //call to create voucher code and save to db
if (!voucherCode) return;
await redis.setEx(key, 15 * 60, {userId, voucherCode});
response.voucherCode = cachedData.voucherCode;
} catch (err) {
console.error("[Error] addVoucherCode: ", err);
}
}
I created a function that mimics a simultaneous request, and when I checked the response, all them have a voucher code, not just the first.
async function getProducts(url, params) {
try {
const customers = [
{ id: 1, token: "Bearer eyJhbGciOi....1" },
{ id: 2, token: "Bearer eyJhbGciOi....2"},
{ id: 3, token: "Bearer eyJhbGciOi....3"},
{ id: 4, token: "Bearer eyJhbGciOi....4"}
];
const data = await Promise.all(customers.map( async customer => {
return await fetch(url + "?" + params.toString(), {
headers: {
Authorization: customer.token
},
}).then(res => res.json());
}));
data.forEach((item, indx) => {
if(item.voucherCode) {
const id = customers[indx].id;
console.log(`Customer ${id} has a voucher!!!!!!!!!!!!!`)
}
})
} catch (err) {
console.error("[Error] getProducts: ", err);
}
}
Result
Customer 1 has a voucher!!!!!!!!!!!!!
Customer 2 has a voucher!!!!!!!!!!!!!
Customer 3 has a voucher!!!!!!!!!!!!!
Customer 4 has a voucher!!!!!!!!!!!!!
I tried adding a 200ms delay inside addVoucherCode but same result. Thanks in advance for the help.
You are calling addVoucherCode in a sync loop, so it'll run 4 times in parallel (and the 4 GET commands will be issued at the same time, it'll reply with null to all of them, and all of them will call createVoucherCode).
There are 2 things you can do to fix it:
Cache the promise of createVoucherCode:
const createVoucherCodePromises = new Map();
function createVoucherCode(userId) {
if (!createVoucherCodePromises.has(userId)) {
createVoucherCodePromises.set(
userId,
_createVoucherCode(userId)
.finally(() => createVoucherCodePromises.delete(userId))
);
}
return createVoucherCodePromises.get(userId);
}
async function _createVoucherCode(userId) {
// ...
}
NOTE: this will not solve the problem if you have multiple node processes running at the same time.
Use SET with NX (won't override existing values) and GET (return existing/old value)
> SET key voucher1 NX GET
OK
> SET key voucher2 NX GET # will return the existing value without overriding it
"voucher1"
> GET key
"voucher1"

Creating and Capturing payment with paypal v2 node.js

I am trying to integrate PayPal server-side payment on a website with a new v2 since v1 is deprecated. Since I had to include quite a lot of code from their git, i will post here everything for a working example
In v1 i could do it really easily:
app.get('/create', function (req, res) {
//build PayPal payment request
let payReq = JSON.stringify({
'intent': 'sale',
'redirect_urls': {
'return_url': 'http://localhost:8081/process',
'cancel_url': 'http://localhost:8081/cancel'
},
'payer': {
'payment_method': 'paypal'
},
'transactions': [{
'amount': {
'total': '7.47',
'currency': 'USD'
},
'description': 'This is the payment transaction description.'
}]
});
paypal.payment.create(payReq, function (error, payment) {
if (error) {
console.error(error);
} else {
//capture HATEOAS links
let links = {};
payment.links.forEach(function (linkObj) {
links[linkObj.rel] = {
'href': linkObj.href,
'method': linkObj.method
};
})
//if redirect url present, redirect user
if (links.hasOwnProperty('approval_url')) {
res.redirect(links['approval_url'].href);
} else {
console.error('no redirect URI present');
}
}
});
});
app.get('/process', function (req, res) {
let paymentId = req.query.paymentId;
let payerId = {'payer_id': req.query.PayerID};
paypal.payment.execute(paymentId, payerId, function (error, payment) {
if (error) {
console.error(error);
} else {
if (payment.state == 'approved') {
const payerCountry = payment.payer.payer_info.country_code;
const total = payment.transactions[0].amount.total;
const currency = payment.transactions[0].amount.currency;
savePayment(payerCountry, total, currency);
res.send('payment completed successfully ' + cnt++);
} else {
res.send('payment not successful');
}
}
});
});
The create endpoint basically creates the order, the paypal API returns hateos links and the controller says the browser should redirect to that link. Once redirected , if user approves payment on paypal site he is redirected to on of
'redirect_urls': {
'return_url': 'http://localhost:8081/process',
'cancel_url': 'http://localhost:8081/cancel'
},
process endpoints retrieves PAYMENT ID and PAYER ID from query and captures the order - allowing me to do whatever i want to do ( e.g save payment in db ) in callback.
Now v2 seems like huge mess:
Following devs guide i have created
Paypal button (copy paste ):
import React, {useEffect} from "react";
import {PayPalButtons, PayPalScriptProvider, usePayPalScriptReducer} from "#paypal/react-paypal-js";
// This values are the props in the UI
const amount = "2";
const currency = "USD";
const style = {"layout": "vertical"};
const ButtonWrapper = ({currency, showSpinner}) => {
// usePayPalScriptReducer can be use only inside children of PayPalScriptProviders
// This is the main reason to wrap the PayPalButtons in a new component
const [{options, isPending}, dispatch] = usePayPalScriptReducer();
useEffect(() => {
dispatch({
type: "resetOptions",
value: {
...options,
currency: currency,
},
});
}, [currency, showSpinner]);
const createOrder = (data, actions) => {
console.log("create")
return fetch('http://localhost:8081/create', {
method: 'post'
}).then(function (res) {
return res.json();
}).then(function (orderData) {
console.log(orderData);
window.location = orderData.redirect;
});
}
// Call your server to finalize the transaction
const onApprove = (data, actions) => {
console.log("approve")
return fetch('/process', {
method: 'post'
}).then(function (res) {
return res.json();
}).then(function (orderData) {
// Three cases to handle:
// (1) Recoverable INSTRUMENT_DECLINED -> call actions.restart()
// (2) Other non-recoverable errors -> Show a failure message
// (3) Successful transaction -> Show confirmation or thank you
// This example reads a v2/checkout/orders capture response, propagated from the server
// You could use a different API or structure for your 'orderData'
var errorDetail = Array.isArray(orderData.details) && orderData.details[0];
if (errorDetail && errorDetail.issue === 'INSTRUMENT_DECLINED') {
return actions.restart(); // Recoverable state, per:
// https://developer.paypal.com/docs/checkout/integration-features/funding-failure/
}
if (errorDetail) {
var msg = 'Sorry, your transaction could not be processed.';
if (errorDetail.description) msg += '\n\n' + errorDetail.description;
if (orderData.debug_id) msg += ' (' + orderData.debug_id + ')';
return alert(msg); // Show a failure message (try to avoid alerts in production environments)
}
// Successful capture! For demo purposes:
console.log('Capture result', orderData, JSON.stringify(orderData, null, 2));
var transaction = orderData.purchase_units[0].payments.captures[0];
alert('Transaction ' + transaction.status + ': ' + transaction.id + '\n\nSee console for all available details');
});
}
return (<>
{(showSpinner && isPending) && <div className="spinner"/>}
<PayPalButtons
style={style}
disabled={false}
forceReRender={[amount, currency, style]}
fundingSource={undefined}
createOrder={(data, actions) => createOrder(data, actions)}
onApprove={(data, actions) => onApprove(data, actions)}
/>
</>
);
}
export default function PayPalButton() {
return (
<div style={{ maxWidth: "750px", minHeight: "200px" }}>
<PayPalScriptProvider
options={{
"client-id": "test",
components: "buttons",
currency: "USD"
}}
>
<ButtonWrapper
currency={currency}
showSpinner={false}
/>
</PayPalScriptProvider>
</div>
);
}
And then followed the flow from paypal's github example
created their HttpClient
const checkoutNodeJssdk = require('#paypal/checkout-server-sdk');
/**
* Returns PayPal HTTP client instance with environment which has access
* credentials context. This can be used invoke PayPal API's provided the
* credentials have the access to do so.
*/
function client() {
return new checkoutNodeJssdk.core.PayPalHttpClient(environment());
}
/**
* Setting up and Returns PayPal SDK environment with PayPal Access credentials.
* For demo purpose, we are using SandboxEnvironment. In production this will be
* LiveEnvironment.
*/
function environment() {
let clientId = process.env.PAYPAL_CLIENT_ID || '<clientId>';
let clientSecret = process.env.PAYPAL_CLIENT_SECRET || '<secret>';
if (process.env.NODE_ENV === 'production') {
return new checkoutNodeJssdk.core.LiveEnvironment(clientId, clientSecret);
}
return new checkoutNodeJssdk.core.SandboxEnvironment(clientId, clientSecret);
}
async function prettyPrint(jsonData, pre=""){
let pretty = "";
function capitalize(string) {
return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase();
}
for (let key in jsonData){
if (jsonData.hasOwnProperty(key)){
if (isNaN(key))
pretty += pre + capitalize(key) + ": ";
else
pretty += pre + (parseInt(key) + 1) + ": ";
if (typeof jsonData[key] === "object"){
pretty += "\n";
pretty += await prettyPrint(jsonData[key], pre + "\t");
}
else {
pretty += jsonData[key] + "\n";
}
}
}
return pretty;
}
module.exports = {client: client, prettyPrint:prettyPrint};
created their CreateOrder:
/**
* PayPal SDK dependency
*/
const checkoutNodeJssdk = require('#paypal/checkout-server-sdk');
/**
* PayPal HTTP client dependency
*/
const payPalClient = require('./PayPalClient');
/**
* Setting up the JSON request body for creating the Order. The Intent in the
* request body should be set as "CAPTURE" for capture intent flow.
*
*/
function buildRequestBody() {
return {
"intent": "CAPTURE",
"application_context": {
"return_url": "http://localhost:8081/process",
"cancel_url": "https://www.example.com",
"locale": "en-US",
"landing_page": "BILLING",
"user_action": "CONTINUE"
},
"purchase_units": [
{
"soft_descriptor": "Donation",
"amount": {
"currency_code": "USD",
"value": "220.00"
}
}
]
};
}
/**
* This is the sample function which can be sued to create an order. It uses the
* JSON body returned by buildRequestBody() to create an new Order.
*/
async function createOrder(debug=false) {
try {
const request = new checkoutNodeJssdk.orders.OrdersCreateRequest();
request.headers["prefer"] = "return=representation";
request.requestBody(buildRequestBody());
const response = await payPalClient.client().execute(request);
if (debug){
console.log("Status Code: " + response.statusCode);
console.log("Status: " + response.result.status);
console.log("Order ID: " + response.result.id);
console.log("Intent: " + response.result.intent);
console.log("Links: ");
response.result.links.forEach((item, index) => {
let rel = item.rel;
let href = item.href;
let method = item.method;
let message = `\t${rel}: ${href}\tCall Type: ${method}`;
console.log(message);
});
console.log(`Gross Amount: ${response.result.purchase_units[0].amount.currency_code} ${response.result.purchase_units[0].amount.value}`);
// To toggle print the whole body comment/uncomment the below line
console.log(JSON.stringify(response.result, null, 4));
}
return response;
}
catch (e) {
console.log(e)
}
}
/**
* This is the driver function which invokes the createOrder function to create
* an sample order.
*/
if (require.main === module){
(async() => await createOrder(true))();
}
/**
* Exports the Create Order function. If needed this can be invoked from the
* order modules to execute the end to flow like create order, retrieve, capture
* and refund(Optional)
*/
module.exports = {createOrder:createOrder};
And endpoints:
const createUsersOrder = async (res) => {
try {
let response = await createOrder();
console.log("Creating Order...");
let orderId = "";
if (response.statusCode === 201){
console.log("Created Successfully");
orderId = response.result.id;
console.log("Links:");
response.result.links.forEach((item, index) => {
let rel = item.rel;
let href = item.href;
let method = item.method;
let message = `\t${rel}: ${href}\tCall Type: ${method}`;
console.log(message);
});
let links = {};
response.result.links.forEach(function (linkObj) {
links[linkObj.rel] = {
'href': linkObj.href,
'method': linkObj.method
};
})
//if redirect url present, redirect user
if (links.hasOwnProperty('approve')) {
var returnObj = {redirect : links['approve'].href}
console.log("Returning " + returnObj)
res.send(returnObj);
} else {
console.error('no redirect URI present');
}
}
console.log("Copy approve link and paste it in browser. Login with buyer account and follow the instructions.\nOnce approved hit enter...");
return
} catch (error) {
console.log('There was an error: ', error);
}
};
app.post("/create", function(req,res) {
createUsersOrder(res);
})
Here, this is called when button is clicked, as "createOrder" method is called. I create order just like in the v1 code, and then redirect browser to the url. However when the user approves transaction on paypal, and thus is being redirected to one of
"application_context": {
"return_url": "http://localhost:8081/process",
"cancel_url": "http://localhost:8081/cancel",
"locale": "en-US",
"landing_page": "BILLING",
"user_action": "CONTINUE"
},
return url ( /process route for success ), the request DOES NOT contain payment_id, only PAYER_ID. But the payment_id ( or order_id in v2 ) is needed to capture the order.
Since i have found literally zero blogs, tutorials, guide for v2 ( only millions for v1) i am confused where to get the order id. Do i really need to save it in DB after i create the order? OR is there any other trick?
Also, the button contains onApprove method, but after creating order, the browser is redirected to paypal, and the paypal redirects user to http://localhost:8081/process endpoint - thus the onApprove method is never invoked and useless (?).
This whole flow of v2 is really confusing, is there something i am missing?
Thanks for help
With your v2 code, do not use any redirects. At all. Your button should call 2 endpoints on your server. These two endpoints should (respectively) do the API operations of creating and capturing the order, and return the JSON result in each case (the capture route can do any server-side operations like storing the transaction result in the database before forwarding the JSON result to the client caller, since the client needs to handle any capture error situations as well as showing a success message). You can find a full stack node.js example in the PayPal integration guide, but it's fine to keep your #paypal/react-paypal-js code pretty much as-is for the front end.

User response is being cutoff and throwing an Unexpected Error. How to get the error message that happened

I am developing a skill using JOVO which takes notes from users and saves in a database. The workflow is working OK but when I am saying something the data is being cut off and a portion of it is getting saved in the database but the session seems to be alive still.
When I am trying to say something again, Alexa is saying Unexpected Error. This is happening for one intent only. It has one slot and the type is AMAZON.SearchQuery.
I want to know the exact error happened and take it to my email address for better understanding. How can I do this?
According to this article, I can customize the error. But I want to know the exact type of error occurred and get the full error message in my email. How can I do this?
I checked my database field length and it is good enough to store a long text. The portion being saved, is nowhere near the field length. It is much lower.
However, this is not happening when I am testing from Alexa test console. Even a 500 character long text is getting saved fine in the database from here. I am using AMAZON.SearchQuery for this slot. Does Alexa have a restriction of character length to be passed as slot value?
I am not able to locate the issue. Google could not help either!
UPDATE
Intent Code:
async NotesBuilderIntent() {
if (this.$inputs.note.value === undefined) {
this.ask("what do you want me to know?");
} else {
if (this.$session.$data.agent_code === undefined) {
/**
* This client has landed directly on the intent
* let's retrieve his info based in Amazon access token
* and create required session values.
*/
if (!this.$request.getAccessToken()) {
return this.tell(
"Oops! Looks like you have either disabled or not enabled the skill yet. Please link your account by going to the Alexa app or companion app to proceed. thank you!"
);
} else {
const token = this.$request.getAccessToken();
//Retrieve user data using access_token.
const profile = await custom.getUserAmazonProfile(token);
// Extract email and amazon profile_id
const profile_id = profile.user_id;
const profile_email = profile.email;
const profile_name = profile.name;
const objUser = await custom.validate_account(
profile_id,
profile_email
);
const status_code = parseInt(objUser.status_code);
if (status_code === 100) {
this.$session.$data.agent_code = objUser.client.agent_code;
this.$session.$data.account_code = objUser.client.account_code;
} else {
const user = await custom.skillTestMode(
profile_email,
profile_name
);
const mode_current = user.current_mode;
if (mode_current === "D") {
this.$session.$data.agent_code = user.client.agent_code;
this.$session.$data.account_code = user.client.account_code;
} else {
return this.tell(
"sorry! looks like you are not authorized to use this skill. please contact your account manager."
);
}
}
}
}
/**
* We already have the client info based on
* access token and built required session values
* to proceed.
*/
const agent_note = this.$inputs.note.value;
const agent_code = this.$session.$data.agent_code;
const account_code = this.$session.$data.account_code;
if (
agent_note === "stop" ||
agent_note === "cancel" ||
agent_note === "later" ||
agent_note === "maybe later" ||
agent_note === "not now" ||
agent_note === "nothing" ||
agent_note === "no"
) {
return this.toIntent("StopIntent");
} else {
const result = await custom.saveAgentNote(
agent_code,
account_code,
agent_note
);
const output = result.speech;
this.ask(`${output}`);
}
}
}
saveAgentNote function:
saveAgentNote: async (agent_code, account_code, agent_note) => {
let data = {};
await rp({
url: baseURI,
headers: { "Content-Type": "application/json" },
qs: {
action: actions.addNote,
code: agent_code,
account_code: account_code,
note: agent_note
},
method: "POST"
})
.then(body => {
data = JSON.parse(body);
})
.catch(error => {
console.log(error);
});
return data;
}
after analyzing your code to find out what causes the session to stay alive, it seems that it is in the next code fraction:
const result = await custom.saveAgentNote(
agent_code,
account_code,
agent_note
);
const output = result.speech;
this.ask(`${output}`);
the line this.ask(`${output}`); you must replace it with this.tell(`${output}`);
For more info about it you can check the next link:
https://www.jovo.tech/docs/output

Why is user information not available from firebase cloud database trigger?

I have created a Firebase cloud function that will trigger on update of the data. When I go into Firebase console and change the node to either true or false, it triggers and I receive an email from my SendGrid set up. The problem is I am not able to obtain the users e-mail information.
I have spent over a week pouring over the documentation and it says I should be able to use context.auth, however, that is always "undefined" when printed out in console.
I have been trying to get the user data from the users actual info in Firebase as well as in /users/{uid}/email. I can't seem to figure out how to get the e-mail since the snapshot is in a different spot.
I need to somehow extract the users first name and email, which are in in:
/users/uid/first_name and /users/uid/email
I want those two things put into this function, so then I can tell SendGrid to use the email and name. The Sendgrid portion is working fine.
context.params.uid gives me the users firebase ID, but does nothing for me. I can't seem to use that to get the data I need
I tried authVar = context.auth and when I print it out it says 'undefined' and my function stops working.
exports.myFunctionPending =
functions.database.ref('/users/{uid}/profile/isPending')
.onUpdate(async (change, context) => {
const snapshot = change.after;
const val = snapshot.val();
const userid = context.params.uid; //shows userid but is useless
const authVar = context.auth; //says undefined and does nothing
console.log(val);
console.log(userid);
const msg = {
to: 'myemail#mydomain.com',
from: 'noreply#mydomain.com',
// custom templates
templateId: 'd-b7aakjsdgwq7d798wq7d8',
substitutionWrappers: ['{{', '}}'],
//substitutions: {
dynamic_template_data: {
//name: user.displayName
name: 'My Name'
}
};
try {
await sgMail.send(msg);
console.log('This was sucessful');
} catch(error) {
console.error('There was an error while sending the email:', error);
}
return null;
});
I had the code in the incorrect spot, I changed the logic and now it's working as intended.
exports.myFunction = functions.database.ref('/users/{uid}/user_area/pending')
.onUpdate(async (change, context) => {
const triggersnapshot = change.after;
const val = triggersnapshot.val();
const userid = context.params.uid;
console.log(val);
console.log(userid);
return admin.database().ref('users/' + userid).once('value').then(function (snapshot) {
var email = snapshot.child('email');
var name = snapshot.child('first_name');
console.log(snapshot.val());
console.log(email.val());
const msg = {
to: [email],
from: {
email: 'noreply#noreply.com',
name: 'No Name'
},
// custom templates
templateId: 'd-8347983274983u483242',
substitutionWrappers: ['{{', '}}'],
dynamic_template_data: {
name: name
}
};
return sgMail.send(msg);
});

Stripe Display Connected Account Balance to User

I am integrating Stripe into my ridesharing app and I was wondering if it was possible to display the Connect Account balance to the user in Swift?
Stripe has an option to retrievestripe.balance.retrieve({}), but that is showing the balance in the console.
Is it possible to pass this value to the frontend in Swift with a GET request and storing the value in a UITextLabel?
I tried something with this GET request, but I can only get it to display in the Swift console?
func readBalance(userID: String)
{
var viewProfileComponents = URLComponents(string: "http://myWebsite/payment/payout")!
viewProfileComponents.queryItems = [
URLQueryItem(name: "userID", value: userID)
]
var request = URLRequest(url: viewProfileComponents.url!) // Pass Parameter in URL
print (viewProfileComponents.url!)
request.httpMethod = "GET" // GET METHOD
URLSession.shared.dataTask(with: request) { (data, response, error) -> Void in
if (error != nil){ // error handling responses.
print (error as Any)
}
else if let data = data {
print(data)
let userInfoString:NSString = NSString(data: data, encoding: String.Encoding.utf8.rawValue)!
if let data = userInfoString.data(using: String.Encoding.utf8.rawValue) {
do {
let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String:AnyObject]
print (json as Any)
if let userInfo = json!["data"]
{
DispatchQueue.main.async {
self.balanceAmount.text? = (userInfo["balance"] as! String)
}
}
} catch let error as NSError {
print(error)
}
}
}
}.resume()
}
Where balanceAmount is my UITextLabel
GET Request
router.get("/payout", function (req, res) {
var userID = req.query.userID;
console.log('get payout body ', req.body);
db.query(`select \"Users\".\"stripeAccountID\", \"Users\".\"balance\" from database.\"Users\" where \"Users\".\"userID\" ='${userID}'`)
.then(function(data) {
const accBalance = stripe.balance.retrieve({
stripe_account: data.stripeAccountID
}).then(db.any(`UPDATE database.\"Users\" set \"Users\".\"balance\" = '${accBalance}' where \"Users\".\"userID\" ='${userID}'`));
console.log(data.balance)
console.log('data: ', data)
res.status(200).json({
status: 'Success',
data: data,
message: 'Retrieved Account Balance.'
});
})
.catch(function(error){
console.log('Error fetching payout', error);
});
})
Stripe Server GET Response
Xcode Console Response
I know the Xcode GET response doesn't match, the balance in Xcode is being grabbed from the Database value.
If there is any other information that could help, please let me know.
Thank you in advance!

Resources