# Webhook URL

## ภาพรวม

ฟีเจอร์นี้ส่งข้อมูลของใบแจ้งหนี้ที่ชำระแล้วไปยังเซิร์ฟเวอร์ของร้านค้า มีไว้เพื่อให้ร้านค้าประมวลผลการชำระเงินโดยอัตโนมัติ และส่งมอบสินค้าหรือบริการให้ลูกค้าของคุณ

Webhook URL ตั้งค่าแยกสำหรับแต่ละโปรเจกต์ และชี้ไปยังสคริปต์ตัวจัดการการชำระเงินภายในร้านค้า ที่อยู่ต้องใช้ HTTPS และชื่อโดเมน: ไม่รับที่อยู่ IP และใบรับรองถูกตรวจสอบทุกครั้งที่ส่ง

ทุกครั้งที่สถานะใบแจ้งหนี้เปลี่ยนเป็นชำระแล้ว (Paid) บริการจะส่งคำขอ POST ไปยัง URL นี้ในรูปแบบต่อไปนี้:

```json
{
   "wallet":{
      "id":"47aa71e2-07a0-482e-9172-7114d7376ba0",
      "name":"usdt-tron",
      "blockchain":"tron",
      "cryptocurrency":"usdt",
      "address":"TKbstUwMzLrfTAGL4erYb7gc7ghmHQ9zG7"
   },
   "project":{
      "id":"9deea1e2-0c08-41a3-bdc2-a34eada3892d",
      "name":"My project",
      "commissionPayer":"seller",
      "commissionRate":1
   },
   "invoice":{
      "id":"a4c9e2ee-9a03-43e5-a1a1-00caf679d16a",
      "uid":"AFhygKX21ecd",
      "createDatetime":"2024-02-26 13:29:24",
      "timeToPayDatetime":"2024-02-27 01:29:24",
      "commissionFiatUSD":0.05,
      "amountFiatUSD":5.02,
      "amountFiat":5,
      "calcAmountFiat":5.02,
      "currencyFiat":"USD",
      "description":null,
      "serviceData":null,
      "status":"paid"
   },
   "payment":{
      "id":"f986ad8d-2298-473d-982a-efbc817b975d",
      "amount":5.02,
      "hash":"74763b65e43bcc9492a6ce9a7f26fbfdbd7635aecd3454420b5e9534cba50ee6",
      "transactionDatetime":"2024-02-26 13:32:57"
   }
}
```

การแจ้งเตือนถูกส่งทุกครั้งที่มีการเปลี่ยนเป็นชำระแล้ว — ทั้งเมื่อบริการพบการชำระเงินโดยอัตโนมัติ และเมื่อร้านค้าจับคู่การชำระเงินกับใบแจ้งหนี้ด้วยตนเอง

## พารามิเตอร์คำขอ

