Перейти к содержимому

Webhooks

Вместо опроса вы можете попросить Accessful отправлять POST-запросом подписанное событие на ваш сервер, как только задача меняет состояние.

Нет ни панели управления, ни эндпоинта регистрации. Вы прикрепляете обратный вызов на каждую загрузку и сами выбираете секрет для подписи — Accessful его не выдаёт.

  • Multipart-загрузка — отправьте поля формы webhookUrl и secret.
  • Загрузка по URL — отправьте JSON-поля callbackUrl и hmacSignature.
Окно терминала
curl -X POST "https://api.accessful.de/api/v1/upload-service/pdf/upload" \
-H "X-API-Key: $ACCESSFUL_API_KEY" \
-F "files=@document.pdf" \
-F "webhookUrl=https://your-app.example.com/hooks/accessful" \
-F "secret=$YOUR_WEBHOOK_SECRET"
type событияСрабатывает, когда
case.runningЗадача начала обработку. Может срабатывать более одного раза (по одному на итерацию).
case.completedРезультат PDF/UA готов к скачиванию.
case.failedОбработка не удалась.
case.canceledКейс был отменён.
case.quota_exceededОтклонено, потому что договорная квота исчерпана.

Состояния queued и quota_pending не доставляются как вебхуки.

Тело запроса — JSON. Content-Type: application/json.

{
"id": "f1d2c3b4-0000-4a1e-8f3c-2d6b5a9e1c40",
"type": "case.completed",
"apiVersion": "2026-06-05",
"occurredAt": "2026-06-05T12:34:56Z",
"data": {
"caseId": "7c2f1e4a-9b0d-4a1e-8f3c-2d6b5a9e1c40",
"fileName": "document.pdf",
"jobStatus": "completed"
}
}
ПолеТипПримечания
idUUIDID события. Используйте его как ключ идемпотентности (см. ниже).
typestringОдин из типов событий выше.
apiVersionstringВерсия контракта (2026-06-05). Зафиксируйте её, чтобы отслеживать изменения.
occurredAtISO-8601Когда событие создано; стабильно между повторными попытками.
data.caseIdUUIDКейс, к которому относится это событие.
data.fileNamestringИмя файла.
data.jobStatusstringСырой статус задачи, напр. completed, failed, canceled, quota_exceeded.

Null-поля опускаются в JSON.

ЗаголовокПримерНазначение
X-Accessful-Signaturet=1749126896,v1=9f86d0…Подпись HMAC — проверяйте именно её
X-Accessful-Webhook-Timestamp1749126896Секунды Unix; то же, что t= выше
X-Accessful-Event-Idf1d2c3b4-…Равен id; ключ идемпотентности
X-Accessful-Event-Typecase.completedМаршрутизация без разбора тела
X-Accessful-Case-Id7c2f1e4a-…ID кейса
X-Accessful-Delivery-Attempt1Счётчик попыток, начиная с 1
X-Signaturen4bQgY…legacy HMAC в base64 только по телу

Заголовок X-Accessful-Signature имеет вид t=<unix>,v1=<hex>. Пересчитайте её и сравните за постоянное время:

  1. Прочитайте t и v1 из заголовка.
  2. Вычислите HMAC-SHA256(secret, "<t>.<сырое тело>") и закодируйте в hex. Подписываемая строка — это временная метка, буквальная точка, затем точное сырое тело запроса — проверяйте до разбора JSON.
  3. Сравните за постоянное время с v1.
  4. При желании отклоняйте, если t старше нескольких минут (защита от повтора).
import crypto from 'node:crypto';
// `rawBody` должен быть точными полученными байтами (напр. express.raw()).
function verify(rawBody, signatureHeader, secret) {
const parts = Object.fromEntries(signatureHeader.split(',').map((p) => p.split('=')));
const expected = crypto
.createHmac('sha256', secret)
.update(`${parts.t}.${rawBody}`)
.digest('hex');
const valid = crypto.timingSafeEqual(Buffer.from(parts.v1), Buffer.from(expected));
const fresh = Math.abs(Date.now() / 1000 - Number(parts.t)) < 300; // 5 мин
return valid && fresh;
}
  • Успех = любой ответ 2xx в пределах тайм-аута (5 с на подключение, 10 с на ответ). Отвечайте быстро, а свою работу выполняйте асинхронно.
  • Сбой (не-2xx, тайм-аут или ошибка соединения) повторяется до 10 попыток с экспоненциальной выдержкой и джиттером — примерно 10s → 30s → 1,5m → 4,5m → 13,5m → 40m → 2h, затем ограничивается 6h, минус до 20 % джиттера. Всё окно охватывает несколько часов.
  • После 10 неудачных попыток событие прекращают доставлять. Обратитесь в поддержку для повторной доставки.
  • Идемпотентность: одно и то же событие может прийти более одного раза (напр. повторная попытка после того, как ваш эндпоинт уже успешно ответил). Дедуплицируйте по X-Accessful-Event-Id — он стабилен при каждой повторной попытке.