Square POS iOS Deep Link — Payment Reuse, Cancellation and Consecutive Transactions

Hello Square Developer Team,

I’m developing Carlin’s Garden, a web-based point-of-sale system for a small family bakery.

Our Register integrates with the existing Square Point of Sale app on an iPhone using the square-commerce-v1://payment/create URL scheme.

The intended workflow is:

  1. Our web Register creates a sale and opens the Square app with the payment amount.

  2. The customer completes payment using Tap to Pay on iPhone or another supported card payment method.

  3. Square returns to our website through a callback URL.

  4. Our backend verifies the Square transaction and marks the sale as paid.

  5. The cashier proceeds to the next customer.

We’ve experienced an occasional problem where Square appears to process the payment successfully, but our Register becomes stuck during the return/confirmation process.

We’re improving our payment recovery and duplicate-charge protections, but we need clarification about how Square handles previously issued POS API deep links.

Our questions:

1. Deep-link reuse after payment

If a square-commerce-v1://payment/create URL has already been used to complete a successful payment, can that exact same URL be opened again and initiate another payment?

Or does Square automatically prevent it from being reused?

2. Request ID and duplicate-payment protection

Does the POS API’s request_id provide any Square-enforced idempotency or replay protection?

For example, if the same request_id and payment deep link are submitted twice, will Square prevent a second charge?

Or is request_id only intended to correlate the original request with the callback response?

3. Expiration or invalidation

Do POS API payment deep links have a documented expiration or single-use guarantee?

Is there any supported method to invalidate an issued payment URL?

4. Cancelled or interrupted payments

If the cashier opens Square but cancels the payment, closes the app, loses internet connectivity, or never returns to our Register, how can our application authoritatively determine that the previous deep link can no longer initiate a charge?

5. Payment verification and recovery

If Square successfully processes the card but the callback is lost or our website fails to restore correctly, what is the recommended way to identify and recover that completed payment without initiating another charge?

6. Consecutive customer transactions

What is Square’s recommended integration pattern for a mobile-web Register that needs to process multiple consecutive payments throughout the day?

We want the cashier to complete one payment and safely begin the next transaction without older payment links creating a duplicate-charge risk.

Our backend independently verifies payment status and transaction identity, but successful verification alone doesn’t necessarily establish whether an older payment link remains usable.

We’re specifically asking about the Square Point of Sale API for iOS, not the Online Checkout Payment Links API.

Could someone from the Square Developer team clarify the provider-enforced behavior of these POS deep links, especially regarding request_id, replay protection, and their lifecycle after payment completion or cancellation?

Any official documentation or recommended implementation guidance would be greatly appreciated.

Thank you!

Welcome to the Developer Forum!

  1. Don’t rely on a POS API deep link becoming unusable after payment or cancellation. The iOS implementation handles each launch as a new request. In other words, completion clears the active request; it does not record the URL as consumed.
  2. The POS API request carries no Square-side idempotency key. You’d rather want to use state, which Square echoes back in the callback so you can match the response to your sale. Treat duplicate-charge protection as your Register’s job, and mark a sale as “handed to Square” before you open the URL, and never reopen a URL for a sale that already has a callback or a matched payment.
  3. For the iOS Point of Sale API, there is no documented expiration time or single-use guarantee for square-commerce-v1://payment/create URLs, and no documented operation to revoke an individual issued URL. Don’t assume completion or cancellation makes that URL unusable.
  4. A payment_canceled callback describes that attempt. Closing the app, losing connectivity, or missing the callback leaves an unresolved outcome. There is no supported “is this URL now incapable of charging?” query. Payment reconciliation answers whether a payment occurred, not whether the original URL is reusable.
  5. For verification, use transaction_id as the Order ID, then retrieve the Payment through its tender. If the callback is lost, reconcile through payment webhooks/ListPayments and associated Orders. Include a unique sale/attempt reference in notes, and fetch payment details
  6. For consecutive sales, persist attempts before launch, serialize POS requests, restore browser state from your backend, and reconcile uncertain attempts before retrying. These controls prevent duplicate actions in your register, yet they don’t revoke retained raw URLs.

Hope this helps!