Single event webhook on payment completed

When a Order is completed, I want to run a scenario in via a webhook. Currently I’m listening on payment.updated. The issue is that I get 3 rapid pings to that webhook in less than a second with all of them having a status of COMPLETED. This causes the scenario to run 3 times which I don’t want. There doesn’t seem to be any differentiating properties that I can use to filter out the other 2. What event can I use that I know will only be fired ONCE upon completion of the order (order has been paid 100% in full).

1 Like

:wave: I’m Square Dev AI, here to help answer your question!
Based on the information you’ve provided, the following documentation will help answer your question:

Additional Documentation

Pay for Orders
Use Webhooks to Integrate with a Payroll System
Handle Inventory Event Notifications

If this documentation helped you find a solution, please check the box indicating that this reply solves the problem.
Otherwise one of our Developer Advocates will provide additional assistance shortly.

1 Like

You can use the payment.updated webhook event, but you should implement a mechanism in your application to handle duplicate events. This is because Square’s webhook system may send duplicate notifications for the same event. One way to handle this is by storing the event IDs of the processed events and then ignoring any incoming events with the same ID. This way, even if you receive multiple notifications for the same event, your scenario will only run once.

This answer was reviewed by @Bryan-Square.

I suppose that is one way to handle it, but that does intrudce complexity into our application. Since the payment completed event is significant enough, I feel like it would be good for Square to have a single payment.completed event we can listen to that we know will only ever be triggered once.

1 Like

We’re constantly working to improve our features based on feedback like this, so I’ll be sure to share your request to the API product team. :slightly_smiling_face:

1 Like

One way to handle this is by storing the event IDs of the processed events and then ignoring any incoming events with the same ID

As far as I can tell, the webhook packets I get for payment.updated contain a “version” field. For a particular payment, whether it’s generated from the API, from a POS system, or from a Square Terminal, we get posts with the version number set to 1, 2, 6, and 7 - that is 4 posts for the transaction. In the example from Feb 2024 I’m looking at, only the 6th and 7th post is complete, some of the processing fees are not included till then. JSON packet excerpt:

            "version": 7

The AI advice suggests using the ID - not sure whether they mean the event ID (event_id) or the payment ID here, but neither are useful as the version (data.object.payment.version) overrides those and thus later version webhook posts need to overwrite anything saved earlier.

When I get the webhook payment.updated posts, I manage this by comparing the incoming packet version number against the one saved last time I got a payment.updated post, and discarding the post if the version number is less than or equal to the saved version.

This is somewhat more complicated than most of us would like - I think in general people are just wanting one “completed” post rather than having to manage/prioritize 4 or more webhook posts for each transaction. It looks like this was implemented to indicate transaction progress and just to make sure the info is as complete as possible, both great objectives, but it does require more work than some other systems which only post one completion packet, from memory.

Somewhat confusingly, the version behaviour is described wrongly in the documentation which (from memory) says that a “version_token” field (a long alphanumeric tag) is sent in the packet, but in fact what is sent is a “version” field containing an integer for the packet version number (much more practically useful). I have a vague memory that sandbox did at one point send version_token as described. but production certainly doesn’t at this point.

Many apologies if I’ve got any of this wrong. I can provide example packets if useful, give me a yell, I can also do discord if needed.

@BrianC It seems like the current implementation does add a lot of complexity for us developers. Hopefully we can get a payment.completed webhook which would solve some of this complexity.

1 Like

The answers are incredible! And this topic has not been solved actually. The writer says “3 rapid pings to that webhook in less than a second” He says “less than a second” You can not differentiate 3 requests that occurs less than a second by creating additional mechanism in your code. This problem needs to be fixed. It’s really annoying for developers.

To be fair, you actually can differentiate. Each webhook post tells you its version and the appid is also included.

Granted it would be great to only get one post per transaction; and it would also be handy to be able to listen to posts for just one appid as it seems that you get them all when subscribed. It would be so nice to be able to specify whether you are subscribed to ALL webhooks for all appids, or just all those posts made by one appid. Even a few subscriptions could subject a server to a mountainous storm of posts.