Документация

Веб-хуки

Веб-хуки отправляют внешним системам уведомления о создании, изменении и удалении данных организации.

Веб-хуки

Создать и настроить точки доставки можно в настройках веб-хуков. Секреты авторизации и секретные заголовки хранятся зашифрованными и не показываются после сохранения.

Какие события отправляются

В настройках выбираются действия: создание, изменение и удаление. Список сущностей отдельно не задается: веб-хук получает все поддерживаемые изменения организации, которые подходят под выбранные действия. Финансовые события отправляются на тех же условиях: FinanceOperation — операции, FinanceObligation — обязательства, FinanceRecurring — регулярные шаблоны, FinanceCategory — категории, FinanceMethod — способы оплаты. Например, finance_operation.create сообщает о новой операции, finance_obligation.update — об изменении расчёта.

ДействиеСобытиеДанные
Создание*.createВ payload передается новое состояние объекта в after.
Изменение*.updateВ payload передаются before, after и changed; customFields детализируется по uid полей, остальные JSON-поля передаются целиком.
Удаление*.deleteВ payload передается последнее известное состояние объекта в before. При отмене финансовой операции событие finance_operation.delete также содержит after со state=cancelled: сама операция сохраняется в истории. Замена операции создаёт update прежнего ID и create новых операций, а не delete.

Авторизация и заголовки

Для точки доставки можно выбрать без авторизации, Bearer token или Basic auth. Также можно добавить обычные и секретные заголовки. Секретные значения не возвращаются в интерфейс после сохранения.

HTTP-запрос

Веб-хуки доступны на действующем тарифе «Бизнес» и отправляются POST-запросом на указанный URL. Используйте публичный HTTPS-адрес: .local, localhost и внутренние адреса не подходят. Тело запроса — JSON. Ответ с HTTP-статусом 2xx считается успешной доставкой. Финансовое событие становится доступным для отправки после успешного сохранения всей операции; ошибка сохранения очереди откатывает изменения.

ЗаголовокЗначение
Content-TypeВсегда application/json; charset=utf-8.
X-Nakogda-EventНазвание события, например clients.update.
X-Nakogda-DeliveryУникальный идентификатор доставки. Используйте его для дедупликации.
X-Nakogda-SignatureДобавляется, если задан секрет подписи.
AuthorizationДобавляется при Bearer token или Basic auth.

Формат payload

Поле event состоит из имени сущности и действия. before и after добавляются только когда соответствующее состояние есть в событии. changed заполняется для изменений: обычные поля сравниваются по верхнему уровню, а customFields раскрывается по uid измененных полей. В финансовых событиях cause содержит исходное действие, например save_operation или correct_operation; суммы передаются точными строками с двумя десятичными знаками, ID — числами, schema_version=1 задаёт версию снимка, timezone — часовой пояс дат. Распределения, начисления и история сроков передаются массивами; изменившийся массив приходит целиком.

Пример изменения клиента
{
	"id": 12345,
	"event": "clients.update",
	"type": "update",
	"entity": "Clients",
	"entity_id": 77,
	"organization_id": 12,
	"user_id": 5,
	"api_key_id": null,
	"created_at": "2026-07-08 12:30:00",
	"before": {
		"id": 77,
		"name": "Анна"
	},
	"after": {
		"id": 77,
		"name": "Анна Иванова"
	},
	"changed": {
		"name": {
			"before": "Анна",
			"after": "Анна Иванова"
		}
	}
}

Финансовые события

Финансовые изменения приходят на те же адреса веб-хуков организации и учитывают выбранные действия: создание, изменение и удаление. Отдельно подписываться на финансовые сущности не нужно. Для доставки действуют общие настройки и действующий тариф «Бизнес».

Финансовый API принимает сессию кабинета и стандартные API-ключи с правами их пользователя. Ключ «только чтение» не выполняет финансовые изменения, включая создание платежей по расписанию. Действия ключом сохраняют его api_key_id в событии; исходящие веб-хуки используют общие настройки доставки.

