How to identify Stripe webhooks type? - stripe-payments

I am using Stripe and I need to understand how to only process webhooks that are generated by Stripe behind the scenes. When my server sends something to Stripe (new subscription, new individual charge) Stripe will generate events that are sent via the webhooks I provide. Well, I don't need to process those since it will create a mess. I only want to process Stripe generated webhooks in situations like: failed charge at subscription renewal, manual modifications via the Stripe dashboard, refunds generated in the dashboard, etc).
I went through the events generated and I cannot find anything that would make a difference from those my API calls generate or those generated behind the scenes.
Is there something I am missing?
Update
- API call: event has a request id
- Stripe behind the scenes: event has null request_id
- Stripe dashboard: event has a request id (This still remains a problem)
If I discard all webhook events that are not null I will also discard Stripe dashboard events. I need to process Stripe behind the scenes and also Stripe dashboard generated events.

First of all, Stripe currently does not support identifying the incoming webhook event type. Looking in the Dashboard I indeed can see what initiated the event (API, Dashboard or Automatic) but Stripe's people said they don't support it.
However, there is a workaround. For anyone struggling with this I will describe what I did. An automatic Stripe generated event is easy to differentiate. It contains a null request field. Any other type of event will have a request id (ex: re_123h2kj18321hjk3218). The problem remains with differentiating between API and Stripe Dashboard generated requests. Therefore, the solution is to capture the request id for every request generated by the API. Whenever a webhook arrives to your server, you check for the request field NOT to be in the Storage System (DB, etc) OR that the request is null. This means that the event was generated by either the Dashboard or Automatically by Stripe (subscription renewal).
Steps:
Hook into the CurlClient provided by Stripe. Extend that class and
override the request() method. The request method returns the
response generated by Stripe servers. Capture the headers of the
response which would contain a Request-id. Store that in your
Storage (in my case a DB)
In your configuration files you need to specify that Stripe should use your own CurlClient. ApiRequestor::setHttpClient(new CurlClient()); (I've named my CurlClient too but you can name it whatever)
When a webhook arrives, you have three options to identify the type:
Automatic: if the event has a request=null
Dashboard: the request is not null and the request is not in you Storage
API: you're left with one situation. The request is not null but exists in your DB
As you can see, there's quite a lot of work for something really easy. All Stripe needs to do is provide another field in their webhook event name something like request-type with three options (api, automatic, dashboard). They already have this build but they don't allow it to be shown in the webhook event.

On the event object documentation, you'll see the request property documented. This property is set whenever the event came from an API request. Otherwise, if it's null it means there was no API request associated with it and it was what we call an Automatic event in the dashboard.
You need to discard any event where request is not null on your end!

Related

How to save card details (payment method) in Stripe using backend?

The docs only covers the case where the payment method is created by the frontend (JS). But there is a risk that the user leaves the website before the frontend sends the information to the backend that the card has been added (and its ID).
In order to make a payment, I need ID of the payment method. I don't want to query Stripe's API for user cards IDs every time before making a payment, so I want to save the payment method ID in my local database. I also want to allow the user to define more payment methods and choose the default one.
Is there a reason you are using the non-recommended workflow you linked to? The most up-to-date version can be found here
Have you checked out using webhook listeners? I use them to create/update my local records.
In the workflow you reference, 3 webhook events potentially fire. First the setup_intent.created event is triggered when your server code generates the SetupIntent and its client_secret. Then, when the user fills out whatever Payment or Card element you instantiate and your frontend code calls the stripe.confirmCardSetup() (or stripe.confirmSetup() in the case of a PaymentElement), both the setup_intent.succeeded and payment_method.attached events will fire.
This last one will POST the payment_method object that was just attached to your customer back to your system. This object will have both the Payment Method ID as well as the associated Customer ID. You can use these to update your local records to map payment methods to customers in your server and avoid unnecessary API calls.

DocuSign dynamic/multiple webhook urls

Is there any guidelines/recommendations for the webhook URL that I can use for setting up the event notifications?
I am thinking of using something like this - /webhook/v1/{uniqueAppID}. The uniqueAppID changes for every envelope, I dynamically construct the URL and set it to the EventNotification object while creating the envelope.
The unique app id is used to track the response from DocuSign, So if at all there is any issue in parsing the response, I would know for which envelope/app id I have got the notification.
I read that the system will retry delivery for failures only after a successful acknowledgement is received from the webhook, In my case, it will be like having multiple webhooks. Will this setup cause any issues in retrying the failures? Does setting up the url like /webhook/v1?uniqueAppID={uniqueAppID} helps?
Thank You
Great questions.
First up, you don't have to use any kind of endpoint/URL schemes. You could have them all go one place. The information that you get from DocuSign in the payload would allow you to know everything you need about the envelope and if you need additional information - you could make API calls to determine this.
However, I would agree that if you need this information, using different endpoints would give you greater flexibility. Also, if it's different apps, you could, in theory, deploy them separately and thus the endpoint code would change without affecting other apps.
As for retry, this is done in case DocuSign does not get a 200, 201 or other HTTP response that's positive from your web server. If DocuSign gets 401 or 500 etc. If no response is received, DocuSign would retry again in 24 hours.
That should not impact your decision about the design.
One last thing to consider, you cannot be behind firewall/VPN etc. Highly recommend you consider a public cloud provider (Azure, AWS, Google) for your app to avoid networking issues.
When using envelope-level webhooks, the triggers and destination URI are embedded into that envelope. After the envelope enters a predefined state like 'sent' or 'completed', the writeback targets the URI that you provided. Unless you intentionally change this, it should remain envelope-specific.
This is different from our typical Connect setup, which would have a single URI per listener and envelopes writebacks would be directed to the listener URI at the time they're processed.
Any subsequent failure or retry attempts would follow the standard guidelines outlined here: How to get docusign webhook to retry on failure?

How to find out if a document has been signed

In my returnUrl handler, I am using list documents.
In the returned array, how can I figure out if the document has been signed or not?
Thanks!
Your return url handler will be called with a query parameter event as discussed in Inbar's answer.
But you should not use the query parameter for making business decisions since a bad guy could easily call your return url and simply tack on an event=signing_complete query parameter--spoofing your application.
Instead, when your application needs to know if the envelope has been signed or not, it has two categories of options:
Ask DocuSign
Your app can call the Envelopes::get method to determine the current status of the envelope. Other API methods can also be used for this functionality.
Design your app such that you do not call DocuSign about a particular envelope more often than once every 15 minutes since such behavior is considered polling and is not allowed.
Webhook: DocuSign will call your app
You can set up a webhook with DocuSign so that the eSignature platform will call your application when the envelope is complete (signed by all the signers, etc).
Use the DocuSign webhook HMAC feature to guarantee that the notification message came from DocuSign (was not spoofed) and that it was not altered in transmission.
By using AWS or equivalent, you can easily receive the notification messages behind the firewall, with no firewall changes. And AWS will not charge you for the first million notification messages per month. See the connect-* repos on github.com/docusign
Dashboards
If your app wants to present a dashboard to a business decision maker about the status of your envelopes, then relying on the event query parameter is fine. But before your app does anything that costs real money, eg initiate goods or services to be provided to a customer, make sure that the envelope has been signed by using one of the two techniques above.
The URL you get back from DocuSign has an event parameter and looks like this:
http://www.acme.com?event=signing_complete
signing_complete means it was signed.
https://developers.docusign.com/esign-rest-api/guides/features/embedding has the full list of other events in the "Determining Recipient Action" section of the article.

How to make an Approval step in Azure Logic app calling my own APIs similar to office365 approval connector?

I wanna build a small workflow using Azure Logic Apps that contains an "Approval" step, which is simply an API call in my own system, similar to office 365 approval connector.
However, from what I found on the internet, the only way to make a long running task in Azure Logic Apps is to use Webhooks.
In Webhooks, I could not set a value to the parameter I created "Bool-Approved".. so, How can I check it later in a condition step?
The other possible solution maybe is to use Swagger to have an "Bool-Approved" parameter. However, it does not support long running action!
What's the possible solution for me?
As you mentioned, the way to do it is to use the Webhook action, and for that you need to implement the Subscribe/Unsubscribe pattern described here. The webhook action will allow you to get any payload (via an HTTP Post) from the instance-based webhook you are subscribing to.
The points below are a summary of this blog post:
https://www.mexia.com.au/correlation-identifier-pattern-on-logic-apps/
To implement the Subscribe/Unsubscribe Webhook pattern you need to consider:
Subscription store: A database to store the unique message Id and the
instance-based callback URL provided by the webhook action.
Subscribe and Start Request Processing API: this is a RESTful API that is in charge of starting the processing of the request and storing the
subscription.
Unsubscribe and Stop Request Processing API: this is another RESTful API that is only going to be called if the webhook action on the main workflow times out. This API is in charge of stopping the processing and deleting the subscription from the store.
Instance-based webhook: this webhook is to be triggered by your own custom approval event. Once triggered, your webhook is in charge of getting the instance-based callback URL from the store and invoking it. After making the call back to the main workflow instance, the subscription is to be deleted. This is the webhook that is in charge of sending the payload you require to the waiting webhook action in your Logic App.
The subsequent actions will be able to use that response body, so you can implement your conditions, etc.
You can follow the blog post mentioned above to see a detailed example and get more details on how to implement it.
make you api return HTTP code 200 if the response if "ok" and 400 if the response is "not ok". This way you can force logic app to behave the way you need it to behave..

Stripe: "charge.succeeded" webhook not firing for connected account. Wrong event type name?

I suppose that a fundamental question I really ought to be asking, before I get into the details below, might be:
As a vendor/service-provider with a standalone Stripe account that's been connected to a platform account, is it possible for me to set up a webhook that will be called when the platform makes a successful charge on my behalf?
In any case, that's what I'm trying to do, with a webhook that I set up on the recipient account, configured to be called for any of the following events:
Test invocations of the webhook from my dashboard cause it to fire as expected.
But when when I create a charge through the platform, setting destination to reference the connected account, the webhook doesn't fire -- even though the charge is successfully created, along with an accompanying event, in the connected account.
One big fat clue -- that I don't know how to interpret -- is that the type of the event shown in the dashboard's "Events & Webhooks" tab isn't charge.succeeded or charge.captured -- it's payment.created (!).
But:
there's no event type with that name listed in the webhook configuration menu;
nor, as far as I can tell, does the API define a payment object type (and indeed, the type of the object referenced in the event is charge):
So:
Is this just a naming glitch in the API implementation that Stripe simply needs to fix?
Or is there some more fundamental problem that I'm failing to grasp with the idea of setting a webhook on a connected standalone account that I own?
(Or am I just doin' it wrong?)
At the moment, the payment.created event is not visible in the list of selectable events, so you'd have to check "Send me all events" when creating the webhook endpoint in order to receive those.
extending Dmitry's comment in the post, I was able to solve it by adding my endpoint and webhook event type to Endpoints receiving events from your account section in the Stripe dashboard.
The other section called Endpoints receiving events from Connect applications is for events with a Connect Account associated with it. The event object will have an account property, as long as it is an event generated from a Connect Account. These events will go in the Endpoints receiving events from Connect applications section of the Webhooks page in the Dashboard.

Resources