Consider sample chat application where user purchase monthly/annual subscriptions (subscriptions like Amazon Prime, etc).
As soon as the subscription expires, user should not be able to send messages in app.
User can end their subscription before the original subscription end date.
One solution in my mind (Frontend) - to cache the end date in app and before every "send message" operation, compare the end date and current date.
But the problem is - if user ends the subscription early, user will still be able to send the message.
How can I push update the new subscription end date in cache.
Another solution was (Backend) - I have a table in backend storing subscription details like subscription_id, user_id, subscription_enddate. So before any "send message" operation, query the subscription table and compare the dates and then continue/cancel further operations.
Q1. Should I go with Backend solution or can you please share some improvements to frontend method or any best practice for this scenario?
Q2. Also is storing subscription details in separate table best practice or any good design instead. ?
PS- Sample chat app is based on AWS Amplify Datastore
Let me try to breakdown the answer and give my opinion. I would also like to mention solutions to such problems are determined by the scale and various tradeoffs.
Q1-
If sending messages has an adverse effect, you should never rely on the frontend solution only as it is easy to bypass them. You can use a mixture to ensure that the load is not very high on the backend.
Adding a Frontend Cache for subscription will ensure you will be able to filter most of the messages on the frontend if the cache is not tampered with.
Adding a service before the queue, that validates whether the user subscription has expired adds one more layer of security. If the user subscription is valid it pushes the message to Queue else throws an error. This way any bad actor can also not misuse the system.
Q2-
Depending on the use-cases and load, you can have a separate table or a separate micro-service for the subscription itself.
When to have a separate micro-service?
When the subscription data is required from multiple applications in your system and needs to have its own scalability independent of others, it can be beneficial to have a separate micro-service.
When to have a separate table?
In other cases, where you feel adding a service would be overkill. You can keep the data separate in a different table/DB giving you the flexibility to change subscription and even extract it easily in the future.
I use Stripes' webhooks and want to get notified, if the customer successfully "paid the bill". I came across two webhooks, which in my opinion both could do the job:
Webhook "invoice.paid" - According to Stripe doc: Occurs whenever an invoice payment attempt succeeds or an invoice is marked as paid out-of-band.
Webhook "checkout.session.completed" - According to Stripe doc: Occurs when a Checkout Session has been successfully completed.
My questions are:
I don't understand the second part of the "invoice.paid" webhook: "invoice is marked as paid out-of-band" -> What does "out-of-band" mean? Is this to be considered a successful payment?
Regarding "checkout.session.complete" -> This can also occur, if payment fails - correct?
Which webhooks shall I consider (or are there other webhooks) to see the status "customer paid the bill successfully"?
What is more, I don't really know if disputes should be considered as successful payments or not: On one hand, I get a invoice.paid webhook, on the other hand, I get a charge.dispute.created webhook. geeezus...
I appreciate your help! Thanks.
I don't understand the second part of the "invoice.paid" webhook: "invoice is marked as paid out-of-band" -> What does "out-of-band" mean? Is this to be considered a successful payment?
This is specifically referring to marking an invoice paid out of band (ie, the customer paid you outside of Stripe and you want to mark the Stripe invoice paid without collecting a payment). This will not involve an actual payment, but does transition the invoice to status=paid so this event fires.
Regarding "checkout.session.complete" -> This can also occur, if payment fails - correct?
This event signals only that the Checkout session is complete. Depending on the mode use for Checkout, this may or may not involve a payment. If an immediate payment is expected, the session will only complete if that payment is successful. For example mode=setup or mode=subscription with a free trial will not involve an immediate payment. A subscription with trial, though, will create a $0 invoice and fire invoice.paid.
Which webhooks shall I consider (or are there other webhooks) to see
the status "customer paid the bill successfully"?
This depends on what you mean by "paid" and "bill". If you mean specifically for invoices (whether related to subscriptions or not), then invoice.paid is a good choice. You can then filter for amounts greater than $0 etc to further constrain was "paid" means.
What is more, I don't really know if disputes should be considered as
successful payments or not: On one hand, I get a invoice.paid webhook,
on the other hand, I get a charge.dispute.created webhook.
Disputes are not payments, and should be an entirely separate discussion. You can only have a dispute after a payment. Suggest starting by reading the docs on disputes.
To summarize: What are you really trying to do? These events are related and sometimes overlap, but not always. It highly depends on what you're doing.
What's going on?
When you create a checkout session it will have an id, which you'll store in your database next to the user who started the checkout session.
When you receive an invoice.paid webhook event, it does not have any link back to the checkout session! (so you'll know someone paid, but you won't know who paid!)
checkout.session.completed solves this because it contains the id of the checkout session and the stripe customer id, which allows you to link the two, so you basically have a mapping from your customer ids to stripe's customer ids.
So simply grab the customer id from the checkout.session.completed event and store it in your database next to the relevant user, that way you'll be able to tell which one of your users is paying you when you receive an invoice.paid event!
How can this be implemented?
When a checkout session is started, store the checkout session id next to the user who started the session so you can look it up later
When you see checkout.session.completed, look at the accompanying JSON and take the stripe customer number and store it in your database (e.g. a column like stripe_id in users table). To figure out which of your users it's for, use the checkout session id to look it up in your database (i.e. the data you stored in step 1)
Now that you have the stripe customer id stored in your users table, whenever you see invoice.paid, look at the accompanying JSON, take the stripe customer number, look it up in your users table to find who paid, and update the expiry date of their subscription to 1 month into the future.
That's it!
Also good to know
Both checkout.session.completed and invoice.paid events are triggered when someone new subscribes, and only invoice.paid is triggered each month thereafter (presuming the user had enough funds and didn't cancel)
You can get to the stripe customer number in both webhook events like so (this is ruby, but should be similar with js or python):
payload = request.body.read
data = JSON.parse(payload, symbolize_names: true)
data.object.customer
=> "cus_Lvyv721cJGpYB1"
We are using authorize.net for payments in our checkout but in some cases we are not getting any response from authorize.net so we are unable to store transaction details in our database and also customers are being charged more than once. So to resolve this we are planning to get the transaction details before sending the payment but we don't have transaction id in our side, so we need a API to get the transaction details using invoice number.
I have searched lot in the API documentation but couldn't able to find it, so any reference might be helpful.
You cannot retrieve transaction information through their API with an invoice number. If you know the dates, and other helpful information about these missing transactions, you can use their Transaction Reporting API to get those day's transaction and retrieve the necessary information that way.
One way to avoid this in the future is to use either Silent Post1 or their new Webhooks API to get notified whenever a payment is made (and any other event you specify).
1 I am the author of that article.
In our API reports we noticed that we always get the Actions filed with no values.
after checking this with facebook support we understood that our request query was wrong. we are able to get the data with the following query that the suggested to us:
https://graph.facebook.com/act_52081533/adgroupstats?start_time=2013-04-22T00%3A00%3A00+-0700&end_time=2013-04-23T00%3A00%3A00+-0700&include_deleted=true&stats_mode=with_delivery&&limit=500&offset=0&access_token
I'm getting the same data as the UI present on 22/4/2013 but I don't understand why they are including 23/4/2013 date and why they using '+-0700'. The account time zone is GMT -8.
I read all documents referring this issue but could not found an explanation to this patters.
Is there any way to get the user count by status of facebook events? Facebook does this on the event page (the left columng with each status has a count next to it), but could not find any documentation on how to do the same. It needs to work for small or large events. For small events, I can easily get the list of users and do a quick count. But for events with over 1000 users, the previous method is too slow and not acceptable.
I don't think there's a better way than count every list of users as explained below.
You can which users are 'attending' an event by issuing an HTTP GET to /EVENT_ID/attending
You can which users have replied 'maybe' to an event by issuing an HTTP GET to /EVENT_ID/maybe
You can which users are declined an event (i.e. responded 'no') by issuing an HTTP GET to /EVENT_ID/declined
You can which users have not replied to an event by issuing an HTTP GET to /EVENT_ID/noreply
Taken from https://developers.facebook.com/docs/reference/api/event/
UPDATE 28-Jun:
As of today, Facebook added new fields to the Event FQL table that allows you to do exactly what you want.
From the developers blog:
We've added the following fields to the event FQL table to make it
easier to get the counts of users RSVP-ed to an event:
all_members_count
attending_count
unsure_count
declined_count
not_replied_count
They're pretty much self-explanatory.