Square - платёжная платформа для малого и среднего бизнеса: терминалы, онлайн-платежи, инвойсы, подписки. Популярна в США, Канаде, Австралии, Великобритании, Японии. Для B2B SaaS и сервисных компаний Square предлагает Payment Links и Invoices API - выставить счёт и принять оплату без физического терминала. Кастомная интеграция с Kommo позволяет создавать платёжную ссылку прямо из карточки сделки и автоматически переводить сделку в Closed Won после получения оплаты.
Square Payments API работает на основе OAuth 2.0 и nonce-токенов (одноразовых токенов из Web Payments SDK). Для серверных операций - Payment Links API: создать ссылку, отправить клиенту, получить уведомление о платеже через webhook.
Payment Link (Square) - одноразовая или многоразовая страница оплаты с фиксированной суммой и описанием. Создаётся через API, не требует сайта или POS-терминала.
Проблема: ручное выставление счетов
Типичный процесс без интеграции: сделка закрылась в Kommo -> менеджер открывает Square Dashboard -> вручную создаёт инвойс или Payment Link -> копирует ссылку в Kommo -> ждёт оплаты -> вручную отмечает сделку как оплаченную.
Этот процесс занимает 10-15 минут на каждую сделку. При 20+ сделках в месяц - 3-5 часов на рутину. Оплаченные сделки остаются в статусе “ожидает оплаты” до ручного обновления.
Архитектура интеграции
Kommo: сделка переходит в этап "Выставить счёт"
-> Kommo webhook: leads.status.changed
-> Ваш сервер
Ваш сервер
-> Square API: создать Payment Link
{amount: deal.budget, note: deal.name, kommo_lead_id: deal.id}
-> Kommo API: добавить ссылку в карточку сделки как примечание
Клиент оплачивает -> Square
-> Square webhook: payment.completed
{order.reference_id: kommo_lead_id}
-> Ваш сервер
-> Kommo API: перевести сделку в Closed Won
-> Kommo API: обновить custom field "Оплачено"
Реализация: создание Payment Link при смене этапа
import requests, uuid, os
from flask import Flask, request, jsonify
app = Flask(__name__)
SQUARE_ACCESS_TOKEN = os.environ["SQUARE_ACCESS_TOKEN"]
SQUARE_LOCATION_ID = os.environ["SQUARE_LOCATION_ID"]
SQUARE_WEBHOOK_SIG = os.environ["SQUARE_WEBHOOK_SIGNATURE_KEY"]
KOMMO_SUBDOMAIN = os.environ["KOMMO_SUBDOMAIN"] # mycompany
KOMMO_TOKEN = os.environ["KOMMO_ACCESS_TOKEN"]
INVOICE_STAGE_ID = int(os.environ["KOMMO_INVOICE_STAGE_ID"])
CLOSED_WON_STAGE_ID = int(os.environ["KOMMO_CLOSED_WON_STAGE_ID"])
SQUARE_BASE = "https://connect.squareup.com/v2"
SQUARE_HDR = {
"Authorization": f"Bearer {SQUARE_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Square-Version": "2024-05-15",
}
KOMMO_BASE = f"https://{KOMMO_SUBDOMAIN}.kommo.com/api/v4"
KOMMO_HDR = {
"Authorization": f"Bearer {KOMMO_TOKEN}",
"Content-Type": "application/json",
}
def get_lead(lead_id: int) -> dict:
r = requests.get(
f"{KOMMO_BASE}/leads/{lead_id}",
headers=KOMMO_HDR,
params={"with": "contacts,custom_fields_values"},
)
return r.json()
def create_payment_link(amount_usd: float, note: str, reference_id: str) -> str:
# Square работает в центах
amount_cents = int(amount_usd * 100)
payload = {
"idempotency_key": str(uuid.uuid4()),
"quick_pay": {
"name": note,
"price_money": {"amount": amount_cents, "currency": "USD"},
"location_id": SQUARE_LOCATION_ID,
},
"checkout_options": {
"redirect_url": "",
"ask_for_shipping_address": False,
},
"pre_populated_data": {},
"payment_note": reference_id, # kommo_lead_id для обратной ссылки
"order": {
"reference_id": reference_id, # вернётся в webhook
},
}
r = requests.post(f"{SQUARE_BASE}/online-checkout/payment-links", headers=SQUARE_HDR, json=payload)
r.raise_for_status()
return r.json()["payment_link"]["url"]
def add_note_to_lead(lead_id: int, text: str):
requests.post(
f"{KOMMO_BASE}/notes",
headers=KOMMO_HDR,
json=[{
"entity_id": lead_id,
"entity_type": "leads",
"note_type": "common",
"params": {"text": text},
}],
)
@app.route("/webhooks/kommo", methods=["POST"])
def kommo_webhook():
data = request.json or {}
for lead_data in data.get("leads", {}).get("status", []):
lead_id = lead_data.get("id")
new_status = lead_data.get("status_id")
if new_status != INVOICE_STAGE_ID:
continue
lead = get_lead(lead_id)
budget = lead.get("price", 0) or 0
name = lead.get("name", f"Сделка #{lead_id}")
if budget <= 0:
add_note_to_lead(lead_id, "Square: сумма сделки не указана. Создайте Payment Link вручную.")
continue
link = create_payment_link(
amount_usd=float(budget),
note=name,
reference_id=str(lead_id),
)
add_note_to_lead(lead_id, f"Square Payment Link создан: {link}")
return jsonify({"status": "ok"}), 200
Реализация: webhook при успешной оплате
import hmac, hashlib, base64
def verify_square_signature(body: bytes, signature: str, sig_key: str, url: str) -> bool:
# Square HMAC-SHA256: base64(hmac(url + body, key))
msg = (url + body.decode("utf-8")).encode("utf-8")
secret = sig_key.encode("utf-8")
digest = hmac.new(secret, msg, hashlib.sha256).digest()
computed = base64.b64encode(digest).decode()
return hmac.compare_digest(computed, signature)
@app.route("/webhooks/square", methods=["POST"])
def square_webhook():
sig = request.headers.get("x-square-hmacsha256-signature", "")
full_url = request.url # должен совпадать с URL в Square Developer Dashboard
if not verify_square_signature(request.data, sig, SQUARE_WEBHOOK_SIG, full_url):
return jsonify({"error": "invalid signature"}), 401
event = request.json or {}
if event.get("type") != "payment.completed":
return jsonify({"status": "ignored"}), 200
payment = event.get("data", {}).get("object", {}).get("payment", {})
order_ref = payment.get("order_id", "")
# reference_id хранится в order, нужен отдельный запрос
order_id = payment.get("order_id", "")
if order_id:
r_order = requests.get(f"{SQUARE_BASE}/orders/{order_id}", headers=SQUARE_HDR)
order = r_order.json().get("order", {})
kommo_id = order.get("reference_id", "")
else:
kommo_id = ""
if not kommo_id:
return jsonify({"status": "no_lead_id"}), 200
amount_cents = payment.get("amount_money", {}).get("amount", 0)
amount_usd = amount_cents / 100.0
# Перевести сделку в Closed Won
requests.patch(
f"{KOMMO_BASE}/leads/{kommo_id}",
headers=KOMMO_HDR,
json={"status_id": CLOSED_WON_STAGE_ID},
)
# Добавить примечание об оплате
add_note_to_lead(
int(kommo_id),
f"Square: получена оплата ${amount_usd:.2f}. Payment ID: {payment.get('id', '')}",
)
return jsonify({"status": "ok"}), 200
Настройка Square Developer Portal
- Перейти на https://developer.squareup.com/ -> Applications -> создать App
- Получить Access Token (Production или Sandbox для тестирования)
- Получить Location ID: Square Dashboard -> Locations
- Webhooks: Developer Portal -> Webhooks -> Add endpoint
- URL:
https://your-server.com/webhooks/square - Events:
payment.completed,payment.failed,order.updated
- URL:
- Скопировать Signature Key из настроек webhook
Реальный кейс
Консалтинговое агентство, 6 менеджеров, средний чек $2 400, 25 сделок в месяц. Square использовался как основной инструмент сбора платежей, Kommo - для ведения воронки. Без интеграции: менеджеры тратили 2-3 часа в неделю на создание Payment Links и обновление статусов.
После интеграции: Payment Link создаётся автоматически при переводе сделки в этап “Выставить счёт”. После оплаты сделка переходит в Closed Won без участия менеджера. Экономия: ~2.5 часа в неделю на команду.
Для кого актуально
Сервисные компании и B2B SaaS в США, Канаде, Австралии, работающие через Square как основной платёжный инструмент. Особенно если средний чек $500-5000 и команда продаж 3-15 человек.
Если компания использует другой платёжный gateway - аналогичный подход описан для Kommo + Stripe и Kommo + Paddle.
Часто задаваемые вопросы
Поддерживает ли Square рекуррентные платежи (подписки)?
Да. Square Subscriptions API: POST /v2/subscriptions с plan_variation_id и card_id. Карту клиента нужно сохранить предварительно через Web Payments SDK. Для B2B SaaS с ежемесячными платежами - полноценная альтернатива Stripe Billing.
В каких странах работает Square?
США, Канада, Австралия, Великобритания, Япония, Ирландия, Франция, Испания. Для ЕС в целом Square менее распространён - там лучше подойдут Stripe, Mollie или Checkout.com.
Как тестировать без реальных платежей?
Square предоставляет Sandbox окружение с отдельными API-ключами. Sandbox Access Token и Location ID получаются в Developer Dashboard отдельно от Production. Тестовые карты: 4111 1111 1111 1111 (Visa), CVV любые 3 цифры.
Итог
Kommo + Square - автоматизация приёма платежей из воронки:
- Kommo webhook
leads.status.changed-> создать Square Payment Link order.reference_id=kommo_lead_idдля корреляции- Square webhook
payment.completed-> Closed Won + примечание - HMAC-SHA256 верификация:
base64(hmac(url + body, sig_key)) - Идемпотентность: UUID
idempotency_keyпри создании платежа
Если ваша команда использует Square и Kommo - опишите задачу команде Exceltic.dev. Реализуем интеграцию под ваш стек.