#paulc7053_webhooks

1 messages ยท Page 1 of 1 (latest)

wary tigerBOT
#

๐Ÿ‘‹ 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/1279085561117675713

๐Ÿ“ Have more to share? Add more details, code, screenshots, videos, etc. below.

jagged timberBOT
gloomy swan
#

Hello!

wind comet
#

Wait, that's for the first Invoice isn't it?

gloomy swan
#

yes

#

the trial one I believe

wind comet
#

It looks like the Invoice is still in a draft state, so the payment attempt hasn't happened yet which is why you haven't seen an invoice.finalized or payment related Events for it.

gloomy swan
#

why is that?

#

the subscription appears as active in the dashboard

wind comet
#

I'm not sure yet

gloomy swan
#

Alrighty

#

can you please let me know when you figure it

#

Any updates ? @wind comet

wind comet
#

No, I'm not spotting why this didn't progress.

#

Are you able to consistently reproduce this behavior?

gloomy swan
#

yes...

#

tried it with multiple trial subs

#

and double-triple checked the webhook listens to the invoice events

wind comet
#

Can you advance the billing clock like another hour? It's really close to the finalization time for the Invoice and I'm wondering if you've just not advanced past that yet. My test Invoice finalized fine.

gloomy swan
#

sure

#

same thing...

#

here's an eventId evt_1PtWGkJ4ILijjURSlDJaoZH9

wind comet
#

Can you provide the ID of the Invoice that you're not seeing progress states?

gloomy swan
#

yes

#

also I tried on another subscripion, and this one seems to give out payment vailed evt_1PtWHpJ4ILijjURSemijvujw

#

This is the invoiceId in draft in_1PtWGjJ4ILijjURSxwBKCz65

wind comet
#

Ah, okay, you created a new Billing Clock. Can you now advance that clock another hour?

For Invoices that aren't the first for a Subscription, the Invoices wait about an hour after they are created before they are finalized. It looks like your new billing clock is currently frozen in that hour block.

gloomy swan
#

yes, i thought the clock actually 'keeps ticking'

wind comet
#

Nope, test clocks freeze at the specified times

gloomy swan
#

ill retry say 3 hours after the free trial cutoff

#

is that ok?

wind comet
#

Yeah that should do it

#

Like looking at the most recent Invoice you shared, I see the following:
creation time (relative to the test clock) - 2024-09-02 13:39:06
test clock's current time - 2024-09-02 14:30:00

I think if that clock were to be advanced about 15 minutes you'd see the Invoice finalize and attempt payment. (which will fail because there is no default payment method to be used)

gloomy swan
#

(which will fail because there is no default payment method to be used) why is that?

gloomy swan
#

now im trying to understand why does it fail? This is how I handle it: `
const handlePaymentButtonClick = async (e) => {
e.preventDefault();
if (!stripe || !elements) {
return;
};

    setIsLoading(true);

    const { error: submitError } = await elements.submit();
    if (submitError) {
        setStripeError(submitError.message);
        return;
    };

    // create the customer
    const stripeCustomerIdRes = await fetch('/api/stripe/findOrCreateCustomer', {
        method: 'post',
        headers: {
            'Content-Type': 'application/json',
        },
        body: JSON.stringify({
            billingEmail,

            country,
            language,

            currency,
            totalPrice
        }),
    });
    const stripeCustomerId = (await stripeCustomerIdRes.json()).stripeCustomerId;

    // create the subscription
    const subscriptionRes = await fetch('/api/stripe/createSubscription', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
        },
        body: JSON.stringify({
            stripeCustomerId,

            billingEmail,

            country,
            language,

            currency,
            totalPrice
        }),
    });
    const clientSecret = (await subscriptionRes.json()).clientSecret;


    console.log({clientSecret})
    if (!clientSecret) {
        console.log("No immediate payment required due to trial period.");

        router.push(returnUrl); // Example redirect
        return;
    };`
#

and this is how I create the subscription :"

const stripe = new Stripe(
process.env.NODE_ENV === 'development'
? process.env.STRIPE_TEST_API_KEY
: process.env.STRIPE_PRODUCTION_API_KEY
);

export default async function createSubscription(req, res) {
const {
stripeCustomerId,
...
} = req.body;

const metadata = {
    stripeCustomerId,

...
};

//create a dynamic product
const product = await stripe.products.create({
    name: `${currency.toUpperCase()}${totalPrice} Subscription`,
});
console.log("Stripe product has been created.");

//create the subscription
const subscription = await stripe.subscriptions.create({
    customer: stripeCustomerId,
    items: [{
        price_data: {
            currency: currency.toLowerCase(),
            product: product.id,
            unit_amount: Math.round(totalPrice * 100),
            recurring: { interval: 'year' },
        }
    }],
    payment_behavior: 'default_incomplete',
    payment_settings: { save_default_payment_method: 'on_subscription' },
    expand: ['latest_invoice.payment_intent'],
    metadata: metadata,
    trial_period_days: 3
});
console.log("Stripe subscription has been created.");

const clientSecret = subscription.latest_invoice?.payment_intent?.client_secret || null;

res.send({
    subscriptionId: subscription.id,
    clientSecret: clientSecret,
});

};" (the clientSecret is always null)

wind comet
#

It fails because the a default payment method isn't set up, so the Subscription doesn't have anything to charge for the Invoice's payment.

You either need to set a default payment method on the Subscription:
https://docs.stripe.com/api/subscriptions/object#subscription_object-default_payment_method
Currently your flow will do this when the first payment succeeds since you're setting
payment_settings: { save_default_payment_method: 'on_subscription' },
but no payment happens due to the Subscription starting with a free trial, so there isn't a payment method to save.

Or you can set a default payment method on the Customer object, which will be used for all Subscriptions that don't have their own default payment method set:
https://docs.stripe.com/api/customers/update#update_customer-invoice_settings-default_payment_method

gloomy swan
#

if I understand it correctly, then ai just need to replace it with 'default_source'?

wind comet
#

I don't know what you mean by that, but it doesn't sound right.

gloomy swan
#

I have looked at your links, yet it's not entirely clear to me what value should the payment_settings have when creating the subscription

wind comet
#

It has nothing to do with payment_settings, you need to collect payment method details from your customer. Do you want to collect those when the Subscription is started in a trail phase, or do you want to wait for the trail to end before collecting those details?

gloomy swan
#

yes, in trial phase already

#

i use the card element/apple pay/gpay

wind comet
#

Then instead of trying to get the intent from the first Invoice, which will be null for a Subscription starting with a trial period, you'll want to get the ID of the Setup Intent that the Subscription creates. It's stored in the pending_setup_intent field:
https://docs.stripe.com/api/subscriptions/object#subscription_object-pending_setup_intent

Then you can use the client secret from that intent to use Elements to collect payment method details.

gloomy swan
#

Thanks so much!

#

right now I have to go, will look into that as soon as Im back on desktop

#

Thanks again!