Запросы и ограничения финансового API

Финансовые сущности и события
СущностьСобытияЧто содержит снимок
FinanceOperation
finance_operation.createfinance_operation.updatefinance_operation.delete
Денежная или неденежная операция: сумма, валюта, состояние, собственные распределения allocations и начисления charges, свободный остаток available_credit, сумма возвратов refunded_amount и связи замен replacement_ids.
FinanceObligation
finance_obligation.createfinance_obligation.update
Ожидаемый платёж, долг или расходное обязательство: сумма, срок, состояние, оплачено paid, списано written_off, остаток remaining, распределения и история начислений, сроков и состояний.
FinanceRecurring
finance_recurring.createfinance_recurring.update
Расписание: recurrence_start, recurrence_rule, исключения recurrence_exdates, пауза paused и курсор обработки next_on. Курсор отличается от ближайшей даты платежа next_payment_on в ответе API.
FinanceCategory
finance_category.createfinance_category.update
Категория с действующими для организации названием, направлением, типом и признаком архива. У системной категории сохраняется стабильный логический id.
FinanceMethod
finance_method.createfinance_method.update
Способ оплаты с действующим для организации названием и признаком архива. У системного способа сохраняется стабильный логический id.

before — состояние до первого изменения, after — итоговое состояние после всего действия. При создании нет before, при исчезновении объекта нет after. Для update поле changed содержит пары before/after изменившихся полей. Массивы allocations, charges, terms, states и другие JSON-массивы передаются целиком.

В финансовых снимках суммы — точные десятичные строки с двумя знаками, например "100.00" или "-40.00". Не переводите их в двоичные дробные числа для расчётов. Идентификаторы и version — числа, флаги — логические значения, schema_version=1 — версия формата снимка. Поле timezone задаёт часовой пояс дат и времени, отсутствующая nullable-дата передаётся как JSON null.

cause указывает исходное действие: например, save_operation, allocate, edit_operation, correct_operation, save_recurring или sync_regular. Изменения посещения используют booking_sync, booking_complete, booking_cancel, booking_delete, booking_restore. Финансовое изменение цены сохраняет cause=save_booking_price; правка цены через API записи — cause=price_change. Связанное событие booking.update при изменении цены также использует cause=price_change. Одно действие может создать несколько событий по разным затронутым сущностям.

Какие события ожидать после финансового действия
ДействиеСобытия и результат
Оплата части ожидаемого платежаfinance_operation.create сообщает об оплате, finance_obligation.update — о том, сколько уже оплачено и сколько осталось оплатить. Использованный прежний аванс также может получить finance_operation.update с новым available_credit.
Изменение даты, суммы или правила расписанияfinance_recurring.update и finance_obligation.update для пересчитанных автоматических платежей; новые периоды дают finance_obligation.create. Прошлые платежи, оплаты, ручные условия и отмены пользователя защищены. Перенос начала назад достраивает недостающие периоды по новому правилу.
Пауза и возобновление расписанияfinance_recurring.update меняет paused. Будущие автоматические неоплаченные платежи без ручных изменений получают finance_obligation.update с state=cancelled. Оплаты, ручные условия и отмены пользователя сохраняются. Возобновление восстанавливает допустимые даты с прежними ID через finance_obligation.update; новые допустимые периоды дают finance_obligation.create. Полные календарные дни строго между приостановкой и возобновлением не начисляются, даже при переносе начала назад. Граничные дни сохраняются в часовом поясе организации: короткое выключение и включение не пропускает платёж.
Исключение даты или пропуск платежаИсключённый автоматический период получает finance_obligation.update со state=cancelled, разрешённый пропуск пользователя — со state=skipped. Это не delete. Возврат исключённой даты может восстановить прежний ID автоматического платежа.
Отмена операции или удаление посещенияОтмена операции даёт finance_operation.delete: в before остаётся прежняя операция, в after — state=cancelled, история сохраняется. Удаление посещения само по себе не означает удаление финансовой истории: изменение связанного расчёта приходит отдельно, например finance_obligation.update с cause=booking_delete.
Редактирование или замена операцииРедактирование с сохранением ID даёт finance_operation.update. Замена даёт update прежнего ID со state=replaced и create новых операций; их ID перечислены в replacement_ids. Связанные источники и обязательства получают собственные итоговые события.
Возврат денегВозврат создаёт расходную finance_operation.create и обновляет затронутые расчёты и исходную оплату. Если возврат меняет стоимость посещения, дополнительно приходит booking.update с cause=price_change. Исправление возврата публикует итоговые изменения по тем же правилам.
Архивирование категории или способа оплатыfinance_category.update или finance_method.update с новым признаком archived. Архивирование не является удалением и не стирает прежние операции.

