Square Online ו-Square POS: כל תשלום שהושלם מפיק מסמך, וכל החזר מפיק חשבונית זיכוי.
התקנה (5 דקות)#
- ב-Square Developer Console צרו אפליקציה. בלשונית Credentials העתיקו את ה-Access token והדביקו אותו במסך החיבור. ההרשאות הנדרשות:
ORDERS_READו-PAYMENTS_READ. - בלשונית Webhooks → Subscriptions → Add subscription הדביקו בשדה Notification URL בדיוק את כתובת ה-Webhook שמוצגת במסך החיבור, בלי שינוי אפילו בתו אחד. Square חותם גם על הכתובת, ולכן כל הבדל שובר את האימות. סמנו את האירועים
payment.updated,order.updatedו-refund.updated. - העתיקו את ה-Signature key של ה-subscription והדביקו בשדה הסוד.
- הגדירו את המע״מ ב-Square (Taxes). בלי מס מוגדר המסמך יופק ללא מע״מ.
- בחרו סוג מסמך ולחצו על שליחת הזמנת בדיקה.
Developer reference#
Mode: hook, pull. Category: payments. Refunds: supported.
Events.
| Event | Condition | Result |
|---|---|---|
payment.updated, payment.created | payment.status == "COMPLETED" | issue |
order.updated | order_updated.state == "COMPLETED" | issue |
refund.updated, refund.created | refund.status == "COMPLETED" | credit note |
| anything else | 200 event ignored |
Square has no payment.completed event; a payment completes through payment.updated. Payment and order events of the same sale share the external id (the Square order id; the payment id when the payment has no order), so they never issue twice.
Auth. x-square-hmacsha256-signature = base64(HMAC-SHA256(notificationUrl + rawBody, signatureKey)), declared as { kind: "hmac", encoding: "base64", message: url + rawBody }. The URL is the one Square used, so the registered Notification URL must equal the receiver URL exactly. Behind a TLS-terminating proxy the URL the app sees can be http://...; the message function therefore also tries the https:// form and the URL rebuilt from x-forwarded-proto / x-forwarded-host, and signs with whichever matches the presented signature. All comparisons are constant-time.
Pull. GET https://connect.squareup.com/v2/orders/{order_id} with Authorization: Bearer <access token> and Square-Version. A payment with no order_id needs no fetch and maps to one line "תשלום Square". 404 answers 200 skipped; network error, 5xx, 401/403 answer 502 (Square retries up to 24 hours); missing credentials answer 502 חסרים פרטי חיבור.
Mapping. Square amounts are integer minor units, which equal agorot for ILS.
| Square field | Document field |
|---|---|
order.id (else payment.id) | externalId; apiIdentifier = square-<id> |
line_items[].name + variation_name | line name |
line_items[].quantity (string) | line quantityMilli |
line_items[].base_price_money.amount | line unitPriceAgorot; if modifiers make gross_sales_money differ from base x quantity, one line for gross_sales_money |
total_service_charge_money | line named after service_charges[].name (usually shipping) |
total_tip_money | line "טיפ" |
total_discount_money | document discountValue (fixed) |
total_tax_money + taxes[].type (INCLUSIVE / ADDITIVE) | vatBp; additive prices are grossed up so the document is tax-included |
total_money | sanity input for the tax mode |
money.currency | currency |
fulfillments[].*_details.recipient | customerName, customerEmail, customerAddress (payment buyer_email_address as fallback) |
tenders[].type / payment.source_type | payment type (CARD, WALLET card; CASH; BANK_ACCOUNT transfer; SQUARE_GIFT_CARD store credit; else other) |
closed_at / created_at | issueDate |
Refunds. refund.id is the refund's own id (redelivery-safe), order_id (else payment_id) resolves to the issued document. amount_money.amount equal to the original document total credits the whole document; any other amount issues a single-line partial credit of exactly that amount. A refund whose original never issued is recorded as error.
Test with curl (the sample order id SAMPLEORDER0000000000000000Z is answered from a fixture, no token needed):
KEY='<signature key>'
URL='https://invoice.slk.co.il/api/billing/ecommerce/square/<hookId>'
BODY='{"merchant_id":"6SSW7HV8K2ST5","type":"payment.updated","event_id":"6a8f5f28-54a1-4eb0-a98a-3111513fd4fc","created_at":"2026-09-20T10:00:06.308Z","data":{"type":"payment","id":"SAMPLEPAYMENT000000000000000Z","object":{"payment":{"id":"SAMPLEPAYMENT000000000000000Z","status":"COMPLETED","source_type":"CARD","order_id":"SAMPLEORDER0000000000000000Z","amount_money":{"amount":21000,"currency":"ILS"},"total_money":{"amount":21000,"currency":"ILS"}}}}}'
SIG=$(printf '%s%s' "$URL" "$BODY" | openssl dgst -sha256 -hmac "$KEY" -binary | base64)
curl -i -X POST "$URL" -H "content-type: application/json" -H "x-square-hmacsha256-signature: $SIG" -d "$BODY"Sources: signature validation, payment.updated, refund.updated, event reference, retrieve order, webhooks overview.
Troubleshooting#
- 401 — ה-Signature key שגוי, או שה-Notification URL ב-Square שונה מהכתובת במסך החיבור (אפילו קו נטוי בסוף או http במקום https). העתיקו את הכתובת שוב, מילה במילה.
- 404 — ה-hookId בכתובת שגוי.
- 502 "חסרים פרטי חיבור" — הדביקו Access token במסך החיבור. Square ינסה שוב עד 24 שעות.
- 502 "פרטי החיבור נדחו" — לאסימון אין הרשאת ORDERS_READ, או שהוא שייך לחשבון Square אחר (Sandbox במקום Production).
- המסמך הופק בלי מע״מ — לא הוגדר מס ב-Square. הגדירו Taxes ושלחו את ההזמנה מחדש.
- החזר לא הפיק חשבונית זיכוי — היומן יציג "error" אם המסמך המקורי לא הופק במערכת. הפיקו אותו ואז הריצו את ההחזר מחדש.
- "blocked" — מכסת המסמכים החודשית או חבילת המנוי. "dormant" — מודול החיוב כבוי.