Skip to content

Вебхуки данных ​

Вебхуки позволяют Bito сообщать вам об изменениях данных клиента, чтобы не приходилось опрашивать API. Адрес назначения появляется двумя путями:

  • webhook_uri в интеграции — Bito подписывает его автоматически при каждой установке;
  • webhook/subscribe — через Integration API, по каждому адресу отдельно, с выбранными вами событиями.

webhook_uri: автоматическая подписка ​

Если в интеграции указан webhook_uri, при каждой установке интеграции Bito подписывает этот адрес на события create, update и delete следующих коллекций: currencies, customers, trades, users, productCategories, products, unitsOfMeasure, saleOrders, invoices, transactions, purchases, purchaseReturns, purchaseOrders.

status_change этим путём не отправляется — если он нужен, подпишитесь отдельно через webhook/subscribe. Удаление интеграции удаляет эту подписку, повторная установка создаёт её заново.

Список доступных событий ​

POST /integration/api/v2/webhook/events возвращает всё, на что можно подписаться. Имена событий — <коллекция>.<действие>.

Response (сокращённо)

json
{
    "code": 0,
    "data": [
        {
            "collection_name": "saleOrders",
            "actions": ["create", "update", "delete", "status_change"],
            "events": [
                "saleOrders.create",
                "saleOrders.update",
                "saleOrders.delete",
                "saleOrders.status_change"
            ]
        },
        {
            "collection_name": "customers",
            "actions": ["create", "update", "delete"],
            "events": ["customers.create", "customers.update", "customers.delete"]
        }
    ],
    "time": "2025-01-15T10:30:00.000Z"
}
ДействиеКогда срабатывает
createЗапись создана
updateЗапись изменена
deleteЗапись удалена
status_changeИзменился статус записи. Доступно только для коллекций, у которых статус вообще есть — какие именно, показывает вызов events.

Подписка ​

POST /integration/api/v2/webhook/subscribe. Вызов работает как upsert в пределах одного destination: повторная отправка заменяет список событий для этого адреса и не трогает остальные ваши адреса.

Request

http
POST /integration/api/v2/webhook/subscribe
api-key: mycompany:9ad41c0e7b3f28d5610ac94e7f1b26d8
Content-Type: application/json

{
    "destination": "https://your-app.example.com/bito/webhook",
    "events": ["saleOrders.create", "saleOrders.status_change", "customers.update"]
}

Response

json
{
    "code": 0,
    "data": {
        "destination": "https://your-app.example.com/bito/webhook",
        "events": ["saleOrders.create", "saleOrders.status_change", "customers.update"],
        "secret": "d7c1904ae5b3268f04ad91c7e63b58f2019ce74db28a1650f3c9e7a84b2d6015"
    },
    "time": "2025-01-15T10:30:00.000Z"
}
ЭндпоинтТелоКто может вызывать
POST webhook/events-Любой авторизованный пользователь интеграции
POST webhook/get-all-Любой авторизованный пользователь интеграции
POST webhook/subscribe{ destination, events[] }Владелец аккаунта или дополнительный владелец
POST webhook/unsubscribe{ destination }Владелец аккаунта или дополнительный владелец

subscribe и unsubscribe проверяют, от чьего имени выполняется запрос: вызов от имени обычного сотрудника через заголовок user_id отклоняется.

Ограничения: не более 100 разных адресов на интеграцию, не более 500 событий в одном вызове subscribe; subscribe и unsubscribe — не чаще 1 запроса в секунду.

Приём доставки ​

Что присылает Bito

http
POST https://your-app.example.com/bito/webhook
account-id: 507f1f77bcf86cd799439011
X-Bito-Signature: t=1736937000,v1=6b1f0a...c94e
Content-Type: application/json

{"collection_name":"saleOrders","action":"status_change","id":"6712f0a9c4d1e87b3a0f9911","organization_id":"6712f0a9c4d1e87b3a0f7788"}

В теле передаётся идентификатор изменившейся записи, а не само изменение. Получите актуальную запись по id через обычные эндпоинты чтения v2, в рамках аккаунта из заголовка account-id.

ЗаголовокКогда естьЗначение
account-idВсегдаАккаунт, в котором произошло событие
X-Bito-SignatureВсегдаПодпись — см. ниже
api-keyТолько у подписки webhook_uriТокен, который Bito сгенерировал для этой подписки. Это не api_key вашей интеграции — не используйте его для вызовов API. Подписки, созданные через webhook/subscribe, заголовок api-key не отправляют.

Bito ждёт ответ 10 секунд и не следует редиректам (3xx). Ответ, не пришедший за 10 секунд или отличный от 2xx, считается неудачной доставкой. Ставьте тяжёлую работу в очередь и сразу возвращайте 2xx.

Проверка подписи ​

X-Bito-Signature имеет вид t=<unix-секунды>,v1=<hex>, где v1 — это HMAC_SHA256(secret, "{t}.{raw_body}"). secret — это секрет вашего клиента (client_secret); subscribe и get-all возвращают именно это значение. Он один для всех аккаунтов и всех адресов, не меняется при повторной установке и меняется только при смене секрета.

Пример проверки

js
import { createHmac, timingSafeEqual } from 'crypto';

// `raw` MUST be the untouched request body bytes. Do NOT JSON.parse and
// re-stringify before verifying -- key order and number formatting will differ
// and the signature will never match.
export function verify(raw: string, header: string, secret: string): boolean {
    const parts = Object.fromEntries(header.split(',').map((p) => p.split('=')));
    const t = parts.t;
    const v1 = parts.v1;
    if (!t || !v1) return false;

    // Reject anything older than 5 minutes to blunt replay.
    if (Math.abs(Math.floor(Date.now() / 1000) - Number(t)) > 300) return false;

    const expected = createHmac('sha256', secret).update(`${t}.${raw}`).digest('hex');
    const a = Buffer.from(expected, 'hex');
    const b = Buffer.from(v1, 'hex');
    return a.length === b.length && timingSafeEqual(a, b);
}

WARNING

Хешируйте сырые байты тела запроса. Это самая частая ошибка при работе с вебхуками Bito. Если вы сделаете JSON.parse и заново сериализуете тело перед вычислением HMAC, байты, которые вы хешируете, разойдутся с теми, что хешировал Bito, как только отличится порядок ключей, пробелы или формат чисел — и подпись никогда не совпадёт. Сначала проверьте подпись по нетронутому телу, и только потом разбирайте JSON.

Чего вебхуки не гарантируют ​

WARNING

  • Одна попытка, без повторов. Нет ни повторной отправки, ни задержек, ни очереди недоставленных. Если ваш адрес недоступен, событие потеряно.
  • Нет гарантии порядка. Доставки могут приходить не по порядку.
  • Массовые операции не создают событий вообще. Массовый импорт и групповые изменения не отправляют вебхуки. Считайте вебхук поводом перечитать данные, а не самими данными, и периодически сверяйтесь полным чтением. Интеграция, полагающаяся на полноту вебхуков, незаметно разойдётся с реальностью.

Bito 2.0 Integration API