Skip to content
Translated page. The English version is the source of truth.

POST /apiv2/reports/webhooks

ลงทะเบียน URL แล้ว NETTS จะเรียกไปยัง URL นั้นเมื่อรายงานพร้อมใช้งาน แทนที่คุณจะต้องคอยสอบถามสถานะ (polling)

ปลายทางเหล่านี้ถูกแยกต่างหากจาก เว็บฮุกของคำสั่งซื้อ การลงทะเบียนที่นั่นจะไม่ได้เป็นการสมัครรับการแจ้งเตือนรายงาน และในทางกลับกันก็เช่นเดียวกัน รูปแบบข้อมูลที่ส่งผ่านเครือข่าย — ลายเซ็น ส่วนหัว พฤติกรรมการลองใหม่ — เหมือนกันทุกประการ ดังนั้นตัวจัดการ (handler) ที่เขียนขึ้นสำหรับอันหนึ่งจึงสามารถใช้งานร่วมกับอีกอันได้

URL ฐานของปลายทาง

https://netts.io/apiv2/reports/webhooks

ส่วนหัวของคำขอ

ส่วนหัวจำเป็นคำอธิบาย
X-API-KEYใช่คีย์ API จากแดชบอร์ด
X-Real-IPใช่ที่อยู่จากรายการที่อนุญาต (whitelist) ของคีย์

ตัวหลักและตัวสำรอง

สูงสุดสองปลายทางต่อหนึ่งบัญชี primary จะได้รับทุกอย่าง backup จะถูกใช้งานเฉพาะหลังจากที่การส่งไปยังตัวหลักหมดความพยายามแล้วเท่านั้น — และมันจะถูกลงลายเซ็นด้วยรหัสลับของมันเอง ไม่ใช่ของตัวหลัก

การลงทะเบียน

bash
curl -s -X POST 'https://netts.io/apiv2/reports/webhooks' \
  -H 'X-API-KEY: your-api-key' \
  -H 'X-Real-IP: 203.0.113.10' \
  -H 'Content-Type: application/json' \
  -d '{"url": "https://example.com/netts/reports", "role": "primary"}'
json
{
  "status": "success",
  "code": 10000,
  "data": {
    "id": 1,
    "url": "https://example.com/netts/reports",
    "role": "primary",
    "is_active": true,
    "created_at": "2026-09-06 17:05:12+00:00",
    "updated_at": "2026-09-06 17:05:12+00:00",
    "secret": "whsec_<64 hex characters>"
  }
}

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

bash
curl -s -X POST 'https://netts.io/apiv2/reports/webhooks/1/rotate-secret' \
  -H 'X-API-KEY: your-api-key' -H 'X-Real-IP: 203.0.113.10'

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

การจัดการ

วิธีการเส้นทางการดำเนินการ
GET/apiv2/reports/webhooksดูรายการของคุณ โดยไม่มีรหัสลับ
GET/apiv2/reports/webhooks/{id}อ่านค่ารายการเดียว
PATCH/apiv2/reports/webhooks/{id}เปลี่ยน url หรือหยุดชั่วคราวด้วย is_active: false
DELETE/apiv2/reports/webhooks/{id}ลบออก

URL ต้องเป็น HTTPS สาธารณะ ที่อยู่แบบ Loopback, ที่อยู่ส่วนบุคคล และ link-local จะถูกปฏิเสธ รวมถึงข้อมูลประจำตัวภายใน URL ด้วยเช่นกัน สิ่งใดก็ตามที่ถูกปฏิเสธจะส่งกลับมาเป็น 422 พร้อมเหตุผล การตรวจสอบนี้จะทำงานอีกครั้งทันทีก่อนการส่งข้อมูลแต่ละครั้ง ดังนั้นปลายทางที่ภายหลังแปลงค่าไปเป็นที่อยู่ส่วนบุคคลจะหยุดรับข้อมูล

สิ่งที่เราส่งให้

json
{
  "event": "report.ready",
  "delivery_id": 4,
  "order_id": "REPxxxxxxxxxxxx",
  "order_type": "statement",
  "client_request_id": "stmt-2026-09-usdt",
  "status": "done",
  "format": "csv",
  "download_url": "/apiv2/reports/REPxxxxxxxxxxxx/download",
  "expires_at": "2026-10-06 15:48:04+00:00",
  "artifact": { "sha256": "…", "size_bytes": 696 },
  "confirmed_at": "2026-09-06T15:48:04Z"
}
ฟิลด์คำอธิบาย
eventreport.ready — คีย์สำหรับกำหนดเส้นทางไปยังตัวจัดการของคุณ
delivery_idคีย์สำหรับกรองข้อมูลซ้ำ ส่งมาในส่วนหัว X-Netts-Delivery ด้วยเช่นกัน
order_idหมายเลขคำสั่งซื้อที่คุณได้รับเมื่อส่งรายงานเข้าคิว
order_typestatement หรือ balance_at_date
download_urlเส้นทางสำหรับดาวน์โหลดไฟล์ ซึ่งสัมพันธ์กับ https://netts.io
artifact.sha256ค่า Checksum เพื่อให้คุณสามารถตรวจสอบไฟล์ที่ดาวน์โหลดมาได้
confirmed_atUTC

