Загрузка
Не опрашивайте статус в цикле: передайте webhook_url в запросе — и мы отправим подписанное уведомление на ваш сервер, как только картинка готова или не получилась.
Каждое уведомление подписано этим секретом: HMAC-SHA256 от времени и тела. Один секрет на аккаунт, для всех ключей и всех уведомлений. Он не то же самое, что API-ключ.
whsec_••••••••••••••••••••••••••••••••Отправим на ваш адрес подписанное тестовое событие test: true — один раз, без повторов. Не чаще одного раза в 30 секунд.
Результат появится здесь и первой строкой в журнале ниже.
X-Timestamp, точка, тело.whsec_ — и добавьте префикс sha256=.X-Webhook-Signature-256 за постоянное время. Старше 300 секунд по X-Timestamp — отклоняйте.import hashlib, hmac, re, time TOLERANCE_SECONDS = 300 def verify_webhook(secret: str, timestamp: str, raw_body: bytes, signature: str) -> bool: if not secret or not isinstance(raw_body, bytes): return False if not re.fullmatch(r"[0-9]{1,12}", timestamp or ""): return False if not re.fullmatch(r"sha256=[0-9a-f]{64}", signature or ""): return False if abs(time.time() - int(timestamp)) > TOLERANCE_SECONDS: return False expected = "sha256=" + hmac.new( secret.encode("utf-8"), timestamp.encode("ascii") + b"." + raw_body, hashlib.sha256, ).hexdigest() return hmac.compare_digest(expected, signature)
import { createHmac, timingSafeEqual } from "node:crypto"; const TOLERANCE_SECONDS = 300; function verifyWebhook(secret, timestamp, rawBody, signature) { if (!secret || !Buffer.isBuffer(rawBody)) return false; if (!/^[0-9]{1,12}$/.test(timestamp)) return false; if (!/^sha256=[0-9a-f]{64}$/.test(signature)) return false; if (Math.abs(Date.now() / 1000 - Number(timestamp)) > TOLERANCE_SECONDS) return false; const expected = "sha256=" + createHmac("sha256", Buffer.from(secret, "utf8")) .update(timestamp + ".", "ascii") .update(rawBody) .digest("hex"); return timingSafeEqual(Buffer.from(expected, "ascii"), Buffer.from(signature, "ascii")); }
Разбирайте JSON только после успешной проверки. Во время замены секрета подпись может сойтись с текущим или с ещё принимаемым прежним секретом.
X-Webhook-Eventcreation.completed или creation.failedX-Webhook-Delivery-IDX-TimestampX-Webhook-Signature-256sha256= и подпись, 64 символа