#Village-webhook-event

1 messages ยท Page 1 of 1 (latest)

slow barn
#

Hi! What are you trying to do?

#

The best way mostly is just to test.... but happy to talk to you about what might work for your use-case.

potent canyon
#

I am using subscriptions (mostly, with one time setup fees). I do not pre-create customers. I am only using $checkout_session = \Stripe\Checkout\Session::create($checkout_obj); to send a customer to the payment page.

#

All i want to know is when they have made a successful payment, the payment was approved, and i need to allow them access on my site. I would need to get back some metadata to know what level of service they paid for.

#

One of the first issues i have noticed with the 15 events, while im looking to be able to just focus on one event, not a single event contained all the info i needed. Some of the events had the metadata passed in the $checkout_session and others had the metadata saved in dashboard product prices.

#

Or is it possible to rely on just a single event always firing?

slow barn
#

You likely just want to rely on checkout.session.completed and then you can retrieve other relevant objects that you need from there for metadata if you need to.

potent canyon
#

The follow up to this is also going to be when they renew the subscription, in 30 days when they get auto charged, what event is going to fire for that so i know to extend their service? Is the the same event as their first time? I can not find a way in testing to mimic a renewal to test for events.

slow barn
#

On renewal you will want to listen for invoice.paid

#

Have you used test clocks before?

#

These are a great way to simulate a renewal

potent canyon
#

So can i safely rely on only checkout.session.completed anytime i collect a payment from a customer? Whether new subscription signup or renewal?

#

No, i have not seen test-clocks, i will look at that.

slow barn
#

Yep checkout.session.completed will mean that a Subscription was successfully started here

potent canyon
#

So on auto-subscription-renewals the checkout.session.completed event isn't fired?

slow barn
#

No, checkout.session.completed will only fire when a Checkout Session is completed due to your Customer being on-session and completing that Checkout Session

#

You will need separate events for renewals

#

You could just listen for invoice.paid and then back track to the Subscription from there if you want.

#

But I would recommend using checkout.session.completed for the initial payment

potent canyon
#

I will dig into ^^all that^^ but im sure i will have follow up questions later (> 1hr). Should i post back to this thread or start a new thread later for follow up?

slow barn
#

I'll leave this open for a bit, but feel free to just post in the main channel and ask someone to re-open your thread if this has been archived before you come back!

potent canyon
#

When working with subscriptions, you can set monthly, 6 months, yearly, etc. Does stripe always advance the renewal to the following month keeping lockstep with the date? Like a monthly subscription started on Jan 25th will always renew on the 25th of each month vs exact 30 days? And how does it handle shorter months?

If a sub starts Jan 31st what happens in Feb? And if it (logically) shortens to Feb 28th, then in March does it stay at 28th or go back to 31st when it can?

rich turret
#

You should always avoid trying to set the renewal date to the last day of the month. It will shorten to the 28th and not go back. It is best practice to use the 1st rather than the last day of the month.

#

If you specify your recurring interval to 'monthly' you will get an invoice every 1st, 5th, or whichever date (that exists in all months) you select.

potent canyon
#

I missed this feature, i created products and on the price set the price to recurring. I did not see anything about setting a billing date/cycle.

rich turret
potent canyon
#

Based on just setting a recurring price on a product, what is the default renew behavior?

rich turret
potent canyon
#

If im understanding the docs you linked, that is for creating products/price via the API? What about when i have created my products/prices in the dashboard? I didn't see anything in the dashboard related to billing cycles. What am i missing?

rich turret
#

Since this Discord server is developer focused, we tend to reach for API solutions first. Let me check on DB options

#

Okay, that's a price and I think the default is an interval_count of 1.

#

If you are creating a subscription in the dashboard you will see an option to "start billing cycle on".

potent canyon
#

I have not created subscriptions, just products with a recurring price. On my Dashboard > Payments > Subscriptions it just shows (test) customers that have been auto created by checkouts. If i click on one of those customers it shows Current Period for example "Mar 22 to Apr 22". I assume that is the billing cycle?

rich turret
#

Yup. If you are tryiing to create these via the Dashboard you need to first select a Customer. Then you can create a subscription for that customer in the "Actions" menu

#

Wait... hold on sec. Current period is always forward looking, billing period is always the last completed billing cycle

potent canyon
#

Im not trying to create anything, im just doing bare minimum. Selling subscriptions, only making products with prices as "service levels".

rich turret
#

Selling subscriptions
That means you'll need to create the subscription object for a customer

potent canyon
#

I think this happens automatically in the background.