การประทับเวลาทั้งหมดเป็นรูปแบบ UTC

การตรวจสอบความถูกต้องของลายเซ็น

X-Netts-Signature: sha256=<hex>
X-Netts-Timestamp: <unix seconds>
X-Netts-Delivery:  <delivery_id>

ลายเซ็นคือ HMAC-SHA256 บน "<timestamp>." + raw body ซึ่งคำนวณด้วยรหัสลับของปลายทางที่ได้รับคำขอ ให้เปรียบเทียบข้อมูลแบบเวลาคงที่ (constant time) และปฏิเสธสิ่งใดก็ตามที่มีการประทับเวลาอยู่นอกช่วง ±5 นาที

python
import hmac, hashlib, time

def verify(raw_body: bytes, sig_header: str, ts_header: str, secret: str) -> bool:
    if abs(time.time() - int(ts_header)) > 300:      # ป้องกัน replay
        return False
    signed = f"{ts_header}.".encode() + raw_body
    expected = "sha256=" + hmac.new(secret.encode(), signed, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, sig_header)

ลงลายเซ็นด้วยรหัสลับของ URL ที่คำขอส่งมาถึง: ตัวหลักและตัวสำรองมีรหัสลับที่แตกต่างกัน

การส่งข้อมูลเป็นแบบส่งอย่างน้อยหนึ่งครั้ง (at-least-once)

การตอบกลับที่ขาดหายไปจะทำให้เกิดการลองใหม่ ดังนั้นเหตุการณ์เดิมอาจถูกส่งมาซ้ำสองครั้งได้

  1. กำจัดข้อมูลซ้ำด้วย delivery_id การส่งซ้ำจะต้องไม่มีผลกระทบต่อระบบฝั่งคุณ (no-op)
  2. ตรวจสอบความถูกต้องของลายเซ็นก่อนดำเนินการ, ไม่ใช่ตรวจสอบหลังจากนั้น
  3. ตอบกลับ 2xx หลังจากที่คุณบันทึกเหตุการณ์เรียบร้อยแล้วเท่านั้น สถานะอื่นใดนอกเหนือจากนี้ หรือการหมดเวลา (timeout) จะถือเป็นความล้มเหลวและจะถูกลองใหม่

การลองใหม่ไปยังปลายทางหนึ่งจะมีระยะห่างที่ 1 นาที, 5 นาที, 15 นาที, 1 ชั่วโมง, 6 ชั่วโมง และ 24 ชั่วโมง — รวมทั้งหมดหกครั้ง กินเวลามากกว่า 31 ชั่วโมงเล็กน้อย เมื่อครบกำหนดแล้วและคุณได้ลงทะเบียน backup ไว้ การส่งข้อมูลจะย้ายไปที่นั่นและกำหนดการจะเริ่มนับใหม่ด้วยรหัสลับของตัวสำรองเอง ค่า delivery_id จะยังคงเดิมตลอด ดังนั้นเหตุการณ์ที่ล้มเหลวบนตัวหลักและสำเร็จบนตัวสำรองจึงยังคงเป็นเหตุการณ์เดียวกัน

ระบบไม่รองรับการเปลี่ยนเส้นทาง (redirects)

ขีดจำกัดอัตราการส่ง

10 คำขอต่อวินาที ต่อหนึ่งปลายทาง โดยแชร์การใช้งานร่วมกันระหว่างไคลเอนต์ทั้งหมด

ข้อผิดพลาด

การลงทะเบียนจะตอบกลับเป็น 201, การลบจะตอบกลับเป็น 204 โดยไม่มีเนื้อหา, กรณีอื่นทั้งหมดจะตอบกลับเป็น 200

HTTPความหมาย
401คีย์ขาดหายไปหรือไม่ถูกต้อง หรือ IP ต้นทางไม่ได้อยู่ใน whitelist
404ไม่พบปลายทางดังกล่าวในบัญชีของคุณ
409บทบาทที่ร้องขอถูกใช้งานแล้ว — role primary is already taken
422URL ถูกปฏิเสธ หรือเนื้อหา PATCH ไม่มีข้อมูลที่จะเปลี่ยนแปลง
429เกินขีดจำกัดอัตราการส่ง

URL ที่ถูกปฏิเสธจะส่งกลับมาเป็น 422 พร้อมระบุเหตุผลอย่างชัดเจน เพื่อให้คุณสามารถแสดงผลให้แก่ผู้ที่ป้อนข้อมูลได้:

json
{"status": "error", "code": -4, "msg": "url: Value error, invalid webhook_url: resolved address 127.0.0.1 is not public"}

ข้อความที่ใช้คือ only https:// URLs are allowed, credentials in URL are not allowed, และ resolved address <ip> is not public ข้อความสุดท้ายจะทำการแปลงที่อยู่ ณ เวลาลงทะเบียนและอีกครั้งทันทีก่อนการส่งข้อมูลแต่ละครั้ง ดังนั้นชื่อโฮสต์ที่ภายหลังชี้ไปยังที่อยู่ส่วนบุคคลจะหยุดรับข้อมูล

เรื่องที่เกี่ยวข้อง