#the-soundbridge-team_subscriptions-schedules

1 messages ยท Page 1 of 1 (latest)

chilly horizonBOT
#

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

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

quasi marlin
#

Hi, where exactly are you getting an issue?

#

Can you share more details please?

flint geyser
#

Yes

chilly horizonBOT
flint geyser
#

So I've created a second monthly re-occuring price for $0.99/Month on the our Everything Bundle (Monthly) subscription like so on the dashboard.

#

Figuring out the secret handshake for getting client_secret & subscriptonId for the frontend component is unclear

fallen rock
#

๐Ÿ‘‹ stepping in here as pgskc needs to step away

flint geyser
#

hi

#

So my company is trying to do "Start for $0.99, Continue at $9.99/Month"

#

So for first month users can start for $0.99, then it should automically do $9.99/Month

#

I'm getting a try/catch error on my current implementation

fallen rock
#

You are hitting a specific error?

flint geyser
#

Failed to retrieve payment intent

#

that's the try/catch error ^^^

fallen rock
#

Okay and have you added logs between each step of your code here?

#

Have you checked that latestInvoice is the object you expect?

flint geyser
fallen rock
#

Ah okay

#

So yeah because you are using a Subscription Schedule the Invoice doesn't finalize immediately on Subscription creation

#

If you look at that Invoice in your Dashboard you will see it is in draft

#

So you need to finalize it first (or wait the 1 hour for finalization) to be able to access the PaymentIntent

flint geyser
#

I'm ChatGPTin' this man, the docs are HUGE ๐Ÿ˜…

#

ok, so because I just made this extra price, that's why I'm getting this?

fallen rock
#

No because you use a Subscription Schedule

#

As opposed to creating the Subscription directly

flint geyser
#

ok, so I guess this implementation just won't work correct?

#

Is there anyway to do simply a trial month on a normal subscription?

#

PayPal does that so easily

#

Or do you have to do a schedule like this?

fallen rock
#

I'm not sure what you mean by "it won't work correct"?

#

It works just fine.

#

You just need to finalize the Invoice

flint geyser
#

Just so this is clear

#

We're using the React Component on the frontend

#

For a normal subscription it pulls up like so ^^^

#

Are you saying I need one more line of code and from this I can get the client_secret and subscriptionId?

fallen rock
#

Yes. You need the client secret to render Payment Element. To get the client secret you need the Invoice to be finalized.

#

So after creating the Subscription Schedule you need to finalize the Invoice that is generated by the new Subscription

flint geyser
#

ok so something like this: const invoice = await stripe.invoices.finalizeInvoice(fullSub.latest_invoice.id);

fallen rock
#

Yes

flint geyser
#

ok I see a payment_intent string code now, but no object with client_secret

fallen rock
#

Are you expanding the payment_intent?

flint geyser
#

const invoice = await stripe.invoices.finalizeInvoice(latestInvoice?.id, { expand: ['payment_intent'] }); like this?

fallen rock
#

Yes

flint geyser
#

ok, I think we got it!

#

WOW

#

lots of low-level stuff ๐Ÿ˜…

#

the React component is now firing!

#

I'm extending everything properly towards the end here and not doing anything redunant right?

fallen rock
#

You could remove the Subscription retrieval request and expand subscription.latest_invoice in your Subscription Schedule creation request

#

Otherwise lgtm

flint geyser
#

ok I can add {expand: ['subscription.latest_invoice.payment_intent']} as a second parameter object on stripe.subscriptionSchedules.create()?

fallen rock
#

Yes

flint geyser
#

Will the webhook be the same as normal subscription or is the payment type different?

#

On normal subscription we do this

fallen rock
#

It is the same

#

As there is still just a normal underlying Subscription created

flint geyser
#

