Square refund issued notifications on your phone.

Get a low-priority push notification when a Square payment is refunded, from the Dashboard, Point of Sale or the Refunds API, with the amount and reason.

How it works

Three steps to your first push

STEP 01

Install the recipe

One click in Studio gives you a personal webhook URL.

STEP 02

Paste your URL into Square

Add it as a webhook for refund.created.

STEP 03

Get a push on your phone

With the text, sound and buttons from the recipe.

Setup

How to set up the Square refund.created webhook

  1. Click Install in Studio and sign in. The recipe is added to your account and you get a personal webhook URL.
  2. In the Square Developer Console (developer.squareup.com/apps), open your application (create a free one if you have none) and switch to Production.
  3. Under Webhooks, choose Subscriptions and click Add subscription.
  4. Paste your webhook URL as the notification URL, tick the refund.created event, and save.https://••••••••/•••••••• your personal URL, shown after install
  5. Tick **refund.created** only. Square also sends **refund.updated** each time the refund's status changes (for example from pending to completed); the recipe ignores those so you get one push per refund.
  6. Sandbox deliveries are marked **(sandbox)**.
  7. Square signs every notification with an `x-square-hmacsha256-signature` header (an HMAC-SHA256 of your notification URL and the body, keyed with the subscription's signature key), but JustPush doesn't check that signature yet, so keep your endpoint URL private.
The code

What runs when the webhook arrives

Studio calls handleRequest(request) with the incoming webhook and sends the message it returns. It's yours after install; change anything.

transform.js
1// Square → refund.created
2// Fires once when a payment is refunded, from the Square Dashboard, Point of Sale,
3// Terminal or the Refunds API.
4// Docs: https://developer.squareup.com/docs/refunds-api/webhooks
5
6// Where the money goes back to, in plain words.
7const DESTINATIONS = {
8 CARD: "card",
9 BANK_ACCOUNT: "bank account",
10 WALLET: "digital wallet",
11 BUY_NOW_PAY_LATER: "buy now, pay later",
12 CASH: "cash",
13 SQUARE_ACCOUNT: "Square account",
14}
15
16// Header names can arrive in any case.
17function header(request, name) {
18 const headers = request.headers || {}
19 const key = Object.keys(headers).find((k) => k.toLowerCase() === name)
20 const value = key ? headers[key] : null
21 return Array.isArray(value) ? value[0] : value
22}
23
24// Table lookup that ignores inherited names such as "toString".
25function pick(table, key, fallback) {
26 return typeof key === "string" && Object.prototype.hasOwnProperty.call(table, key) ? table[key] : fallback
27}
28
29// Square Money is { amount, currency } with amount in the currency's smallest unit
30// (cents for USD/EUR/GBP, whole yen for JPY). Returns null when there's no amount.
31function money(value) {
32 const amount = value?.amount
33 const currency = value?.currency
34
35 if (typeof amount !== "number" || !Number.isFinite(amount) || typeof currency !== "string" || !currency) return null
36
37 try {
38 const format = new Intl.NumberFormat("en-GB", { style: "currency", currency })
39 return format.format(amount / 10 ** format.resolvedOptions().maximumFractionDigits)
40 } catch {
41 return null
42 }
43}
44
45function handleRequest(request) {
46 const body = request.body && typeof request.body === "object" ? request.body : {}
47 const refund = body.data?.object?.refund
48
49 // Guard: only refund.created. refund.updated follows as the refund completes, and
50 // is skipped so each refund gives one push.
51 if (body.type !== "refund.created" || !refund || typeof refund !== "object") {
52 console.log(`Ignoring Square event "${typeof body.type === "string" ? body.type : "unknown"}"`)
53 return null
54 }
55
56 // A refund is normally PENDING or COMPLETED when created; REJECTED/FAILED means it didn't go through.
57 const failed = refund.status === "REJECTED" || refund.status === "FAILED"
58 const amount = money(refund.amount_money)
59 const to = pick(DESTINATIONS, refund.destination_type, null)
60 const why = typeof refund.reason === "string" && refund.reason.trim() ? refund.reason.trim().slice(0, 100) : null
61 const sandbox = String(header(request, "square-environment") ?? "").toLowerCase() === "sandbox" ? " (sandbox)" : ""
62
63 return {
64 title: failed ? "⚠️ Refund failed" : "↩️ Refund issued",
65 message:
66 (failed
67 ? `${amount ?? "A refund"} couldn't be refunded`
68 : amount ? `${amount} refunded` : "A payment was refunded") +
69 (to ? ` to ${to}` : "") +
70 (why ? ` — ${why}` : "") +
71 sandbox,
72 topic: "Square",
73 // Low for a normal refund (you or a teammate most likely issued it yourself),
74 // High when Square rejected it, because the customer is still waiting for their money.
75 priority: failed ? 1 : -1,
76 }
77}
Payload

The Square refund.created webhook

This is what Square sends to your URL for refund.created. It is a sample, trimmed to the fields recipes use.

refund.created · sample.json
1{
2 "data": {
3 "id": "KkAkhdMsgzn59SM8A89WgKwekxLZY_ptNBVqHYxt5gAdfcobBe4u1AZsXhoz06KTtuq9Ls24P",
4 "type": "refund",
5 "object": {
6 "refund": {
7 "id": "KkAkhdMsgzn59SM8A89WgKwekxLZY_ptNBVqHYxt5gAdfcobBe4u1AZsXhoz06KTtuq9Ls24P",
8 "reason": "Item arrived damaged",
9 "status": "PENDING",
10 "version": 7,
11 "order_id": "haOyDuHiqtAXMk0d8pDKXpL7Jg4F",
12 "created_at": "2026-09-28T16:27:41.836Z",
13 "payment_id": "KkAkhdMsgzn59SM8A89WgKwekxLZY",
14 "updated_at": "2026-09-28T16:27:41.846Z",
15 "location_id": "NAQ1FHV6ZJ8YV",
16 "amount_money": {
17 "amount": 1500,
18 "currency": "USD"
19 }
20 }
21 }
22 },
23 "type": "refund.created",
24 "event_id": "bc316346-6691-4243-88ed-6d651a0d0c47",
25 "created_at": "2026-09-28T16:27:41.852Z",
26 "merchant_id": "6SSW7HV8K2ST5"
27}
FAQ

Square refund issued notifications: questions

Does this work on iPhone and Android?

Yes. Install the JustPush app from the App Store or Google Play and sign in. Every phone signed in to your account gets the notification.

Do I need to write code?

No. Install the recipe in Studio, paste your webhook URL into Square and you are done. The code is there if you want to change the text, the sound or the buttons.

Can I change what the notification says?

Yes. After install the recipe's code is yours. Edit it in Studio and test it against the sample payload before you save.

What does it cost?

JustPush is free for 30 days. After that it's $19.99 a year, or $39.99 once. There is no extra charge for recipes.

Ready when you are

Square on your phone in two minutes.

Install the recipe, paste one URL, done. Free for 30 days, no credit card required.