Webhooks
Event-ийг найдвартай хүлээн авч, payload бүрийн signature-ийг шалга.
Webhook нь ямар нэг зүйл болоход — хамгийн чухал нь төлбөр амжилттай болоход —
Wire таны сервер рүү мэдэгдэх боломж олгоно. Зөвхөн checkout redirect-д хэзээ
ч бүү найд; баталгаажуулсан payment_intent.succeeded webhook-г үнэний эх
сурвалж болгон үзэж, server талд баталгаажуул.
Webhook нь нэмэлт — төлбөр баталгаажихад шаардлагатай биш. Тохируулаагүй ч Wire өөрөө оператороос статусыг шалгаж PaymentIntent-ээ шинэчилдэг тул төлбөр зөв бүртгэгдэнэ. Webhook нь зүгээр л «болмогц мэдэгдэх» суваг: түүнгүй бол статусаа API-аас өөрөө татаж авна.
1. Endpoint бүртгэх
Нийтийн HTTPS URL руу чиглэсэн webhook endpoint үүсгэ. Гарын үсгийн нууц
(whsec_… угтвартай) нь үүсгэх үед зөвхөн нэг удаа буцаагдана — аюулгүй
хадгал.
ep, err := client.WebhookEndpoints.Create(ctx, &wire.WebhookEndpointCreateParams{
URL: "https://yourshop.mn/webhooks/wire",
EnabledEvents: []string{"payment_intent.succeeded"},
IdempotencyKey: "wh-ep-1",
})
fmt.Println(ep.Secret) // whsec_... — shown only nowep = client.webhook_endpoints.create(
url="https://yourshop.mn/webhooks/wire",
enabled_events=["payment_intent.succeeded"],
idempotency_key="wh-ep-1",
)
print(ep.secret) # whsec_... — shown only nowconst ep = await wire.webhookEndpoints.create({
url: "https://yourshop.mn/webhooks/wire",
enabled_events: ["payment_intent.succeeded"],
idempotencyKey: "wh-ep-1",
});
console.log(ep.secret); // whsec_... — shown only nowcurl https://api.wire.mn/v1/webhook_endpoints \
-H "Authorization: Bearer sk_live_..." \
-H "Idempotency-Key: wh-ep-1" \
-d url=https://yourshop.mn/webhooks/wire \
-d "enabled_events[]=payment_intent.succeeded"Event нь verified ба enabled хоёулаа болсон endpoint руу л dispatch хийгдэнэ. Шинээр үүсгэсэн endpoint нь live event хүлээн авахаас өмнө verify хийгдсэн байх ёстой.
Event нь өөрийг нь үүсгэсэн project-ийн endpoint руу очно. Хэрэв танд хэд хэдэн project байгаа бол (жишээ нь сайт тус бүрд нэг) тэдгээр нь бие биенийхээ event-ийг хүлээн авахгүй.
Project бүр яг нэг идэвхтэй webhook endpoint-той. Шинэ хаяг руу шилжихдээ одоогийнхоо URL-ыг шинэчилнэ (эсвэл эхлээд устгана) — энэ хязгаарыг өгөгдлийн сан өөрөө барьдаг тул нэг event хоёр хаяг руу салаалах боломжгүй. Хоёр тусдаа систем рүү event хэрэгтэй бол хоёр project үүсгэ.
2. Endpoint-оо баталгаажуулах
Шинээр үүсгэсэн endpoint pending төлөвтэй байна. Баталгаажуулахад Wire
таны URL руу endpoint.verification төрлийн гарын үсэгтэй ping илгээнэ:
2xx хариулбал endpoint verified болж live event хүлээн авч эхэлнэ, эс
тэгвэл pending хэвээр үлдэнэ. Ping-ийн signature жинхэнэ delivery-тэйгээ яг
адил тул доорх шалгах кодоороо шууд угтаж болно.
Аль хэдийн баталгаажсан endpoint-ийн URL-ыг солиход шинэ хаяг эхлээд ping-ээ давах шаардлагатай — түүнийг хүртэл delivery хуучин хаяг руугаа тасралтгүй үргэлжилнэ.
Firewall allowlist
Wire-ийн delivery бүр зөвхөн нэг тогтмол IP-ээс ирнэ:
65.109.117.186Endpoint-ийнхээ firewall / WAF-д энэ хаягийг зөвшөөрч, бусдыг хаа. IP шалгалт нь signature шалгалтыг орлохгүй — хоёуланг нь хий.
3. Signature header
Delivery бүр WirePayment-Signature header авч явна:
WirePayment-Signature: t=1717000000,v1=5257a869e7ec...t— signature үүсгэгдсэн Unix timestamp (секунд).v1— таны endpoint secret (whsec_…)-ээр key хийсэн,"<t>.<rawbody>"string дээрх hex-encoded HMAC-SHA256.
Гараар шалгахдаа: HMAC_SHA256(secret, t + "." + rawBody)-г тооцоолж, hex-encode
хийгээд v1-тэй constant time-аар харьцуул. Timestamp нь таны тэвчээрийн
хязгаараас гадуур байвал delivery-г татгалз (SDK-ууд default-аар 300 секунд).
4. Handler дотроо шалга
Үргэлж raw, задлаагүй request body-гийн эсрэг шалга — эхлээд задалбал байтууд өөрчлөгдөж, signature эвдэрнэ.
func handler(w http.ResponseWriter, r *http.Request) {
body, _ := io.ReadAll(r.Body)
event, err := client.Webhooks.Verify(
body,
r.Header.Get(wire.SignatureHeader),
endpointSecret, // whsec_...
)
if err != nil {
http.Error(w, "bad signature", http.StatusBadRequest)
return
}
if event.Type == "payment_intent.succeeded" {
// fulfill the order
}
w.WriteHeader(http.StatusOK)
}import wire
event = client.webhooks.verify(
request.body, # raw bytes
request.headers[wire.SIGNATURE_HEADER],
endpoint_secret, # whsec_...
)
if event.type == "payment_intent.succeeded":
... # fulfill the orderimport { SIGNATURE_HEADER } from "@buildry-wire/wire";
const event = wire.webhooks.verify(
rawBody, // unparsed request body (string or Buffer)
req.headers[SIGNATURE_HEADER.toLowerCase()],
endpointSecret, // whsec_...
);
if (event.type === "payment_intent.succeeded") {
// fulfill the order
}Шилдэг туршлага
2xx-ээр хурдан хариул, дараа нь хүнд ажлыг асинхроноор хий.- Idempotent бай — ижил event нэгээс олон удаа delivery хийгдэж болно. Event
id-ээр давхардлыг арилга. - Server талд давхар шалга: үнэ өндөртэй захиалга биелүүлэхээс өмнө PaymentIntent-ийн статусыг API-аар баталгаажуул.