I'm using a Google Apps Script Web App to listen for webhook events from Stripe as well as to post data back. I can post values to attributes that are at the top level without issues, e.g.:
const data = await postCustomer(customerId, {
name: 'Name',
email: 'email@example.com'
}
})
async function postCustomer(id, args) {
const data = await postStripeData(id, args, ['customers'])
return data
}
async function postStripeData(id, args, path1, path2) {
const fullPath = makeFullPath(id, path1, path2)
const data = await post(getStripeApiUrl() + fullPath + '?key=' + getKey(), args)
return data
}
async function post(url, args) {
const response = await UrlFetchApp.fetch(url, {
'method': 'post',
'payload': args
})
if (await response.getResponseCode() === 200) {
const data = await JSON.parse(response)
return data
} else {
throw new Error("I couldn't post to this url: " + url)
}
}
However, I can't post objects within keys (I used a real location in my post request):
const data = await postCustomer(customerId, {
address: {
country: 'US',
state: 'CA',
city: 'City',
postal_code: '00000',
line1: 'Line 1',
line2: 'Line 2'
}
})
The error I get is that address
is an invalid object, and it appears in my Stripe logs like this:
{
"address":
"{line2=Line 2, state=CA, country=US, postal_code=00000, line1=Line 1, city=City}",
}
The documentation displays similarly, though it doesn't show an example for GAS. Here's the Node.js example (it didn't make a difference whether or not I include trailing commas in the payload object and the nested object or whether I quoted the key names):
const stripe = require('stripe')('sk_test_51PoHIuFYLeju0XxwXR4z3EHW3oaSqtTlD2Kr2xvUPRzhORHsjssb35rLfw1kbdQsVYdkHiYZ7vmKgWrXic30Y2XN00bvs1FZaO');
const customer = await stripe.customers.update(
'cus_NffrFeUfNV2Hib',
{
metadata: {
order_id: '6735',
},
}
);
I tried using JSON.stringify()
on address
. I get the same error message, and it shows in the log like this:
{
"address": "{"country":"US"}"
}
I also tried using JSON.stringify()
on the entire payload in post()
. In this case, I get a response of 200 and can successfully return the response, but the customer doesn't get updated.
I also tried sending the address
as a Blob, but I don't really know how to use those. The error was that it got the wrong format (application/x-www-form-urlencoded
is what is expected, and this appears to be what UrlFetchApp.fetch()
defaults to).
When I saw your provided URL, I found the following curl command.
curl https://api.stripe.com/v1/customers/cus_NffrFeUfNV2Hib \
-u "sk_test_09l3shTSTKHYCzzZZsiLl2vA:" \
-d "metadata[order_id]"=6735
In the case of the property including objects, it seems that "metadata[order_id]"=6735
is used. In the case of
{
address: {
country: 'US',
state: 'CA',
city: 'City',
postal_code: '00000',
line1: 'Line 1',
line2: 'Line 2'
}
}
how about the following modification?
async function postCustomer(id, args) {
const data = await postStripeData(id, args, ['customers'])
return data
}
async function postStripeData(id, args, path1, path2) {
const fullPath = makeFullPath(id, path1, path2)
const data = await post(getStripeApiUrl() + fullPath + '?key=' + getKey(), args)
return data
}
async function post(url, args) {
const response = await UrlFetchApp.fetch(url, {
'method': 'post',
'payload': args
})
if (await response.getResponseCode() === 200) {
const data = await JSON.parse(response)
return data
} else {
throw new Error("I couldn't post to this url: " + url)
}
}
In the current stage, Google Apps Script works with synchronous processes.
function postCustomer(id, args) {
const data = postStripeData(id, args, ['customers'])
return data
}
function postStripeData(id, args, path1, path2) {
const fullPath = makeFullPath(id, path1, path2)
const data = post(getStripeApiUrl() + fullPath + '?key=' + getKey(), args)
return data
}
function post(url, args) {
// --- I added the below script.
args = Object.fromEntries(Object.entries(args).flatMap(([k1, v1]) =>
typeof v1 == "object" ? Object.entries(v1).map(([k2, v2]) => [`${k1}[${k2}]`, v2]) : [[k1, v1]]
));
// ---
const response = UrlFetchApp.fetch(url, {
'method': 'post',
'payload': args
})
if (response.getResponseCode() === 200) {
const data = JSON.parse(response)
return data
} else {
throw new Error("I couldn't post to this url: " + url)
}
}
By this, when the following script is run,
const data = postCustomer(customerId, {
address: {
country: 'US',
state: 'CA',
city: 'City',
postal_code: '00000',
line1: 'Line 1',
line2: 'Line 2'
}
});
The payload is as follows.
{
"address[country]": "US",
"address[state]": "CA",
"address[city]": "City",
"address[postal_code]": "00000",
"address[line1]": "Line 1",
"address[line2]": "Line 2"
}
doGet
and doPost
, when you modify the script, please reflect the latest script to the Web Apps. Please be careful about this.