# How to identify and handle 'CANCELLED' payments?

**URL:** <https://developer.squareup.com/forums/t/how-to-identify-and-handle-cancelled-payments/23404>\
**Category:** Questions\
**Tags:** payments-api\
**Created:** [July 28, 2025, 10:08pm UTC](https://developer.squareup.com/forums/t/how-to-identify-and-handle-cancelled-payments/23404 "2025-07-28T22:08:15Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![NemoNoman](https://avatars.discourse-cdn.com/v4/letter/n/bb73d2/32.png) [@NemoNoman](https://developer.squareup.com/forums/u/NemoNoman)\
**Post date:** [July 28, 2025, 10:08pm UTC](https://developer.squareup.com/forums/t/how-to-identify-and-handle-cancelled-payments/23404/1 "2025-07-28T22:08:15Z")

</div>

I will be happy to provide webhooks showing examples of this problem.  
I just became aware of the ‘CANCELLED’ status on payments. My wife owns a small yoga studio: I handle Square Data processing – she looks at the square dashboard.

The studio sells ‘E-Cards’ for class attendance. My home-built website creates an internal customer id, and then saves the Square ID for the customer. Customer then enters a credit card, for payment for an E-card (20). When the payment is approved, we update the customer records the payment id, and with an E-Card PIN so they can enter the class.

Today a new first-time customer followed this process and attended a class.

My wife wanted more information from the Square Dashboard, and there were no transactions shown. I’m first line tech support, so I looked at database records, including payment webhooks that I store.

I found webhookks for customer creation, card creation, payment creation.

I also capture payment.updated webhooks, but my experience is that the ‘updates’ are sometimes not visible at all – I requested info, and was told that some updates are internal to square, and don’t show on webhooks. So I have mostly been ignoring payment updates.

This time I checked those updates.  
After the payment.created webhook there were 2 additional webhooks version 2 and 3, related to the payment id.

Version 2 arrived 2 seconds after version 1: Only signifcant change to version 2 was this:

```auto
[card_payment_timeline] => Array                        
    (                                                   
        [authorized_at] => 2025-07-24T00:22:30.576Z     
        **[voided_at] => 2025-07-24T00:22:32.330Z**         
    )   

```

Version 3 arrived 12 seconds later: Only significant differences between versions 2 and 3:  
[payment][card\_detatils][status] =\> changed from AUTHORIZED tp VOIDED  
and  
[payment][status] =\> changed from AUTHORIZED to CANCELLED

There was no record of any of the payment transaction, or these payment versions on the Square Dashboard.

My wife spoke to the student. She told us that she looked at her credit card statement and found the charge (same time as transaction 1), then found a second entry “REFUNDED”. **Student had NOT requested a refund.**

> I logged into my credit card account, and it seems like I got charged on the 27th at 9:41 pm and it got refunded at 9:42 pm.

So the student had assumed she’d paid, and our system did too.

I need to understand what happened, and what to do about it?  
I don’t know how to keep watching webhooks for cancellations, when we’ve already given the student the class they ‘paid’ for?

I have now found similar instances in my webhook database, and can provide those in detail if it helps.

Thanks.

---

<div class="post-metadata">

**Author:** ![Square-Dev-AI](https://sea1.discourse-cdn.com/square/forums/user_avatar/developer.squareup.com/square-dev-ai/32/2513_2.png) [@Square-Dev-AI](https://developer.squareup.com/forums/u/Square-Dev-AI)\
**Post date:** [July 28, 2025, 10:08pm UTC](https://developer.squareup.com/forums/t/how-to-identify-and-handle-cancelled-payments/23404/2 "2025-07-28T22:08:32Z")

</div>

👋 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:

> **[Payments API Webhooks](https://developer.squareup.com/docs/payments-api/webhooks)**
>
> Learn about the Square webhook notifications supported by the Payments API.

> **[Refunds API Webhooks](https://developer.squareup.com/docs/refunds-api/webhooks)**
>
> Learn how to use Square webhooks to get notifications of refund updates.

> **Additional Documentation**
>
> [Use Customer Webhooks](https://developer.squareup.com/docs/customers-api/use-the-api/customer-webhooks)  
> [Gift Card Webhooks](https://developer.squareup.com/docs/gift-cards/webhooks)  
> [Pay or Refund Invoices](https://developer.squareup.com/docs/invoices-api/pay-refund-invoices)

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.

---

<div class="post-metadata">

**Author:** ![Bryan-Square](https://sea1.discourse-cdn.com/square/forums/user_avatar/developer.squareup.com/bryan-square/32/38_2.png) [@Bryan-Square](https://developer.squareup.com/forums/u/Bryan-Square)\
**Post date:** [July 28, 2025, 10:13pm UTC](https://developer.squareup.com/forums/t/how-to-identify-and-handle-cancelled-payments/23404/3 "2025-07-28T22:13:52Z")

</div>

What is the `payment_id` for the payment in question? 🙂

---

<div class="post-metadata">

**Author:** ![NemoNoman](https://avatars.discourse-cdn.com/v4/letter/n/bb73d2/32.png) [@NemoNoman](https://developer.squareup.com/forums/u/NemoNoman)\
**Post date:** [July 28, 2025, 10:56pm UTC](https://developer.squareup.com/forums/t/how-to-identify-and-handle-cancelled-payments/23404/4 "2025-07-28T22:56:55Z")

</div>

vpPb6zbPsEq7AbuVDMvqnLwHVlIZY

---

<div class="post-metadata">

**Author:** ![Bryan-Square](https://sea1.discourse-cdn.com/square/forums/user_avatar/developer.squareup.com/bryan-square/32/38_2.png) [@Bryan-Square](https://developer.squareup.com/forums/u/Bryan-Square)\
**Post date:** [July 28, 2025, 11:23pm UTC](https://developer.squareup.com/forums/t/how-to-identify-and-handle-cancelled-payments/23404/5 "2025-07-28T23:23:00Z")

</div>

Looks like that payment failed due to an incorrect `order_id`. 🙂

```auto
{
  "errors": [
    {
      "code": "NOT_FOUND",
      "detail": "Order not found for id ",
      "category": "INVALID_REQUEST_ERROR"
    }
  ],
  "payment": {
    "id": "vpPb6zbPsEq7AbuVDMvqnLwHVlIZY",
    "created_at": "2025-07-24T00:22:29.908Z",
    "updated_at": "2025-07-24T00:22:30.861Z",
    "amount_money": {
      "amount": 2000,
      "currency": "USD"
    },
    "status": "CANCELED",
    "delay_duration": "PT168H",
    "source_type": "CARD",
    "card_details": {
      "status": "VOIDED",
      "card": {
        "card_brand": "MASTERCARD",
        "last_4": "2479",
        "exp_month": 3,
        "exp_year": 2027,
        "fingerprint": "sq-1-7PoUyLMFbDrwEhNWxQ5E1WNr8PrvS7mrToVgwO9ST-oSQjfa_NU24Kg0zKtp8hankQ",
        "card_type": "DEBIT",
        "prepaid_type": "NOT_PREPAID",
        "bin": "527519",
        "payment_account_reference": "50011PFDH8RZ5ZPMHUD7U0ANIS4E1"
      },
      "entry_method": "ON_FILE",
      "cvv_status": "CVV_NOT_CHECKED",
      "avs_status": "AVS_ACCEPTED",
      "auth_result_code": "102122",
      "statement_description": "SQ *WEAVERVILLE YOGA INC",
      "card_payment_timeline": {
        "authorized_at": "2025-07-24T00:22:30.576Z",
        "voided_at": "2025-07-24T00:22:30.861Z"
      }
    },
    "location_id": "91F1VEX85751A",
    "order_id": "",
    "risk_evaluation": {
      "created_at": "2025-07-24T00:22:30.768Z",
      "risk_level": "NORMAL"
    },
    "customer_id": "ZNB65WXZSX9XX6Z2SZJNKQHX0G",
    "total_money": {
      "amount": 2000,
      "currency": "USD"
    },
    "approved_money": {
      "amount": 2000,
      "currency": "USD"
    },
    "delay_action": "CANCEL",
    "delayed_until": "2025-07-31T00:22:29.908Z",
    "application_details": {
      "square_product": "ECOMMERCE_API",
      "application_id": "sq0idp-XX6UWAX013YgL8UN-wNg8w"
    },
    "version_token": "cK3pcuHrXOvcv4bZIri6NbOeHSgsw4VWvJmRLuTLD755o"
  }
}

```

🙂

---

<div class="post-metadata">

**Author:** ![NemoNoman](https://avatars.discourse-cdn.com/v4/letter/n/bb73d2/32.png) [@NemoNoman](https://developer.squareup.com/forums/u/NemoNoman)\
**Post date:** [July 28, 2025, 11:49pm UTC](https://developer.squareup.com/forums/t/how-to-identify-and-handle-cancelled-payments/23404/6 "2025-07-28T23:49:46Z")

</div>

Our E-card payments are simply payments to the studio: they do not have related orders.  
Order ID is not a required field in the Create Payment API.

If a missing order ID was a consistent cause of failure, many hundred payments would be failing.

Also your answer suggests the VOID was issued by Square? Not by cutomer or Card Company?

---

<div class="post-metadata">

**Author:** ![NemoNoman](https://avatars.discourse-cdn.com/v4/letter/n/bb73d2/32.png) [@NemoNoman](https://developer.squareup.com/forums/u/NemoNoman)\
**Post date:** [July 29, 2025, 12:05am UTC](https://developer.squareup.com/forums/t/how-to-identify-and-handle-cancelled-payments/23404/7 "2025-07-29T00:05:59Z")

</div>

I have just gone through the web hooks looking for ‘VOID’ and all these E-Card payments were voided. I just discovered that we lost thousands of dollars, and Square never sent specific notification of payment failure.

Some notfication, at least on the Square dashboard would have been helpful.

Making Order\_ID a required field on the Create\_Payment API should be done.

This is devestating information.

---

<div class="post-metadata">

**Author:** ![NemoNoman](https://avatars.discourse-cdn.com/v4/letter/n/bb73d2/32.png) [@NemoNoman](https://developer.squareup.com/forums/u/NemoNoman)\
**Post date:** [July 29, 2025, 12:21am UTC](https://developer.squareup.com/forums/t/how-to-identify-and-handle-cancelled-payments/23404/8 "2025-07-29T00:21:31Z")

</div>

$17,960 in lost revenue. I don’t know how to recover.

---

<div class="post-metadata">

**Author:** ![NemoNoman](https://avatars.discourse-cdn.com/v4/letter/n/bb73d2/32.png) [@NemoNoman](https://developer.squareup.com/forums/u/NemoNoman)\
**Post date:** [July 29, 2025, 1:39pm UTC](https://developer.squareup.com/forums/t/how-to-identify-and-handle-cancelled-payments/23404/9 "2025-07-29T13:39:12Z")

</div>

I accept that it was my coding error that caused the multiple instances of payment failures - I had included a NULL order\_id in the payment curl.

I had gotten used to bad curl results saying ‘failed’ and so I check for ‘failed’ in the result array (and deal with failed results with an error handler). But in this case the results include words like ‘CANCEL’, ‘VOID’, etc.. so I didn’t treat the result as an error.

**PLEASE NOTE that even if i _had_ found the ‘error’ result for the curl, THERE WAS NOTHING I COULD DO to keep it from being submitted.** _The error only shows up when the curl is executed, and a payment has been intitated._

Also, the events that follow these ‘error’ payment curls are utterly confusing. Now that I know what happens, it’s just nuts. I just don’t get what Square is doing.

Despite noting the error, Square submits the (so-called error-filled) payment record to the bank. **The bank accepts the record, and charges the card**.

Following this, however, Square on its own sends the bank a new command to refund the charge it has just accepted. **Even though the BANK ACCEPTED THE PAYMENT,** Square, on its own, makes additional changes: **Square, on its own, ISSUES A REFUND.**

 ![Truist data](https://global.discourse-cdn.com/square/original/2X/7/7c9d00e97b06d0924ec99f599f7747efa4e4118e.png)

I have been looking at the process more closely now, Although I had been checking for errors in the ‘payment.created’ webhook, for these error-identified curls, the payment status was ‘APPROVED’

I have since looked deeper, and found that every payment, with or without errors, has 3 webhook entries.  
Webhook 1 – payment.created – This status always ‘APPROVED’  
Webhook 2 – payment.updated - This also always says status ‘APPROVED’  
but if there’s error, a new entry appears is [payment][card\_payment\_timeline] =\>  
[voided\_at] =\> 2025-07-29T12:17:52.371Z  
The payment status ONLY CHANGES IN  
Webhook 3 - payment.updated which now says [status] =\> CANCELED (only when Square identified the curl as having errors)

I can find no documentation for a payment canceled status. But my bank records show that a refund for the payment amount was initiated by Square

So I’m stupid not to have done more extensive error checking of my payment curl. But this doesn’t explain why

1. Square noted the error
2. Despite the error, Square submitted the payment, with status ‘approved’
3. Updated the payment with an obscure new entry to [payment]=[card\_payment\_timeline] (‘voided’) - **But did not also then change the payment status** (status still shows ‘APPROVED’)
4. Sent a refund commend to the bank – with no findable transaction record anywhere
5. Failed to show **ANY** transaction records on the Square dashboard – although both a deposit transaction and a refund transaction were sent to the bank.

I’m ready to own responsibilty for creating a curl that Square said had errors  
But I believe that Square shares responsibility for this mess:

1. Submitting the curl anyway – (which the bank thought was just fine, although Square found an ‘error’.)
2. Issuing an unnecessary refund (at least the bank didn’t think a refund was needed).
3. Failing to show any of these transactions on the Square Dashboard, so the owner was not aware of any problems.

In fact if the confused student hadn’t questioned her bank statement, and reported this mess to the owner, who then asked, we would never have discovered a problem that has cost us thousands of dollars. So i do believe that Square owns a lot for responsibilty for this disaster.

---

<div class="post-metadata">

**Author:** ![Bryan-Square](https://sea1.discourse-cdn.com/square/forums/user_avatar/developer.squareup.com/bryan-square/32/38_2.png) [@Bryan-Square](https://developer.squareup.com/forums/u/Bryan-Square)\
**Post date:** [July 29, 2025, 4:57pm UTC](https://developer.squareup.com/forums/t/how-to-identify-and-handle-cancelled-payments/23404/10 "2025-07-29T16:57:26Z")

</div>

Thank you for walking me through exactly what you saw in your logs and on your bank statement. I’m really sorry for the confusion and inconvenience you’ve been through. Let me try to pull back the curtain on exactly what’s happening inside Square so you can see why you saw an approved‐then‐voided payment, a refund on your bank statement, and very little detail back on the Dashboard.

1. Your request and the “non-blocking” error  
• You submitted a CreatePayment call with order\_id set explicitly to null.  
• Square’s API schema treats that as an unsupported attribute, so we return an error in the response body under the “errors” array (e.g. category=INVALID\_ATTRIBUTE, code=UNSUPPORTED\_ATTRIBUTE).  
• HOWEVER, because order\_id is not required to authorize and capture a card, we treat that particular error as “non-blocking.” We still proceed to call the card networks, authorize the card. In short: you got an API error about order\_id, but Square we still initially authorized the payment.
2. The automatic “fail-safe” refund/void  
Once our system spots that a payment was successfully processed despite having a non-blocking error in its payload, we automatically void the authorization since the payment was just authorized and not fully captured.
3. Why you saw three webhooks  
• webhook #1 – payment.created  
– status: APPROVED  
– This is Square saying “we accepted the authorization (and since auto\_capture=true, we also captured).”  
• webhook #2 – payment.updated  
– status: still APPROVED  
– A timeline event appears under card\_payment\_timeline showing voided\_at. At that moment we’ve told the bank to release or refund the money.  
• webhook #3 – payment.updated  
– status: CANCELED (or REFUNDED)  
– The payment object flips to CANCELED once the void has been successfully queued in our system.
4. Why you don’t see a matching void in the Dashboard’s Orders view  
These automatic “fail-safe” voids aren’t tied to an Order in your Orders list—because Square never fully completed the payment. Only fully completed payments will show in the Dashboard.

Again, I’m sorry for the runaway charges and confusing webhooks. I hope this breakdown of our “non-blocking error → auto-capture → fail-safe void/refund” workflow clears up what you witnessed in your logs, on your bank statement, and on the Dashboard. Please let me know if you have any follow-up questions. 🙂

---

<div class="post-metadata">

**Author:** ![NemoNoman](https://avatars.discourse-cdn.com/v4/letter/n/bb73d2/32.png) [@NemoNoman](https://developer.squareup.com/forums/u/NemoNoman)\
**Post date:** [July 29, 2025, 5:22pm UTC](https://developer.squareup.com/forums/t/how-to-identify-and-handle-cancelled-payments/23404/11 "2025-07-29T17:22:40Z")

</div>

Thanks for the full process information Bryan. I pictured something like what your show.  
However, I think its a big problem on your end that

1. The payment with a non-blocking error is only identified if the payment is submitted.
2. If the curl has a non-blocking error, there is apparently no way create an error handler that blocks submission – the error appears to only be created when the curl is set in process
3. If the curl is identified with non-blocking error, the curl is still submitted to the bank.

You say  
`Square never fully completed the payment. Only fully completed payments will show in the Dashboard.`  
But from the bank’s point of view, both the payment and the void are fully completed. This causes buyer confusion, and buyer mistrust of the business. There is an unfortunate disconnect between the Dashboard records seen by the Dashboard user, and the bank records seen on the buyer’s bank statement. _(What the heck is this charge?? And why the immediate refund? What you guys up to?? etc. [Owner checks the Dashboard and has no clue.])_

As to the square dashboard tranasctions page, ‘completed’ transactions only are now shown. But some button or menu option showing ‘error’ or similar that would show ‘failed’ transactions would be a big help.

The Quick and Dirty Solution® (my favorite brand) would be to turn an ‘order id not found’ into a BLOCKING error. Alternately to require order\_id in the curl explicitly much as source\_id is required (maybe both suggestions are effectively equivalent).

But for Pete’s sake – there needs to be some automatic or manual way to block the curl if it’s going to be voided automatically!!

---

<div class="post-metadata">

**Author:** ![Bryan-Square](https://sea1.discourse-cdn.com/square/forums/user_avatar/developer.squareup.com/bryan-square/32/38_2.png) [@Bryan-Square](https://developer.squareup.com/forums/u/Bryan-Square)\
**Post date:** [July 29, 2025, 7:35pm UTC](https://developer.squareup.com/forums/t/how-to-identify-and-handle-cancelled-payments/23404/12 "2025-07-29T19:35:25Z")

</div>

When a payment is `AUTHORIZED` it will be in a pending state. If the authorization falls off or is voided then the `AUTHORIZED` funds will return to the customers balance. That is what your seeing on the bank statement. If the payment went into a `COMPLETED` state then it will show in the Square Dashboard and will show as a completed payment in the customers bank statement.

As for the other behavior of the Payments API 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. 🙂