rich turret
#

How, what do you do?

#

How are you interacting with your customers?

potent canyon
#

I only create a $checkout_session and set 'price' => 'price_xxxxxxxx' and forward them to the payment page.

#

They make a payment, i get the hook events.

#

In the dashboard i see a customer was created for them

rich turret
#

But it's a subset that does not include billing_cycle_anchor

potent canyon
#

What is default behavior since i didn't? For example, i just made a testing clock, added a test customer. In the dashboard it shows current period Mar 22 to Apr 22. I advanced the clock to Apr 24th, it fired off invoice.created customer.subscription.updated and setup_intent.created. It doesn't look like they were charged for another month as in the dashboard it is showing...

#

What date would they actually get billed on?

#

But it also shows

rich turret
#

Invoices generated like this have a 1 hour period where they remain in draft status so you have an opportunity to modify them. I'm not sure how that behaves with Test Clocks as I haven't had a chance to play with them.

potent canyon
#

Which confuses me, i thought they would have been billed on Apr 23rd, but they weren't. i advanced the clock one more day to 24th, it made the drafts, looks like they still haven't been billed, while at the same time saying next billing is now may 23rd.

#

Okay, i will try advancing the test clock just a couple of hours, brb...

rich turret
#

AFAIK, test clocks will only advance the time but it won't take any actions for you. So if your configuration requires that you manually confirm the invoice advancing the test clock will not perform these actions

potent canyon
#

Okay, still on Apr 24th, advancing a few hours it fired off payment_intent.succeeded charge.succeeded customer.updated payment_intent.created invoice.updated invoice.paid invoice.payment_succeeded and invoice.finalized

rich turret
#

Yeah, auto-advancing and auto-billing a subscription does a lot of events

potent canyon
#

Back to big picture, im just trying to figure out which events i should watch for and which others are noise i can ignore. And i was also curious on default behavior of renewals so im "advertising" correctly to the customer when their membership ends or gets rebilled. I guess i will just need to setup a test clock for jan 31st and see ๐Ÿ™‚

#

Id prefer to only have to listen for and worry about one event that will just always tell me when a payment was paid. Then i can credit that customer on my side.

#

Whether new started sub or renewal.

rich turret
#

Well you might want to listen for some failures as well

potent canyon
#

Failures in what way? My strategy was just setting a service end date in my system. When they make a successful payment, i get the hook event and i extend their date. If they don't pay, payment fails, nothing happens, date comes and goes and their service is expired.

rich turret
#

If their payment method gets declined for example

potent canyon
#

I dont need to "take away" from them for failed payments. Just let the date run out.

#

What don't i know?

rich turret
#

But as for simple webhooks to listen to, invoice.paid will include the invoice object which also has a billing_reason attribute. This will tell you whether its for a new subscription or a renewal, if that matters for your integration,
https://stripe.com/docs/api/invoices/object#invoice_object-billing_reason

potent canyon
#

Okay, i will go over this material you have given me so far. Thank you.

rich turret
#

As for the metadata question. You can pass metadata to the subscription when creating the Checkout session. But I'm not sure if that goes all the way down to the invoice.

#

However, you can get the related subscription from the invoice and retrieve the metadata that way.

potent canyon
#

I tested that already, the metadata i passed to the checkout session was only retained in checkout.session.completed not even in the charge.succeeded or invoice.paid

rich turret
#

No, not cheeckout.metadata, you need to use checkout.subscription_data.metadata

#

All the nesting of attributes can make this tricky but it allows our users to build some flexible integrations

potent canyon
#

My issue is im not manually creating subscriptions, id have to find a way to go backwards, look up what subscription was created in the act of accepting recurring payment, then attach metadata. Right?

rich turret
#

You are manually creating subscriptions, through a Checkout session configured for recurring payments. You can either pass along the metadata to the subscription when you create the Checkout session or you can take your approach, which seems a bit more cumbersome to me.

potent canyon
#

I agree, im not voting for that method. I didn't see where i can pass subscription related values to the checkout session.

rich turret
#

I just told you, twice

potent canyon
#

Is there a doc page (link) that tells me all possible key:values that can be passed in creating a checkout session?

rich turret
#

Yup, the same one I keep linking to

potent canyon
#

im re-reading that link

rich turret
#

If you expand all the docs it gets really verbose. So I can understand not getting it all right away

potent canyon
#

Im reading it, i hear it conceptually, but im not seeing syntax, im not seeing how to package that into the object. (PHP)

#
'subscription_data.metadata` => ['key'=>'value"],
#

