Перейти до змісту

Вебхуки

Замість опитування — підпишіться на події, і HugeProfit POST-итиме їх на ваш URL у реальному часі. Доставки зберігаються в надійній черзі, підписуються та ретраяться при збої.

Як це працює

  1. Ви створюєте підписку: подія + цільовий URL (+ опційний секрет).
  2. Коли подія стається будь-де в системі, ми ставимо в чергу доставку.
  3. Диспетчер POST-ить підписане тіло на ваш URL.
  4. На будь-яку не-2xx / мережеву помилку — ретрай із backoff, до 5 спроб.

Каталог подій

GET /webhooks/events повертає актуальний список. Поточні події:

Подія Спрацьовує коли
sms клієнту надіслано SMS
order_create створено продаж
order_update змінено продаж: відредаговано, змінився статус (зокрема від відстеження доставки — посилка прибула, отримана, повертається), додано ТТН
order_delete видалено продаж
product_update створено або оновлено товар
client_update створено або оновлено клієнта
stock_update змінився залишок товару

order_* = продажі

Події order_* спрацьовують на життєвому циклі продажу (/sales), а не на замовленнях із маркетплейсів (/orders).

Підписки

Метод Шлях Scope
GET /webhooks webhooks:read
POST /webhooks webhooks:write
GET /webhooks/{id} webhooks:read
PUT /webhooks/{id} webhooks:write
DELETE /webhooks/{id} webhooks:write
GET /webhooks/events webhooks:read
GET /webhooks/deliveries webhooks:read
POST /webhooks/test webhooks:write

Створення:

curl -X POST https://crm.h-profit.com/bapi-v2/webhooks \
  -H "Authorization: hp_live_ваш_ключ" \
  -H "Content-Type: application/json" \
  -d '{ "event": "stock_update", "url": "https://yoursite.com/hooks/stock",
        "description": "синк залишків" }'

Відповідь повертає згенерований secret один раз — збережіть його, він потрібен для перевірки підпису. Пізніші списки показують лише замаскований secret_hint.

{
  "id": 5, "event": "stock_update", "url": "https://yoursite.com/hooks/stock",
  "is_active": true, "description": "синк залишків",
  "has_secret": true, "secret_hint": "whsec_0L2T1…",
  "secret": "whsec_0L2T1ARi6Ug8C7VBea-e0NJ-…", "created_at": 1784556220
}

Можна передати власний secret, кастомні headers (об'єкт) та is_active. PUT оновлює будь-що з цього; передача secret ротує його.

url має бути http(s)-адресою в публічному інтернеті: localhost, приватні мережі (10.*, 192.168.*, …) і link-local адреси відхиляються з 422; домен, що резолвиться в таку адресу, не пройде під час доставки. Редиректи не виконуються — 3xx рахується невдалою спробою.

Тіло доставки

Кожна доставка POST-ить таке JSON-тіло:

{
  "id": "b3f1…-uuid",
  "event": "stock_update",
  "created_at": 1784556220,
  "data": { "products": [ { "pid": 123, "mid": 8562, "stock": 7, "price": "10.00" } ] }
}

Із заголовками:

Заголовок Значення
X-GP-Event назва події
X-GP-Delivery UUID доставки (також data.id) — для ідемпотентності
X-GP-Signature підпис (якщо підписка має секрет)

Форма data по подіях: stock_update → { products: [...] }; order_* → { id, action, order_number, status, tracking_number, external_id }; client_update → { id, action, phone, name }; product_update → { id, action, name } або { action: "imported", count, source }; sms → { phone, order_id, order_status, message }.

action у order_update: status_changed (з previous_status) або updated; після редагування продаж має новий id, а previous_id — старий. external_id — ваш номер замовлення, переданий під час створення (null, якщо не передавали):

{ "id": 4605, "action": "status_changed", "order_number": "20072602", "status": "arrived",
  "previous_status": "delivering", "tracking_number": "20450000000001", "external_id": "site-1001" }

Перевірка підпису

Якщо підписка має секрет, ми підписуємо сире тіло:

X-GP-Signature: t=1784556220,v1=3f8a...hex

v1 — це HMAC_SHA256(secret, "<t>.<raw_body>"). Щоб перевірити:

  1. Розберіть t та v1 із заголовка.
  2. Перерахуйте HMAC_SHA256(secret, t + "." + raw_request_body).
  3. Порівняйте в constant time; відхиліть, якщо відрізняється.
  4. Відхиліть, якщо t старіший за ~5 хвилин (захист від replay).
import hmac, hashlib, time

def verify(secret, raw_body, header, tolerance=300):
    parts = dict(p.split("=", 1) for p in header.split(","))
    t = int(parts["t"])
    if abs(time.time() - t) > tolerance:
        return False
    expected = hmac.new(secret.encode(), f"{t}.{raw_body}".encode(), hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, parts["v1"])

Ретраї та backoff

Відповідайте 2xx для підтвердження. Будь-який інший статус (або таймаут/мережева помилка) запускає ретрай:

Спроба Пауза до наступної
1 → 2 1 хвилина
2 → 3 5 хвилин
3 → 4 15 хвилин
4 → 5 30 хвилин
після 5 позначається dead

Таймаут доставки — 15 секунд. Доставка — at-least-once — дедуплікуйте за X-GP-Delivery.

Журнал доставок

GET /webhooks/deliveries повертає історію доставок (фільтри webhook_id, status):

{
  "id": "b3f1…-uuid", "webhook_id": 5, "event": "stock_update",
  "status": "success", "attempt": 1, "max_attempts": 5,
  "response_code": 200, "error": null, "duration_ms": 84,
  "next_retry_at": null, "created_at": "2026-07-20T…"
}

status — одне з pending, success, failed (буде ретрай), dead (здалися).

Тестування ендпоінта

POST /webhooks/test доставляє зразкове тіло синхронно і повертає сирий результат — зручно під час налаштування приймача. Передайте наявний webhook_id або разовий url (+ опційно secret, event, data):

curl -X POST https://crm.h-profit.com/bapi-v2/webhooks/test \
  -H "Authorization: hp_live_ваш_ключ" \
  -H "Content-Type: application/json" \
  -d '{ "webhook_id": 5, "data": { "ping": 1 } }'
{ "ok": true, "response_code": 200, "response_body": "…", "duration_ms": 84,
  "sent_signature": "t=…,v1=…", "sent_body": { /* конверт, який ми надіслали */ } }

Найкращі практики

  • Перевіряйте підпис на кожному запиті.
  • Повертайте 2xx швидко (до 15с); важку роботу робіть асинхронно.
  • Дедуплікуйте за X-GP-Delivery — та сама подія може прийти кілька разів.
  • Нова підписка може стати активною до ~30с на всіх продюсерах.