Platformada nimadir sodir bo'lganda sizga HTTPS POST keladi. Xuddi shu mexanizm agentni ishga tushirish uchun ham ishlatiladi (run.execute).
curl -X POST $AFAI_BASE_URL/api/v1/webhooks \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"url": "https://acme.uz/afai/hooks",
"events": ["run.succeeded", "run.failed"],
"description": "Hisobot uchun"
}'
Javobda secret bo'ladi (whsec_…) — u faqat shu yerda ko'rsatiladi. Imzoni tekshirish uchun kerak.
Maskalar qo'llanadi: "run.*" — barcha run hodisalari, "*" — hammasi.
| Hodisa | Qachon |
run.created | Ish yaratildi |
run.awaiting_approval | Xavfli tool tasdiq kutmoqda |
run.resumed | Tasdiqdan keyin davom etdi |
run.succeeded | Muvaffaqiyatli tugadi |
run.failed | Xato bilan tugadi |
run.cancelled | Bekor qilindi |
notification.created | Agent bildirishnoma chiqardi |
webhook.disabled | Obuna avtomatik o'chirildi |
webhook.test | Sinov tugmasi bosildi |
custom.* | emit_event tool'i orqali agent chiqargan |
Payload:
{
"id": "evt_…",
"type": "run.succeeded",
"created_at": "2026-08-14T12:33:36.260536+00:00",
"workspace_id": "ws_…",
"data": { "run_id": "run_…", "app_id": "app_…", "duration_ms": 134 }
}
Har bir so'rovda:
X-AFAI-Signature: t=1786710418,v1=5f0b…c3
X-AFAI-Event: run.succeeded
X-AFAI-Delivery: whd_…
X-AFAI-Attempt: 1
v1 = HMAC-SHA256(secret, "{t}.{xom_tana}").
SDK bilan:
from afai_sdk import verify_signature, InvalidSignature
try:
verify_signature(secret, raw_body, request.headers["X-AFAI-Signature"])
except InvalidSignature as exc:
return 401, str(exc)
import { verifySignature } from "./afai.js";
verifySignature(secret, rawBody, req.headers["x-afai-signature"]);
Qo'lda:
import hashlib, hmac, time
def verify(secret: str, body: bytes, header: str, tolerance: int = 300) -> bool:
parts = dict(p.split("=", 1) for p in header.split(","))
timestamp = int(parts["t"])
if abs(time.time() - timestamp) > tolerance:
return False # replay
expected = hmac.new(secret.encode(), f"{timestamp}.".encode() + body,
hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, parts["v1"])
Uchta tez-tez uchraydigan xato:
1. Parsing qilingan tanani imzolash. Imzo xom baytlar bo'yicha. Express'da express.json() emas, express.raw() ishlating. 2. t ni tekshirmaslik. Bo'lmasa eski so'rovni qayta yuborish mumkin. 3. == bilan solishtirish. compare_digest / timingSafeEqual ishlating.
2xx qaytaring — tana muhim emas. Uzoq ish qilmang: 10 soniya timeout, navbatga qo'yib darhol javob bering.
Muvaffaqiyatsiz bo'lsa jadval bo'yicha qayta urinamiz:
10s → 1m → 5m → 30m → 2s → 6s (jami 6 urinish)
Ketma-ket 5 marta muvaffaqiyatsiz bo'lsa obuna o'chiriladi:
status: "disabled" bo'ladi va last_error yoziladi;webhook.disabled hodisasi paydo bo'ladi;Tuzatgandan keyin:
curl -X POST $AFAI_BASE_URL/api/v1/webhooks/$ID/enable \
-H "Authorization: Bearer $ACCESS_TOKEN"
«Jim o'lgan» webhook eng yomon holat — shuning uchun o'chirish jarayoni
ko'rinadigan qilingan.
Sinov yuborish — «menda ishlamayapti» savolining 80% shu bilan yopiladi:
curl -X POST $AFAI_BASE_URL/api/v1/webhooks/$ID/test \
-H "Authorization: Bearer $ACCESS_TOKEN"
Javobda delivered, response_code, error va (xato bo'lsa) hint bo'ladi.
Tarix:
curl $AFAI_BASE_URL/api/v1/webhooks/$ID/deliveries \
-H "Authorization: Bearer $ACCESS_TOKEN"
Webhook o'rnatolmasangiz (lokal mashina, korporativ tarmoq) — polling:
curl "$AFAI_BASE_URL/api/v1/events?since=evt_…" \
-H "Authorization: Bearer $ACCESS_TOKEN"
Bitta hodisa bir necha marta yetib borishi mumkin (masalan javob kechikkan, biz qayta urinib ko'rgan). Shuning uchun X-AFAI-Delivery yoki event.id bo'yicha takrorlanishni o'zingiz filtrlang:
if already_processed(event["id"]):
return 200
(SSRF himoyasi, docs/SECURITY.md §4).
har kim sizga soxta «to'lov o'tdi» yubora oladi.