"object": "list",
"data": [
{
"id": "sli_10047dCrnLkr8CZ739788f16",
"object": "line_item",
"amount": 99,
"amount_excluding_tax": 99,
"currency": "usd",
"description": "1 ร— Everything Bundle (Monthly) (at $0.99 / month)",
"discount_amounts": [],
"discountable": true,
"discounts": [],
"invoice": "in_1RtXHtCrnLkr8CZ7rGDzUMdD",
"livemode": true,
"metadata": {},
"parent": {
"invoice_item_details": null,
"subscription_item_details": {
"invoice_item": null,
"proration": false,
"proration_details": {
"credited_items": null
},
"subscription": "sub_1RtXHsCrnLkr8CZ7XoGaIWya",
"subscription_item": "si_SpBfpC31QvffiX"
},
"type": "subscription_item_details"
}, the meta data is empty

#

we need to set a customID here

fallen rock
#

For the Subscription?

#

Or what?

#

Can you be more specific?

flint geyser
#

const schedule = await stripe.subscriptionSchedules.create({
customer: customer.id,
start_date: 'now',
end_behavior: 'release',
metadata: { custom_id },
phases: [
{
items: [
{
price: introPriceId, // $0.99 intro
quantity: 1,
},
],
iterations: 1, // One billing cycle only
},
{
items: [
{
price: priceId, // $9.99 normal monthly
quantity: 1,
},
],
},
],
});

#

Im setting a custom_id like so

#

is this correct?

fallen rock
#

Yeah that would set metadata on the Subscription Schedule object

#

But that won't get carried down to the Subscription. You would need to update the Subscription with that metadata after it is created.

flint geyser
#

wtf

#

how do I do that?

fallen rock
#

You can do that immediately in a request after you create the Schedule

chilly horizonBOT
flint geyser
#

if (canGetIntroPricing(userData) && productID === subscriptionProducts[0]) {
const introPriceId = process.env.STRIPE_INTRO_MONTHLY_SUBSCRIPTION_PRICE_ID;

    if (!introPriceId) {
      return NextResponse.json({ message: 'Missing intro price ID' }, { status: 500 });
    }

    const schedule = await stripe.subscriptionSchedules.create({
      customer: customer.id,
      start_date: 'now',
      end_behavior: 'release',
      metadata: { custom_id },
      phases: [
        {
          items: [
            {
              price: introPriceId, // $0.99 intro
              quantity: 1,
            },
          ],
          iterations: 1, // One billing cycle only
        },
        {
          items: [
            {
              price: priceId, // $9.99 normal monthly
              quantity: 1,
            },
          ],
        },
      ],
    });

    // Retrieve the underlying subscription to get payment intent
    const fullSub: any = await stripe.subscriptions.retrieve(
    schedule.subscription as string,
    { expand: ['latest_invoice'] },
    );

    const latestInvoice: any = fullSub.latest_invoice as InvoiceWithPaymentIntent;

    console.log('latestInvoice', latestInvoice);

    await stripe.subscriptions.update(
      latestInvoice.subscription,
      {
        metadata: {
          custom_id,
        },
      },
    );

    const invoice: any = await stripe.invoices.finalizeInvoice(latestInvoice?.id, { expand: ['payment_intent'] });

    // console.log('INVOICE', invoice);

    if (!invoice.payment_intent?.client_secret) {
      throw new Error('Failed to retrieve payment intent');
    }

    return NextResponse.json({
      client_secret: invoice.payment_intent.client_secret,
      subscriptionId: fullSub.id,
    });
  } ok like this>?
fallen rock
#

Instead of just dropping a bunch of code I would recommend testing it out!

#

From a glance I think it looks good!

flint geyser
#

Yes sorry, seems to be working now. I removed the Metadata from the Subscription schedule creation too. Can you send an example of simplified extend to reduce my code?

#

I tried adding an second extends object to the creation function, but that function doesn't take a second parameter

dawn vault
#

๐Ÿ‘‹ Taking over this thread

#

I tried adding an second extends object to the creation function, but that function doesn't take a second parameter
Which second extend are you referring to? What function doesn't take a second parameter? Could you share a specific line of code that you're facing the issue?

flint geyser
#

last guy said "You could remove the Subscription retrieval request and expand subscription.latest_invoice in your Subscription Schedule creation request
Otherwise lgtm" when I asked him if I'm doing anything extra or redunant

dawn vault
#

I don't see any change in your code from my teammate's advice. I could still see stripe.subscriptions.retrieve is still present in your code. The expand: ['subscription.latest_invoice'] can be placed at stripe.subscriptionSchedules.create() to minimise the additional call to stripe.subscriptions.retrieve.

chilly horizonBOT