Сокращённый пример одного события об ожидаемом платеже на 100.00 RUB после оплаты 40.00 RUB. Показаны изменившиеся поля и распределение; полный снимок также содержит начисления, историю сроков и состояний. Создание самой оплаты приходит отдельным событием finance_operation.create.

Частичная оплата: оплачено 40.00, остаток 60.00
{
	"id": 12347,
	"event": "finance_obligation.update",
	"type": "update",
	"entity": "FinanceObligation",
	"entity_id": 401,
	"organization_id": 12,
	"user_id": 5,
	"api_key_id": null,
	"created_at": "2026-10-29 12:30:00",
	"cause": "save_operation",
	"before": {
		"id": 401,
		"organization_id": 12,
		"client_id": 77,
		"client_name": "Анна",
		"booking_id": 0,
		"kind": "manual",
		"direction": "income",
		"title": "Оплата услуги",
		"amount": "100.00",
		"currency": "RUB",
		"state": "open",
		"version": 1,
		"due_at": "2026-10-29 00:00:00",
		"paid": "0.00",
		"written_off": "0.00",
		"remaining": "100.00",
		"allocations": [],
		"timezone": "Europe/Moscow",
		"schema_version": 1
	},
	"after": {
		"id": 401,
		"organization_id": 12,
		"client_id": 77,
		"client_name": "Анна",
		"booking_id": 0,
		"kind": "manual",
		"direction": "income",
		"title": "Оплата услуги",
		"amount": "100.00",
		"currency": "RUB",
		"state": "open",
		"version": 1,
		"due_at": "2026-10-29 00:00:00",
		"paid": "40.00",
		"written_off": "0.00",
		"remaining": "60.00",
		"allocations": [
			{
				"id": 901,
				"operation_id": 501,
				"source_credit_id": 501,
				"obligation_id": 401,
				"kind": "payment",
				"amount": "40.00",
				"occurred_at": "2026-10-29 12:30:00",
				"reversed_at": null
			}
		],
		"timezone": "Europe/Moscow",
		"schema_version": 1
	},
	"changed": {
		"paid": {
			"before": "0.00",
			"after": "40.00"
		},
		"remaining": {
			"before": "100.00",
			"after": "60.00"
		},
		"allocations": {
			"before": [],
			"after": [
				{
					"id": 901,
					"operation_id": 501,
					"source_credit_id": 501,
					"obligation_id": 401,
					"kind": "payment",
					"amount": "40.00",
					"occurred_at": "2026-10-29 12:30:00",
					"reversed_at": null
				}
			]
		}
	}
}

События становятся доступны доставке только после успешного сохранения всего финансового действия (COMMIT). Ошибка записи очереди откатывает и действие, и его события. Повтор успешного запроса с прежним request_id, неизменившийся снимок и откатившийся запрос не создают дополнительных событий.

