#CMarabate
1 messages · Page 1 of 1 (latest)
Um I am not familiar with Netlify. But if you have questions related to Stripe API that you can confirm from your Dashboard https://dashboard.stripe.com/test/logs, I am happy to help
Sign in to the Stripe Dashboard to manage business payments and operations in your account. Manage payments and refunds, respond to disputes and more.
Netlify Functions are essentially API calls, I have a function that I have a Stripe Webhook Endpoint pointed at and I was having a ton of issues trying to get it to work. If I showed you the code for the function do you think you would be able to take a look and see what I am doing wrong?
So it's to accept Stripe Webhook event?
Yeah the customer.subscription.updated event
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
const ManagementClient = require('auth0').ManagementClient;
const management = new ManagementClient({
domain: process.env.AUTH0_DOMAIN,
clientId: process.env.AUTH0_CLIENT_ID,
clientSecret: process.env.AUTH0_CLIENT_SECRET,
scope: 'read:users update:users',
});
// Get role name from product ID
function getRoleFromPlan(planId) {
switch (planId) {
case 'price_1MfslxFUDFxTEzZGP1NQSmEX':
return 'Test Member';
case 'price_1LAIw9FUDFxTEzZGYzM290b6':
return 'Common Member';
case 'price_1MecZKFUDFxTEzZGPhLWWGmC': // monthly
return 'Uncommon Member (Monthly)';
case 'price_1MecZKFUDFxTEzZGfAk1x67b': // yearly
return 'Uncommon Member (Yearly)';
case 'price_1MebTnFUDFxTEzZG0jNlXiUU': // monthly
return 'Rare Member (Monthly)';
case 'price_1MebTnFUDFxTEzZGXvCaprzh': // yearly
return 'Rare Member (Yearly)';
case 'price_1MecgCFUDFxTEzZG90uvzJIC': // monthly
return 'Epic Member (Monthly)';
case 'price_1MechKFUDFxTEzZGbOz5v5aX': // yearly
return 'Epic Member (Yearly)';
case 'price_1LAJ0tFUDFxTEzZGaNqoqBqi': // monthly
return 'Legendary Member (Monthly)';
case 'price_1MbqiVFUDFxTEzZGo87RhTHT': // yearly
return 'Legendary Member (Yearly)';
default:
return null;
}
}
exports.handler = async (event, context) => {
try {
const { subscriptionId, selectedProduct } = JSON.parse(event.body);
if (event.type === 'customer.subscription.updated') {
const data = JSON.parse(event.body);
const subscriptionId = data.data.object.id;
const subscription = await stripe.subscriptions.retrieve(subscriptionId);
const customer = await stripe.customers.retrieve(subscription.customer);
const userId = customer.metadata.auth0_user_id;
const user = await management.getUser({ id: userId });
const roles = user.app_metadata.roles || [];
const roleName = getRoleFromPlan(selectedProduct.id);
if (!roleName) {
console.error(`Error: Invalid product ID ${selectedProduct}`);
return { statusCode: 400, body: `Invalid product ID ${selectedProduct}` };
}
const updatedRoles = roles.filter(role => role !== roleName);
await management.updateUser({ id: userId }, { app_metadata: { roles: updatedRoles } });
await stripe.subscriptions.update(subscriptionId, { cancel_at_period_end: true });
console.log(`Subscription canceled successfully for user ${userId}`);
return { statusCode: 200 };
} else {
console.error(`Error: Invalid event type ${event.type}`);
return { statusCode: 400, body: `Invalid event type ${event.type}` };
}
} catch (error) {
console.error(error);
return { statusCode: 500, body: error.message };
}
};
let handleUnsubscribe: ((user: { subscriptions: any[] }) => Promise<void>) | ((arg0: any) => void);
handleUnsubscribe = async (user: { app_metadata: {} }) => {
const userRoles = user['https://raidchamps.com/app_metadata'].roles;
console.log(`userRoles`, userRoles);
console.log(`userRoles[0]`, userRoles[0]);
if (!userRoles || userRoles.length === 0) {
// User is not subscribed to any plan
return;
}
setLoading(true);
// Get the subscription ID of the first active subscription
const subscriptionId = getPlanFromRole(userRoles[0]);
console.log(`subscriptionId`, subscriptionId);
if (!subscriptionId) {
// User does not have any active subscription
return;
}
// Cancel the subscription in Stripe
const response = await fetch('/.netlify/functions/handle-unsubscribe', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
event: event,
}),
});
if (!response.ok) {
// Failed to cancel the subscription
console.error('Failed to cancel the subscription:', response);
return;
}
setLoading(false);
};
...
<button onClick={() => handleUnsubscribe(user)}>{loading ? 'Loading...' : 'Unsubscribe'}</button>
That should be the full picture of what I am trying and what I am experiencing.
And this is not my first time using a Stripe Webhook like this, I have one setup for the Subscribe/Upgrade button that works fine but that one uses the invoice.paid event.
It's unclear to me where it is a Stripe webhook handler. I see handle-unsubscribe as a Netlify backend endpoint? And your request to that endpoint is failed
So we would need the log of that logic
What logic? a log from the webhook? because it never gets triggered so there are no logs.
And this is all the log for the function tells me...
/.netlify/functions/handle-unsubscribe
Request to this endpoint failed, correct? I see it in your screenshot
Yeah
Well it triggerd the function but the webhook never ran
Because of the invalid event type error im guessing
I am confused. That supposes to be your own fucntion, not the webhook handler
Webhook handler is the program you use to receive webhook from Stripe (ie. we send events to you), while this is a request from your frontend to your backend
It is my own function but the webhook endpoint is pointing to it
Are you saying I need another function that I call that will handle the webhook somehow?
Why is this so freaking confusing. All I want is a way to let my users unsubscribe lol.
Been going at it for over a week and getting nowhere.
Am I going about it all wrong is there a simpler way to handle this?
It is my own function but the webhook endpoint is pointing to it
This part I don't get. Webhook endpoint should be a separated function than your backend <> frontend flow
I clearly do not understand webhooks but that is exactly what I am doing with this webhook endpoint and it works great...
If you only need to let your customer unsubscribe, you don't need webhook AFAIK. Webhook is when you want to response to some events coming from Stripe
Okay cool I knew I was doing something way wrong. So how should I allow customers to unsubscribe?
When you handle the request to /.netlify/functions/handle-unsubscribe simpy call the Cancel Subscription API https://stripe.com/docs/api/subscriptions/cancel
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 so exactly what I am doing except it does not need a webhook endpoint?
Yep
Doesn't really explain why it isn't working but that is good to know.
Just by looking at the error, I think your logic stopped here
const { subscriptionId, selectedProduct } = JSON.parse(event.body);
if (event.type === 'customer.subscription.updated') {
...
So probably you want to console.log this event
Okay thanks!