??

rich turret
#

Well it's just nested associative arrays.

potent canyon
#

Or is it another nested layer deep? like subscription_data => metadata => [key=>value] ?

rich turret
#
'subscription_data => ['metadata' => ['foo' => 'bar']]

I think, I. mostly use Python

#

Yeah I think the second one

potent canyon
#

Okay, i will test that out. Thanks.

rich turret
#

๐Ÿ‘

#

I hope that gets your metadata in the place it needs to go

potent canyon
#

๐Ÿคž

#

Oh quick question before i dig into all this with testing.

#

Is there a way to do the testing clocks while actually going through a checkout session from my site? When i created a testing clock i had to make a fake customer in the dashboard, so i can't really test all of the objects with whatever data they would have attached to them from a real checkout process.

#

For example, testing adding subscription metadata then watching how it comes back in hooks when i advance time.

rich turret
#

Well, test clocks are bound to customers. So what you would do is create a fake customer with a test clock and then specify that customer ID when creating the Checkout Session.

potent canyon
#

Okay, i will try that.

rich turret
#

Still a few hoops to jump through but it gets your test clock wired up to the checkout session

potent canyon
#

Im having issue getting the sub metadata into the checkout session. In PHP i tried

'subscription_data' => ['metadata' => ['test_key' => 'test_value']],

Which i believe is correct syntax because the API doesn't throw an error. But that key:value pair isn't showing up in the $checkout_session.

#

I also have this

'metadata' => ['signup_email' => $signup_email],

Which does show up in the $checkout_session

royal current
#

Hello ๐Ÿ‘‹
Taking over for Snufkin here as they had to step away
AFAIK I don't think we copy the metadata to underlying objects

potent canyon
#

So even its not showing up in the $checkout_session object it still might be returned in the endpoint hook event?

royal current
#

AFAIK subscription_data sets the metadata on the subscription itself.
In theory, checkout_session should have a subscription object you can expand on and get the metadata from it

potent canyon
#

Is that what you mean? Or is there something else i have to do to "expand" it?

#

There is no syntax examples in the docs on creating a session showing how to use the "more parameters" with children.

royal current
#

oh wait apologies
I misunderstood the question here.
I thought you were unable to get the metadata on your webhook endpoint

potent canyon
#

I have to send it before i can get it ๐Ÿ™‚

#

Big picture goal, im trying to pass key:value in the checkout session that i can see in the invoice.paid hook to match payment to customer on my end.

#

I was told the subscription_data.metadata would be a way to do that. I have not figured out the correct syntax in PHP to do that, as im not seeing it show up in the $checkout_session when i dump to screen.

#

As in this $checkout_session im not seeing the test_key=test_value set in the above code.

royal current
#

ah okay. I'm not super skilled in PHP as well but give me a moment to look into it

potent canyon
#

Should it be showing in the $checkout_session? Or is it possible to not be visible and still be in the hook event?

#

I can do a test transaction and see what comes back in the hook. But im guessing if its not in the session it wont be in the hook.

royal current
#

I'd suggest testing as it'd clarify both pieces at once

potent canyon
#

hmm, okay, so i set it in the code, it doesn't show in the $checkout_session, but it did come back in the hooks as:

'data.object.lines.data.1.metadata.test_key' => 'test_value',
#

So its returned in lines which are prices of products.

#

I will have to setup a timer test to see how/if it comes back on a renewal.... this will take a few mins.

royal current
#

Ah okay
Thanks for confirming
As far as I can tell It should work for renewal as well but testing would certainly confirm that assumption

potent canyon
#

Okay, i test clock to a renewal. It returned the metadata in invoice.paid (and a couple others) as

'data.object.lines.data.0.metadata.subdata_meta_key' => 'test_value'

Not ideal IMO because how do you know where to look? Will it always be in lines.data.[0].metadata vs [1] or some other number?

#

And i see it fired off events for invoice.paid and invoice.payment_succeeded. What types of scenarios might cause only one of those to be triggered? Or are they both always triggered together?

#

Im trying to figure out which one event i can rely on to always fire when a customer pays (whether new sub or renewal) and only have to listen for that one event.

royal current
#

They're mostly fired one after the other but if I understand it correctly,
invoice.payment_succeeded might also be triggered on partial payment of the invoice. invoice.paid is triggered when the invoice is marked paid

potent canyon
#

So safer to rely on invoice.paid

#

Okay, im going back down the rabbit hole. I'll make more noise if i stumble again.

royal current
#

NP! ๐Ÿ™‚ Good luck