Тригери й відповідь
Флоу має рівно один тригер — саме він визначає, коли флоу запускається.
Вебхук
Кожен флоу з вебхук-тригером має власну адресу з токеном:
POST https://app.oxta.io/webhook/<id флоу>/<токен>
Вихід тригера — headers, query, body, method, path, timestamp. Читайте його за іменем тригера: {{ outputs.incoming.body.title }}.
Тіло розбирається за Content-Type: JSON стає об'єктом, application/x-www-form-urlencoded — об'єктом полів (усі значення рядками), будь-що інше приходить рядком як є. Якщо сервіс надсилає JSON із заголовком форми (так робить, наприклад, WayForPay), тіло все одно розбирається як JSON.
Перевірка підпису
Токен в адресі захищає лише доти, доки адресу ніхто не дізнався. Платіжні системи й магазини додатково підписують кожен запит, і тоді флоу може приймати тільки справжні. Увімкніть це в тригері «Вебхук», блок «Перевірка підпису»:
| Схема | Заголовок | Як перевіряємо |
|---|---|---|
| Загальний HMAC | задаєте самі, типово X-Signature | HMAC сирого тіла: SHA-256, SHA-1 або SHA-512, hex або base64, з префіксом або без (sha256=) |
| WooCommerce | X-WC-Webhook-Signature | base64 HMAC-SHA256 сирого тіла |
| Shopify | X-Shopify-Hmac-Sha256 | base64 HMAC-SHA256 сирого тіла |
| Stripe | Stripe-Signature | hex HMAC-SHA256 від мітка часу.тіло, не старше 5 хвилин |
| GitHub | X-Hub-Signature-256 | sha256= + hex HMAC-SHA256 сирого тіла |
| Monobank (еквайринг) | X-Sign | ECDSA P-256 відкритим ключем банку |
| LiqPay | поле signature у тілі | base64 SHA1 (або SHA3-256) від private_key + data + private_key |
| WayForPay | поле merchantSignature у тілі | hex HMAC-MD5 полів платежу через ; |
Секрет береться лише зі змінної флоу з позначкою «секрет». У тригері зберігається тільки назва змінної, самого значення в налаштуваннях вузла немає. Змінна без позначки «секрет» не підійде.
- WooCommerce. У WooCommerce → Налаштування → Розширені → Webhooks вставте адресу вебхука і в поле «Secret» — те саме значення, що у змінній. Під час збереження WooCommerce надсилає тестовий запит
webhook_id=…без підпису: на нього Oxta відповідає200, але флоу не запускає. Флоу при цьому має бути увімкнене, інакше буде403, і WooCommerce вебхук не збереже. Після п'яти невдалих доставок поспіль WooCommerce сам вимикає вебхук, тож спершу переконайтеся, що підпис проходить. - Monobank. У змінну покладіть токен мерчанта (
X-Token): за ним Oxta сама отримає відкритий ключ банку й запам'ятає його. Можна покласти і сам ключ із/api/merchant/pubkey. Якщо банк змінить ключ, Oxta перечитає його (не частіше ніж раз на 5 хвилин). - Shopify. У змінну — client secret застосунку. Для вебхуків, створених у Налаштування → Сповіщення → Вебхуки, ключ показано там же під списком.
- Stripe. У змінну — signing secret із префіксом
whsec_…зі сторінки вебхука в Stripe (цілком, разом із префіксом). Підписано мітку часу разом із тілом, тож запит, старший за 5 хвилин, відхиляється якexpired— перехоплений запит не вийде повторити. Поки Stripe змінює секрет, у заголовку буває кілька підписів: досить, щоб збігся один. - GitHub. У змінну — той самий Secret, що в налаштуваннях вебхука репозиторію чи організації. Тестовий
ping, який GitHub надсилає одразу після створення вебхука, отримує200без запуску флоу. - LiqPay. Підпис лежить не в заголовку, а в полі
signatureтіла; у змінну —private_key. ПолеdataLiqPay кодує в base64, тож Oxta додає до тіла розкодованийdecoded: статус платежу читайте як{{ outputs.incoming.body.decoded.status }}. Документація LiqPay згадує і SHA1, і SHA3-256 — приймаються обидва. - WayForPay. Підпис лежить у полі
merchantSignature; у змінну —SecretKeyмерчанта. Підписано поляmerchantAccount;orderReference;amount;currency;authCode;cardPan;transactionStatus;reasonCode. WayForPay чекає у відповідь підписанеacceptі без нього повторює сповіщення 4 дні, тому на правильний запит Oxta одразу відповідає{"orderReference", "status": "accept", "time", "signature"}, а флоу виконується у фоні. ВузолResponseі?wait=1у цьому режимі не впливають на відповідь. - Інші сервіси — через загальний HMAC: заголовок, алгоритм, кодування й префікс беруться з документації сервісу.
Запит без правильного підпису отримує 401 з причиною в тілі, і флоу не запускається:
reason | Що це означає |
|---|---|
missing-signature | у запиті немає підпису — ні в заголовку, ні в потрібному полі тіла |
mismatch | підпис не збігся: інший секрет, або тіло змінили дорогою |
expired | підпис Stripe правильний, але запит старший за 5 хвилин |
missing-secret | у збереженому флоу не обрана секретна змінна або вона порожня |
key-unavailable | не вдалося отримати ключ Monobank — перевірте токен |
Відхилені запити не з'являються в історії запусків, бо запуску не було. Останні 20 відмов видно в тому ж блоці тригера з часом і причиною; вміст тіла не зберігається. Кнопка «Перевірити на прикладі» звіряє вставлене тіло й підпис, не запускаючи флоу (для LiqPay і WayForPay достатньо тіла — підпис уже в ньому; старий приклад від Stripe покаже expired). Тіло вставляйте точно як його надіслав сервіс: зайвий пробіл уже дає інший підпис. Зміни налаштувань діють після збереження флоу.
Коли викликач чекає на відповідь
Типово вебхук відповідає {"ok": true} одразу, а флоу добігає у фоні. Якщо потрібна справжня відповідь, викликач просить її в самому запиті:
| Запит | Що буде |
|---|---|
| без сигналу | {"ok": true} одразу, флоу далі у фоні |
?wait=1 | чекаємо на вузол Response і віддаємо його |
Prefer: wait=10 | те саме, стандартом RFC 7240, і 10 секунд як межа |
X-Oxta-Wait: 1 | те саме, якщо адресу змінити не можна |
Prefer: respond-async | не чекати, навіть якщо є ?wait=1 |
Межа очікування — 15 секунд типово, максимум 30. Після неї викликач отримує 504, але флоу не переривається і добігає до кінця.
Відповідь формує вузол Response: статус, заголовки, тіло з {{виразами}}. Перша відповідь виграє — якщо Response є на кількох гілках, візьметься той, що виконався першим. Щоб віддати змістовну помилку, поставте Response на гілку error.
Форма
Тригер «Форма» запускає флоу з полів, які заповнює людина. У вузлі описуються поля: назва, підпис, тип (текст, багаторядковий текст, число, так/ні, вибір із варіантів, дата), обов'язковість. Форма відкривається на сторінці флоу «Запустити» (/flows/<id>/run) і в тестовому запуску в редакторі. Відповіді потрапляють у флоу як input.form.<назва>, уже приведені до типу: число буде числом, прапорець true або false, дата у форматі YYYY-MM-DD. Порожнє обов'язкове поле чи чужий варіант зупиняють запуск ще до старту, помилка показується під полем. Приклад: заявка на відпустку з полями «співробітник», «днів», «з дати» → Slack керівнику → рядок у Google Sheets. Форму поки бачить лише власник акаунта; публічні форми на сайтах з'являться пізніше.
Розклад
Крон-тригер приймає вираз із п'яти полів і зону IANA:
0 9 * * 1-5 о 9:00 у робочі дні
*/15 * * * * кожні 15 хвилин
0 0 1 * * першого числа щомісяця
Дрібніше за хвилину не буває. Зона типово UTC — якщо потрібен Київ, вкажіть Europe/Kyiv, інакше розклад поїде на дві-три години.
Обмеження частоти
У налаштуваннях флоу можна задати ліміт: скільком запитам дозволено пройти за вікно. Понад ліміт вебхук відповідає 429 із Retry-After. Без налаштування діє платформний дефолт: 60 запитів на хвилину на флоу. Додатково всі вебхуки одного акаунта разом не можуть перевищити 600 запитів на хвилину. Для флоу, адреса якого потрапляє в інтернет, варто задати жорсткіший ліміт.