wire docs

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 now
ep = 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 now
const 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 now
curl 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.186

Endpoint-ийнхээ 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 order
import { 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-аар баталгаажуул.

Энэ хуудсанд