#roda_api
1 messages ยท Page 1 of 1 (latest)
๐ Welcome to your new thread!
โฒ๏ธ We'll be here soon! Typically we respond in a few minutes, but sometimes we might take a bit longer if the server is busy or if you have a particularly tricky question.
โฑ๏ธ We close idle threads, which makes them read-only. Once a thread is closed it won't be reopened, but you can always start a new thread if you have another question.
๐ This thread will always be available, even after it's closed. You can find it again using Discord's search, or you can save this link: https://discord.com/channels/841573134531821608/1351595494807179316
๐ Have more to share? Add more details, code, screenshots, videos, etc. below.
Hi! Email is not globally unique at Stripe, so this will happen. Your best bet is to store the [ Customer ID, email ] relationship so you can pull the correct customer given an email.
Well, the problem is that if a new subscription is made, there will be a new relation, or better, two possible active relations.
I also sent a request to Stripe, because there is a issue involved with this, because when this happens the old customer portal becames inacessible and could have an active subscription in it. The current behaviour retrieves the most recent customer_id created from a certain email.
But about the API, there isn't any endpoint to retrieve all subscriptions for a certain email right?
Actually there is: https://docs.stripe.com/api/customers/search
Complete reference documentation for the Stripe API. Includes code snippets and examples for our Python, Java, PHP, Node.js, Go, Ruby, and .NET libraries.
Hmm, that's the customer search ๐
I was talking about retrieve all subscriptions
You can't search Subscription by email so you'd have to search Customer first, and then get their Subscriptions.
Well, I will keep the Promise.all to query all the customer_ids for the same email address then. But should be option to query all for the same email address, or a way to keep the same customer_id with the no code integrations.
const customerIds = await stripe_1.resolveCustomerIdFromEmail(customer.email);
// Collect all subscriptions from all customer IDs
const subscriptions = await Promise.all(
customerIds.map(async (cId) => {
return await stripe_1.findSubscriptionsFromCustomerId(cId);
})
);
const allSubscriptions = subscriptions.flat();
Currently doing this way, so probably the only way to do it in Code if there isn't any filter to get it all for the same email address.
Those function calls on stripe_1 are not part of the Stripe Node SDK so I'm not sure what they do.
const resolveCustomerIdFromEmail = async (email) => {
let matchingCustomers = [];
const response = await fetch(`https://api.stripe.com/v1/customers/search?query=email:'${email}'`, {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.STRIPE_API_KEY}`
}
});
const responseData = await response.json();
matchingCustomers = responseData.data || [];
}
// Return an array of customer IDs
return matchingCustomers.map(customer => customer.id).filter(Boolean);
}
exports.resolveCustomerIdFromEmail = resolveCustomerIdFromEmail;
/**
* Gets all the Stripe subscriptions from a given customer ID
*/
const findSubscriptionsFromCustomerId = async (customerId) => {
const response = await fetch(`https://api.stripe.com/v1/subscriptions?customer=${customerId}`, {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.STRIPE_API_KEY}`
}
});
const responseData = await response.json();
return responseData.data || [];
}
exports.findSubscriptionsFromCustomerId = findSubscriptionsFromCustomerId;
Just searching form the email, and then, the subscriptions for the customerId.
I think with the current endpoints available this is the only way
Why are you not using the Stripe Node SDK?
When I did it this functions two years ago I didn't know about it, was thinking of making the switch
Give me a sec.
Ok, here you go:
You can replace your two-step, many-request process with a single API request:
// const resolveCustomerIdFromEmail = async (email) => {
const getSubscriptionsForEmail = async (email) => {
let subscriptions = [];
const response = await fetch(
`https://api.stripe.com/v1/customers/search?query=email:'${email}'&expand[]=data.subscriptions&expand[]=data.subscriptions.data.customer`,
{
method: "GET",
headers: {
Authorization: `Bearer ${process.env.STRIPE_API_KEY}`,
},
}
);
const customers = await response.json();
return customers.data
.map((customer) => customer.subscriptions.data)
.flat()
.filter(Boolean);
};
And now I must away. โ
Wow awesome!
(My colleague solanum is however here to help if you need anything further. ๐ )
Thank you! With Node SDK the search is similar?
Yup.
You have to initialize stripe but this what it'd look like.
const getSubscriptionsForEmail = async (email) => {
const customers = await stripe.customers.search({
query: `email:'${email}'`,
expand: ["data.subscriptions"],
});
return customers.data
.map((customer) => customer.subscriptions.data)
.flat()
.filter(Boolean);
};
Got it, thanks timebox! Go to your well deserved day off :P >.<
If you also want to expand the Customer object expanded on the Subscription (i.e. subscrtiption.customer, you can use data.subscriptions.data.customer as the expand.
Will do. Cheers. ๐
Hey solanum, I have a question for you, should I add a sleep cycle to avoid rate limiting on this? And if so how should I do this implementation about the timing?
ooo hello! just noticed the followup, gimme just a second
what context are you doing this in? are you writing production code? if so you want retries with exponential backoff
our docs have a good guide on this:
https://docs.stripe.com/rate-limits#handling-limiting-gracefully
I do have an open source solution to sync roles with subscriptions in stripe, and I'm currently checking with some hour intervals (I know I can do this with webhooks now, but for now I'll stay with intervals checks)
And when the interval checks are made I loop all the customers linked with discord to make sure every single one has a subscription active, if it' isn't i revoke roles
ooo yep, i will say that yes webhooks are greatly preferred here. but yeah i would just implement retries as described in the article above
obviously just adding an arbitrary sleep will reduce chances of 429s, but retries with exponential backoff will ensure you don't miss anything
But should I add a sleep of fractions of seconds when looping each customer to avoid the rate limit, or?
sure! again that will help, but retries are more important
I started my version of this bot two years ago and I was doing
const sleep = async (ms) => await new Promise(resolve => setTimeout(resolve, ms));
await sleep(2000);
Maybe I don't need 2 full seconds right
๐
yeah that's a lot hahahaha
Awesome! Maybe you have any recommendation value? ๐
Awesome I didn't know about retries, oopsie
the limit is this: Live mode: 100 read operations and 100 write operations
Yea, that I know, two years ago my programming was not that good, and I always went for a safer safer extra safer route ๐คฃ
so even 1/100th of a second will guarantee you don't hit the limit (unless your application is making other calls at the same time)