Успешное сохранение не означает успешную HTTP-доставку. Запросы могут повторяться и приходить в другом порядке: очередь не гарантирует FIFO, в том числе для связанных операций и обязательств. После проверки подписи сохраняйте обработанный X-Nakogda-Delivery и отвечайте повторной доставке без повторного применения изменения. Для дедупликации одного события в нескольких точках доставки используйте верхнеуровневый id payload. Одна version сущности для этого не подходит: остатки и курсор могут измениться без её увеличения.

Изменение цены записи

В данных записи price_totals верхнего уровня содержит полный текущий набор цен по валютам: currency — код валюты, amount — строка с двумя десятичными знаками. Этот массив целиком заменяет прежний набор, включая пустой; добавлять к нему валюты из booking_snapshot не нужно. Числовой price_version — версия текущей цены: устаревшая версия не заменяет более новую. Общая цена доступна без модуля «Финансы». Реальное изменение цены в карточке записи или финансовом редакторе, в том числе возврат со снижением цены и его исправление, создаёт один booking.update с cause=price_change и согласованными состояниями before и after.

В примере цена изменена с 9500.00 на 1500.00 RUB. changed.price_totals передаёт полные массивы стоимости до и после операции, changed.price_version — изменение версии. Правка цены сохраняет исторический booking_snapshot услуг. Последующая замена услуг в календаре не меняет уже согласованный вручную или закреплённый финансовым расчётом набор валют. Если цена ещё не согласована и финансового расчёта нет, календарное изменение услуг обновляет текущую цену. Актуальную стоимость всегда берите из price_totals верхнего уровня.

Сохранение той же цены (no-op) и повтор уже выполненного запроса с тем же request_id (replay) сами по себе не создают новое событие. Внешняя доставка существующего события может повторяться: получатель должен устранять дубликаты по верхнеуровневому id события, а не по entity_id записи.

Фрагмент booking.update при изменении цены
{
	"id": 12346,
	"event": "booking.update",
	"type": "update",
	"entity": "Booking",
	"entity_id": 230,
	"organization_id": 12,
	"user_id": 5,
	"api_key_id": null,
	"created_at": "2026-10-26 12:30:00",
	"created_at_iso_string": "2026-10-26T12:30:00+03:00",
	"created_at_timezone": "Europe/Moscow",
	"cause": "price_change",
	"before": {
		"id": 230,
		"price_totals": [{ "currency": "RUB", "amount": "9500.00" }],
		"price_version": 2,
		"booking_snapshot": {
			"version": 2,
			"price_totals": [{ "currency": "RUB", "amount": "9500.00" }]
		}
	},
	"after": {
		"id": 230,
		"price_totals": [{ "currency": "RUB", "amount": "1500.00" }],
		"price_version": 3,
		"booking_snapshot": {
			"version": 2,
			"price_totals": [{ "currency": "RUB", "amount": "9500.00" }]
		}
	},
	"changed": {
		"price_totals": {
			"before": [{ "currency": "RUB", "amount": "9500.00" }],
			"after": [{ "currency": "RUB", "amount": "1500.00" }]
		},
		"price_version": { "before": 2, "after": 3 }
	}
}

Подпись

Если указан секрет подписи, НаКогда добавляет HMAC SHA-256 от исходного тела запроса. Принимающая сторона может пересчитать подпись тем же секретом и сравнить значение.

Формат заголовка
X-Nakogda-Signature: sha256=<hex_hmac_sha256>

hex_hmac_sha256 = HMAC_SHA256(raw_request_body, signing_secret)

Повторы и дубли

Одна доставка не отправляется повторно после успешного HTTP-ответа 2xx. Если внешний сервер не ответил, вернул ошибку или соединение оборвалось, доставка повторяется до 106 раз после первого запроса: через 1, 2, 3, 4, 5 и 10 минут, затем еще 100 раз каждые 10 минут. Для защиты от дублей храните обработанные id или X-Nakogda-Delivery на своей стороне.