How to implement stripe webhook in symfony 5? - webhooks

I have integrated Stripe in my symfony project for subscriptions, the subscription to plans from stripe and payment it works just fine, but the problem is that i couldn't implement the webhook in the right way so i can know if a subscription is created, payed etc.
what i have done so far:
in my subscription controller i created the route to the webhook:
class SubscriptionController extends AbstractController
{
/**
* webhook page
*
* #Route("/bonsai_webhook",name="webhookPage")
*/
public function bonsai_webook(Request $request,Response $response){
\Stripe\Stripe::setApiKey('sk_test_...');
$webhookSecret = "whsec_...";
$event = $request->query;
// Parse the message body and check the signature
$signature = $request->headers->get('stripe-signature');
if ($webhookSecret) {
try {
$event = \Stripe\Webhook::constructEvent(
$request->getcontent(),
$signature,
$webhookSecret
);
} catch (\Exception $e) {
return new JsonResponse([['error' => $e->getMessage(),'status'=>403]]);
}
} else {
$request->query;
}
$type = $event['type'];
$object = $event['data']['object'];
$manager = $this->getDoctrine()->getManager();
$today = date("Y-m-d",strtotime('today'));
switch ($type) {
case 'checkout.session.completed':
// Payment is successful and the subscription is created.
// You should provision the subscription.
$user->setSubEndDate($today);
$manager->persist($user);
$manager->flush();
break;
case 'invoice.paid':
// Continue to provision the subscription as payments continue to be made.
// Store the status in your database and check when a user accesses your service.
// This approach helps you avoid hitting rate limits.
break;
case 'invoice.payment_failed':
// The payment failed or the customer does not have a valid payment method.
// The subscription becomes past_due. Notify your customer and send them to the
// customer portal to update their payment information.
break;
// ... handle other event types
default:
// Unhandled event type
}
return new JsonResponse([['session'=>$session,'status'=>200]]);
}
when i run./stripe listen --forward-to https://localhost:8000/bonsai_webhook
and try to create a subscription i got
customer.created [evt_1IYs4HKoLZxEIn3zDY5tFGZV]
2021-03-25 13:13:41 [307] POST http://localhost:8000/bonsai_webhook [evt_1IZ2SeKoLZxEIn3zvx1urxJ1]
and in in the webhook route i got [{"error":"Unable to extract timestamp and signatures from header","status":403}]
there is no stripe signature is always empty , and i don't know what i did wrong.
i also added some logs
$logger->info($request->headers->get('stripe-signature'),$request->headers->all());
$logger->error($request->headers->get('stripe-signature'),$request->headers->all());
$logger->critical($request->headers->get('stripe-signature'),$request->headers->all());
and i did never receive the logs from the trigger create.subscription.event
so my question is: how to get the stripe signature ? and i hope its the only thing missing in my code.
Thank you.

The error you're seeing indicates the HTTPS certificate you're using locally isn't recognized as valid by Stripe CLI.
I recommend trying the command with http:// instead of https://:
./stripe listen --forward-to http://localhost:8000/bonsai_webhook
If your web server allows insecure local connections that should get things working.

I just figure it out with the help of the stripe communit, my server was trying to redirect to a https:// URL(that's what the 307 redirect is). Setting https:// in the webhook URL doesn't work because it's a self-signed certificate. And the solution was to disable SSL/HTTPS entirely on the local application, instead i switched to an https environement on a server .

In a more recent version of stripe (e.g. 1.11.0 and above) the certificate check can be skipped using --skip-verify.
So in any case someone is stumble upon the same issue like the author:
# listen on HTTPS but do not verify SSL/TLS certificate
stripe listen --forward-to https://localhost:8000/bonsai_webhook --skip-verify

Related

Shopify Webhook Real Time changing

is there an api on shopify where I can see real time when data changes ? Maybe I have a node server and I use sockets to see when anyone has bought anything from my shop that I get a notification via nodejs on my backend. is it possible ? a few websites has this, they offers you to sell on their site and you can see real time changes data when anything was bought
Yes, you can subscribe to multiple Webhooks to get notified when a change occurs on your shop. Using the REST Admin API, available webhook event topics include:
orders/create: occurs whenever an order is created / someone buys from your shop.
orders/paid: occurs whenever an order is paid.
orders/fulfilled: occurs whenever an order is fulfilled.
orders/cancelled: occurs whenever an order is cancelled.
Use the /admin/api/2023-01/webhooks.json endpoint to subscribe to a webhook:
// Node.js - Session is built by the OAuth process
const webhook = new shopify.rest.Webhook({session: session});
webhook.topic = "orders/create";
webhook.address = "https://example.hostname.com/";
// format you want to receive the event data in
webhook.format = "json"; // or XML
// fields you want to receive
webhook.fields = [
"id",
"note"
];
await webhook.save({
update: true,
});
You can also use the GraphQL Admin API for the same purpose.

How to get payment response callback to my backend while using all-in-one sdk on Android

I am trying to setup paytm in my Flutter app, I create the txn token on firebase cloud function in which the callback URL I pass it is paytm's static url, https://securegw.paytm.in/theia/paytmCallback?ORDER_ID=order_id. While the payment flow is working on the client side, I'm not sure how do I get back the response of the payment ON MY BACKEND once the transaction is complete (succeeded or failed)? Do I set up a polling just after I create the transaction token to call the order status API? I tried setting up a webhook in the dashboard > Developer > Webhooks > payment notification, but no requests are made from the paytm servers after the transaction (same goes for refund webhooks).
There is a one plugin available for doing this called paytmkaro you can use this but it's only work with production keys.
Before starting upload the server side code on server which is available on their documentation which is available here please don't make any changes on server side code it's used to generate a txn token on paytm server.
Change the minimum sdk version to 19
and just copy paste this code
` try {
PaytmResponse paymentResponse = await _paytmKaro.startTransaction(
url: serverside code url e.g. https://arcane-temple-61754.herokuapp.com/intiateTansection.php,
mid: your Production merchant id,
mkey: your merchant key,
customerId:customer id (must be unique for every customer),
amount: transection amount,
orderId: Order Id (Order id must be unique Everytime for every order),
);
if(paymentResponse.status=="TXN_SUCCESS"){
Navigator.push(context, MaterialPageRoute(builder: (context)=>txnSuccessful(paytmResponse: paymentResponse,)));
}
else if(paymentResponse.status=="TXN_FAILURE"){
Navigator.push(context, MaterialPageRoute(builder: (context)=>txnFailed(paytmResponse: paymentResponse,)));
}
}
catch(e){
print(e);
key.currentState.showSnackBar(SnackBar(content: Text(e.toString()))); // platformVersion = 'Failed to get platform version.'
}`
and you are done.
Please raise a query to paytm -> Open paytm developer portal than go into the FAQ section and click on send a Query.

Stripe Automatic Confirmation and order fulfillment without Webhooks?

The stripe documentation says when using payment intent using automatic confirmation you should Asynchronously fulfill the customer’s order using webhooks.
If i'm offering a service e.g. ability to download a file once purchased then why do I need to monitor for the payment_intent.succeeded webhook?
If payment succeeded in the following handleCardPayment function then is there still a possibility for the charge to fail? Why shouldn't I allow the user to download the file straight away if the payment has succeeded?
var cardholderName = document.getElementById('cardholder-name');
var cardButton = document.getElementById('card-button');
var clientSecret = cardButton.dataset.secret;
cardButton.addEventListener('click', function(ev) {
stripe.handleCardPayment(
clientSecret, cardElement, {
payment_method_data: {
billing_details: {name: cardholderName.value}
}
}
).then(function(result) {
if (result.error) {
// Display error.message in your UI.
} else {
// The payment has succeeded. Display a success message.
}
});
});
Maybe I've not understood how the handleCardPayment works. Any help appreciated.
When using handleCardPayment, the issue is not so much that the payment might fail, it's that it might succeed but your code doesn't know about it.
handleCardPayment kicks off several asynchronous steps — showing the user a dialog to authenticate a payment with their bank, processing the actual charge against their card, and closing the dialog. It's only after all that completes does the Promise resolve and your function that receives result executes.
Consider the case where:
the customer clicks Pay
handleCardPayment is called
the customer sees a dialog from their bank to authenticate the
payment
they do that, and they consider that their payment is now complete,
and they close their browser immediately.
In this case, your code will never execute, but Stripe still processed the charge. So you don't know that the payment happened and you can't fulfil the order.
That's why it's important to use webhooks, so you get notified asynchronously when the payment completed, even if the user closed their browser mid-process and your code after handleCardPayment never got a chance to run. Alternatively you can use the manual confirmation flow, where the steps are split up and the actual charge isn't processed until your server makes a separate API call.

Accessing local https service from stripe webhook

I am integrating a payment system using Stripe. In the process, I need to test the webhooks in my local dev. machine before I ship it to QA. I have tried the following,
Ultrahook: however when starting the ultrahook it said, authenticated <myaccount>, but did not give any "Forwarding activated..." message. When I tried to access the url from stripe or web, it did not work. Details below,
local url: https : //localhost/xxx/yyy/zzz
ultrahook command: ultrahook -k localhost https : //localhost.com/xxx/yyy/zzz
hook url used in stripe: http : //localhost.arivanza.ultrahook.com/xxx/yyy/zzz
I have also tried, https : //localhost.com/, but the request does not come through from the hook when tested from stripe.
LocalTunnel: I could not find the way to launch the application after downloading it from the github.
PageKite: It by default opens up localhost:80, not sure how to open up the https://localhost.com
Any help would be greatly appreciated.
Hi I have tried by self.
Please follow following steps
download ngrok and extract in any folder
run ngrok.exe and type following command ngrok http [port] -host-header="localhost:[port]"
Y0u will get a url in ngrok console "Forwording" like https://7755afd8.ngrok.io
this url is replacement of localhost:[port]
You can use no https://7755afd8.ngrok.io/index.html
Code example for stripe webhook using asp.net:
var postdata =new StreamReader(HttpContext.Request.InputStream).ReadToEnd();
var data = JObject.Parse(postdata);
var eventid = data["id"].ToString();
var eventdata = StripeHelper.GetStripeEvent(eventid);
if(eventdata!=null)
{
switch(eventdata.Type)
{
case "charge.succeeded":
//charged event
break;
case "customer.source.created":
//card added
break;
case "customer.source.deleted":
//card deleted
break;
case "customer.subscription.trial_will_end":
//trial will end
break;
}
}
If you need to receive webhooks on your local dev machine (let's say, on localhost:1234/api/url), you could use a local "mock" Stripe server, like localstripe. Once lauched, it will act like Stripe and send events if you configure it to.
Install and run localstripe:
pip3 install --user localstripe
localstripe
Configure your program to use localhost:8420 (localstripe) instead of the real Stripe (api.stripe.com). For instance with a Python program:
import stripe
stripe.api_key = 'sk_test_anythingyouwant'
stripe.api_base = 'http://localhost:8420'`
Configure localstripe to send webhook events to your program:
curl localhost:8420/_config/webhooks/mywebhook1 \
-d url=http://localhost:1234/api/url -d secret=whsec_s3cr3t
Not all events are implemented in localstripe, and it could behave slightly differently from real Stripe. But it allows you to test your application in a local sandbox, without touching actual Stripe servers.
Although the others answers work, I think they are a bit dated.
Stripe now has a CLI tool that allows you to create a connection between Stripe and your local host. Here are the steps
Create the webhook file that handles the Stripe webhook calls. Let's assume that path to this file is http://localhost/webhook.
Go to stripe.com, go to the dashboard, then click on Developers, and Webhooks, then add a new endpoint. Make sure the URL in that endpoint is the one from step 1 above (i.e., http://localhost/webhook)
Download and install the Stripe CLI locally. Then follow the instructions to login
In your Stripe CLI, run the following command:
stripe listen --forward-to http://localhost/webhooks.
This will eventually listen to Stripe for any webhooks to your local server, and forward them to your sever locally (i.e, it creates a bridge between the two)
Test your work.
The problem with the above solution is it is not going to send back the responses of the webhook back to the Stripe server (because the http://localhost/webhook is private to your network).
If you insist on having responses back to Stripe, then you should either
Map your localhost to a public domain
Use a tunnel, such as ngrok. This answer describes how to use ngrok, but for me, I make the ngrok call this way:
ngrok http -host-header=localhost 80
The above call would give me something like https://<some-random-numnber>.ngrok.io
So in stripe.com, I would have to write the endpoint as
https://<some-random-numnber>.ngrok.io/<path-to-webhook-response-page>/
Hope this helps
Although the others answers work, I think they are a bit dated.
Stripe now has a CLI tool that allows you to create a connection between Stripe and your local host. Here are the steps
Create the webhook file that handles the Stripe webhook calls. Let's
assume that path to this file is http://localhost/webhook.
Go to stripe.com, go to the dashboard, then click on Developers, and
Webhooks, then add a new endpoint. Make sure the URL in that
endpoint is the one from step 1 above (i.e.,
http://localhost/webhook)
Download and install the Stripe CLI locally. Then follow the
instructions to login
In your Stripe CLI, run the following command:
stripe listen --forward-to http://localhost/webhooks.
This will eventually listen to Stripe for any webhooks to your local
server, and forward them to your sever locally (i.e, it creates a
bridge between the two)
register url in VerifyCsrfToken[Middleware]:
class VerifyCsrfToken extends BaseVerifier
{
protected $except = [
'webhook'
];
}
Test your work

Mandrill .NET inbound mail webhook: HTTP error 411

This is for those who have tried using Mandrill .NET in github.
I need to be able to process inbound mails, and based on Mandrill documentation, I have to create a webhook with a corresponding public url. In terms of implementing the action method, I followed the method signature as described in the documentation of WebHookEvent.cs. At that point everything was working as expected: if I send mail to the mandrill email which I registered to the webhook event, the action method is invoked from Mandrill. For discussions's sake let's assume that the method name is ProcessInboundMail.
Moving forward, my app needs to support multitenancy. So instead of a straightforward processing in the method ProcessInboundMail, I have to somehow Redirect to a url that includes the appropriate subdomain (e.g. company1.myapp.com/mycontroller/ProcessInboundMail). From then on I started to encounter a peculiar issue.
If I send mail to the mandrill email, the action method is no longer properly executed. To verify if the webhook is working, I went to the mandrill admin page > Inbound > Domains (InboundDomains.png), clicked Routes button, then clicked the button "send test" (MailboxRoutes.png), but all I get is this error message:
Webhook failed with error: POST to http://myapp.com/mycontroller/ProcessInboundMail failed with 411: Length Required
Length Required
HTTP Error 411. The request must be chunked or have a content length.
Here is how my ProcessInboundMail looks like:
[AllowAnonymous]
[ValidateInput(false)] // May be required if accepting inbound webhooks
[AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post | HttpVerbs.Head)]
public ActionResult ProcessInboundMail(string id, FormCollection val)
{
var events = Mandrill.JSON.Parse<List<Mandrill.WebHookEvent>>(val.Get("mandrill_events"));
foreach (var e in events)
{
//logic here...
var redirectResult = Redirect(toSomeUrl);
redirectResult.ExecuteResult(this.ControllerContext);
}
return Json(1, JsonRequestBehavior.AllowGet);
}
My question is, how come when I was not using Redirect, clicking "send test" was successful, but now that I am using Redirect, I'm getting this HTTP error 411 when clicking "send test"? What am I doing wrong here?

Resources