| พารามิเตอร์ | คำอธิบาย |
| --- | --- |
| `wallet.id` | ID ของกระเป๋าเงินในรูปแบบ UUID |
| `wallet.name` | ชื่อกระเป๋าเงิน |
| `wallet.blockchain` | บล็อกเชนของกระเป๋าเงินคริปโต |
| `wallet.cryptocurrency` | สกุลเงินคริปโตของกระเป๋าเงิน |
| `wallet.address` | ที่อยู่ของกระเป๋าเงินคริปโต |
| `project.id` | ID ของโปรเจกต์ในรูปแบบ UUID |
| `project.name` | ชื่อโปรเจกต์ |
| `project.commissionPayer` | ผู้จ่ายค่าธรรมเนียมบริการ |
| `project.commissionRate` | อัตราค่าธรรมเนียมเป็น % |
| `invoice.id` | ID ของใบแจ้งหนี้ในรูปแบบ UUID |
| `invoice.uid` | ID ของใบแจ้งหนี้ (สำหรับลูกค้า) |
| `invoice.createDatetime` | วันที่และเวลาที่สร้างใบแจ้งหนี้ (UTC) |
| `invoice.timeToPayDatetime` | วันที่และเวลาที่ใบแจ้งหนี้มีอายุถึงสำหรับลูกค้า (UTC) การค้นหาการชำระเงินดำเนินต่ออีก 1 ชั่วโมงหลังจุดนี้ — เผื่อเครือข่ายที่ช้า ดังนั้นการแจ้งเตือนอาจมาถึงสำหรับใบแจ้งหนี้ที่แสดงเป็นหมดอายุไปแล้ว |
| `invoice.commissionFiatUSD` | จำนวนค่าธรรมเนียมบริการ คำนวณจากจำนวนเงิน `invoice.amountFiatUSD` |
| `invoice.amountFiatUSD` | จำนวนเงินเป็น USD ตอนสร้างใบแจ้งหนี้คำนวณจาก `invoice.amountFiat` ตามอัตราแลกเปลี่ยนปัจจุบัน **ณ เวลาชำระเงินจะถูกเขียนทับด้วยจำนวนเงินที่ได้รับจริง** แปลงเป็น USD ตามอัตราแลกเปลี่ยน ณ ขณะนั้น ค่าธรรมเนียมใน `invoice.commissionFiatUSD` ก็ถูกคำนวณใหม่จากค่านี้ด้วย |
| `invoice.amountFiat` | จำนวนเงินดั้งเดิมของใบแจ้งหนี้ในสกุลเงินเฟียต ไม่เปลี่ยนแปลง |
| `invoice.calcAmountFiat` | จำนวนเงินที่คำนวณในสกุล `invoice.currencyFiat` ตามอัตราแลกเปลี่ยนคริปโต ณ เวลาชำระเงิน อาจต่างจาก `invoice.amountFiat` เพราะลูกค้าอาจชำระใบแจ้งหนี้หลังการสร้างไประยะหนึ่งแทนที่จะชำระทันที ในช่วงเวลานั้น อัตราแลกเปลี่ยนคริปโตเทียบกับ `invoice.currencyFiat` อาจขยับไปทางใดก็ได้ |
| `invoice.currencyFiat` | สกุลเงินเฟียต |
| `invoice.description` | คำอธิบายที่ตั้งไว้ตอนสร้างใบแจ้งหนี้ |
| `invoice.serviceData` | ข้อมูลฝั่งบริการที่ตั้งไว้ตอนสร้างใบแจ้งหนี้ |
| `invoice.status` | สถานะใบแจ้งหนี้ |
| `payment.id` | ID ของการชำระเงินในรูปแบบ UUID |
| `payment.amount` | จำนวนเงินชำระในสกุลเงินคริปโต |
| `payment.hash` | แฮชของธุรกรรม on-chain |
| `payment.transactionDatetime` | วันที่และเวลาของธุรกรรม on-chain (UTC) |

## ลายเซ็นของการแจ้งเตือน

คำขอทุกคำขอถูกเซ็นด้วยคีย์ลับของ Webhook ลายเซ็นเดินทางใน header `X-Timestamp` และ `X-Signature` และช่วยให้แน่ใจว่าการแจ้งเตือนมาจากบริการจริง ไม่ใช่จากบุคคลภายนอกที่รู้ที่อยู่ตัวจัดการของคุณ

ตรวจสอบลายเซ็นก่อนประมวลผลคำสั่งซื้อ กลไกและตัวอย่างสำเร็จรูปอยู่ใน[การตรวจสอบลายเซ็น Webhook](./signature-verification.md)

## คำแนะนำในการจัดการ

**อย่าปฏิเสธการแจ้งเตือนเพียงเพราะกำหนดเวลาชำระเงินผ่านไปแล้ว** การตรวจสอบแบบ “ใบแจ้งหนี้หมดอายุแล้ว การชำระเงินจึงใช้ไม่ได้” ดูสมเหตุสมผลแต่ตัดการชำระเงินจริงทิ้งไปส่วนหนึ่ง: บนเครือข่ายที่ช้า ธุรกรรมอาจได้รับการยืนยันหลังกำหนดเวลา และร้านค้าจับคู่การชำระเงินกับใบแจ้งหนี้ที่หมดอายุด้วยตนเองได้ การแจ้งเตือนนั้นเองคือการยืนยันการชำระเงิน

**ตรวจสอบจำนวนเงินกับฟิลด์ดั้งเดิม** `invoice.amountFiat` นี่คือจำนวนของใบแจ้งหนี้ตามที่ออกไว้ และไม่เปลี่ยนแปลง ส่วนฟิลด์ `amountFiatUSD` สะท้อนจำนวนที่ได้รับจริง และอาจต่างจากจำนวนที่ออกไว้ — ทั้งจากการเคลื่อนไหวของอัตราแลกเปลี่ยนและจากการจับคู่การชำระเงินด้วยตนเอง

**แยกวิเคราะห์จำนวนเงินแบบตัวเลข** ศูนย์ท้ายถูกตัดออก: จำนวน 10.00 มาถึงเป็น 10 ให้จัดรูปแบบเพื่อแสดงผลที่ฝั่งคุณเอง จำนวนที่ต่ำกว่า 0.0001 มาถึงในสัญกรณ์เลขชี้กำลัง เช่น 1.0e-6 — การแยกวิเคราะห์ JSON มาตรฐานคืนตัวเลขที่ถูกต้อง มีเพียงการแยกสตริงด้วยตนเองเท่านั้นที่พัง

**จัดการการแจ้งเตือนแบบ idempotent** การแจ้งเตือนเดียวกันอาจมาถึงซ้ำ — เช่น หากสคริปต์ของคุณประมวลผลการชำระเงินสำเร็จแต่ตอบกลับด้วยโค้ดที่ไม่ใช่ 2xx ก่อนส่งมอบคำสั่งซื้อ ให้ตรวจว่า `invoice.id` นี้ถูกประมวลผลไปแล้วหรือยัง

**Escape ค่าก่อนแสดงผล** ฟิลด์ `invoice.description` และ `invoice.serviceData` ถูกส่งกลับมาตรงตามที่ร้านค้าส่งไว้ทุกประการ หากคุณเรนเดอร์ค่าเหล่านี้ใน HTML ให้ escape ที่ฝั่งคุณเอง

## ตารางการส่ง

เซิร์ฟเวอร์ที่ Webhook URL ต้องตอบกลับด้วยโค้ด HTTP 2xx โค้ดอื่น การหมดเวลา หรือการเชื่อมต่อหลุดนับเป็นการส่งที่ล้มเหลว

ไม่มีการติดตามการเปลี่ยนเส้นทาง: การตอบกลับ 301 หรือ 302 คือการส่งที่ล้มเหลว ไม่ใช่การข้ามไปยังที่อยู่ใหม่ ให้ตั้งที่อยู่สุดท้ายของตัวจัดการ

การเชื่อมต่อมีเวลา 5 วินาที ส่วนคำขอทั้งหมดมี 10 วินาที หากตัวจัดการทำไม่ทันในเวลานี้ การส่งนับเป็นล้มเหลว

หลังการส่งล้มเหลว บริการจะลองส่งใหม่ตามตารางต่อไปนี้:

* 5 นาทีหลังการส่งล้มเหลวครั้งล่าสุด
* หลังจากนั้นอีก 15 นาที
* หลังจากนั้นอีก 30 นาที
* หลังจากนั้นอีก 1 ชั่วโมง
* หลังจากนั้นอีก 3 ชั่วโมง
* หลังจากนั้นอีก 6 ชั่วโมง
* หลังจากนั้นอีก 12 ชั่วโมง
* หลังจากนั้นอีก 24 ชั่วโมง

หลังจากนั้น การพยายามส่งจะหยุดลง

## การปิดใช้งาน Webhook URL

บางครั้งสคริปต์ webhook ของร้านค้าประมวลผลการชำระเงินได้ถูกต้อง แต่ตอบกลับด้วยโค้ด HTTP ที่ไม่ใช่ 2xx ซึ่งทำให้เซิร์ฟเวอร์ของเราลองส่งใหม่บ่อยครั้งตามตารางข้างต้น เพิ่มภาระทั้งกับเซิร์ฟเวอร์ของเราและของคุณ

เพื่อป้องกันกรณีแบบนี้ เรามีกลไกที่ปิดใช้งาน Webhook URL ในโปรเจกต์ หากไม่อยากให้เกิดขึ้น ให้ทำตามขั้นตอนต่อไปนี้:

1. แก้โค้ดตัวจัดการ webhook ของคุณให้ตอบกลับด้วยโค้ด 2xx โดยปกติคือ 200 เมื่อประมวลผลการชำระเงินสำเร็จ ทดสอบด้วยโปรแกรมจำลองใดก็ได้ เช่น Postman
2. ติดต่อฝ่ายสนับสนุนทางเทคนิคเพื่อแก้ไขการตั้งค่า
3. เปิดใช้งาน Webhook URL อีกครั้งในการตั้งค่าโปรเจกต์ แล้วบันทึกโปรเจกต์
