# Payment CytechTeam Dev — Official API Documentation Source: https://payment.cytechteam.dev/docs This is the public API guide. Never expose API keys, webhook secrets, customer credentials or payment data to a third-party AI. Confirm endpoints against the official API before implementation. # รู้จัก Payment CytechTeam Dev Source: https://payment.cytechteam.dev/docs#overview ระบบสร้าง QR PromptPay และจับคู่รายการรับเงินอัตโนมัติจาก LINE Bank Alerts สำหรับร้านค้า เว็บไซต์ หรือระบบสมาชิกที่ต้องการเชื่อมต่อด้วย API Payment CytechTeam Dev API สร้าง PromptPay checkout และคืนสถานะจาก LINE bank notification. ระบบภายนอกใช้ Merchant API Key ผ่าน `Authorization: Bearer` ; หน้า Merchant Console ใช้ Session Cookie แบบ HttpOnly. การเข้าถึงข้อมูลร้านถูกจำกัดตามสิทธิ์ของ credential --- # เริ่มใช้งานใน 5 ขั้นตอน Source: https://payment.cytechteam.dev/docs#getting-started ทำตามลำดับนี้ได้แม้ไม่เคยใช้ Payment API มาก่อน ถ้าต้องการเริ่มแบบสั้น ๆ อ่าน หน้า Quickstart เพิ่มเติมได้ ### สมัครและเข้าสู่ Merchant Console เปิด Console สร้างบัญชีผู้ใช้งานหรือเข้าสู่ระบบ เลือก Workspace และสร้างร้านค้าของคุณ ### กำหนดบัญชีรับเงิน กรอกชื่อร้าน หมายเลข PromptPay ธนาคารที่รับเงิน และเลขบัญชีผู้รับ 4 หลักท้ายให้ตรงกับบัญชีจริง ตรวจข้อมูลก่อนยืนยันการตั้งค่า ### ออก Merchant API Key ไปที่เมนู API & Checkout สร้าง Key สำหรับฝั่งเซิร์ฟเวอร์ คัดลอกเก็บทันที เพราะค่าจริงจะแสดงเพียงครั้งเดียว ### สร้าง Checkout และส่งลิงก์จ่ายเงิน เรียก `POST /v1/checkouts` นำ `payment_path` จากผลลัพธ์ไปเปิดเป็นหน้าจ่ายเงินให้ลูกค้า ระบบจะสร้าง QR จาก PromptPay ที่ตั้งไว้ ### ตรวจสถานะและส่งมอบสินค้า ตั้ง Webhook เพื่อรับ `payment.confirmed` หรือเรียก API อ่านสถานะ ให้ส่งสินค้า/เติมเครดิตเฉพาะเมื่อสถานะเป็น `PAID` เท่านั้น ระบบนี้เป็น Live environment ไม่ใช่ Sandbox การเรียกสร้าง Checkout จะสร้างบิลจริง แนะนำทดสอบกับยอดเล็กและตรวจสอบปลายทางรับเงินจริง --- # ตั้งค่าร้านค้าและบัญชีรับเงิน Source: https://payment.cytechteam.dev/docs#merchant-setup บัญชีร้านค้าคือพื้นที่จัดการ API keys, Projects, Checkout และ Webhook คุณต้องตั้งค่าฝั่ง Merchant ก่อน จึงจะสร้าง QR ที่ลูกค้าชำระเงินจริงได้ ### ชื่อร้าน / Merchant ใช้ชื่อสื่อถึงผู้รับเงิน ลูกค้าจะได้ทราบว่าชำระให้ระบบใด และใช้แยกรายการใน Console ### PromptPay + ธนาคาร ใส่หมายเลข PromptPay ที่รับเงินจริง เลือกธนาคารผู้รับ และเลขบัญชี 4 หลักท้ายให้ถูกต้องสำหรับการจับคู่แจ้งเตือน ### ทวนข้อมูลรับเงิน ข้อมูลบัญชีรับเงินหลักถูกล็อกหลังตั้งค่า เพื่อลดการเปลี่ยนปลายทางโดยไม่ตั้งใจ โปรดตรวจสอบก่อนบันทึก ### ตั้ง Callback URL เลือก HTTPS endpoint แบบสาธารณะที่รับ POST แล้วตอบ 2xx ได้ ตรวจ signature ก่อนนำข้อมูลไปดำเนินการ หากใช้หลายเว็บ: แยกเป็น Projects ภายใน Merchant เดียวกันเพื่อแยก API Key และรายงานได้ ดูหัวข้อ Projects & Workspaces --- # Authentication และการดูแล API Key Source: https://payment.cytechteam.dev/docs#authentication Server-to-server: เข้าสู่ Merchant Console เพื่อสร้างบัญชี ตั้งค่าร้านและ PromptPay แล้วสร้าง Merchant API Key ในหน้า API & Checkout. ส่ง Key ด้วย `Authorization: Bearer cyt_next_...` เท่านั้น อย่านำ Key ไปฝังใน JavaScript ที่ส่งให้เบราว์เซอร์ **Endpoint:** API KEY `Authorization: Bearer cyt_next_...` Merchant Console: เข้าสู่ระบบด้วย `POST /v1/auth/login` จากนั้นเบราว์เซอร์ใช้ `__Host-cytech_console` ซึ่งเป็น `HttpOnly; Secure; SameSite=Strict` Cookie อายุ 30 วัน จึงใช้งานข้ามแท็บหรือเปิดเบราว์เซอร์ใหม่ได้หากยังไม่หมดอายุ. ตรวจสถานะด้วย `GET /v1/auth/session` และออกจากระบบด้วย `POST /v1/auth/logout` . ไม่ต้องอ่านหรือเก็บ Session Token ใน JavaScript **Endpoint:** CONSOLE `Cookie: __Host-cytech_console (browser-managed)` ระบบยังรองรับ `Authorization: Bearer cyt_sess_...` สำหรับ API client ที่ต้องการใช้ Console Session โดยตรง. Session ใหม่มีอายุ 30 วัน และ Session เก่าที่ยังใช้ได้สามารถย้ายไปใช้ Cookie ได้. API Key และ Session ถูกเก็บเป็น Hash ฝั่ง Server; API Key ใหม่แสดงค่าเต็มเพียงครั้งเดียวตอนสร้าง ``` curl -sS -X POST "https://payment.cytechteam.dev/v1/checkouts" \ -H "Authorization: Bearer cyt_next_REPLACE_WITH_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"merchant_ref":"order-1001","amount":"20.00","verification_method":"decimal"}' ``` แทน `cyt_next_REPLACE_WITH_YOUR_KEY` ด้วย Merchant API Key จริงของร้าน และเปลี่ยน `merchant_ref` ให้ไม่ซ้ำในแต่ละออเดอร์. ตัวอย่างใช้ URL เต็ม ไม่ต้องตั้งตัวแปร `BASE` หรือ `KEY` ใน Terminal. คำสั่งนี้สร้างบิลจริงบน Live environment --- # ออก Checkout แรกแบบเร็ว Source: https://payment.cytechteam.dev/docs#quickstart ตัวอย่างด้านล่างใช้ URL เต็มของ Live API และใช้ `cyt_next_REPLACE_WITH_YOUR_KEY` แทนคีย์จริง โดยไม่ต้องตั้งตัวแปร Shell. ดู Quickstart แบบทีละขั้น เพื่อสร้างบิล เปิดหน้าจ่ายเงิน แล้วรับ webhook หรือ polling สถานะ. `merchant_ref` ต้องไม่ซ้ำสำหรับแต่ละออเดอร์ ### 1. Create ``` curl -X POST "https://payment.cytechteam.dev/v1/checkouts" \ -H "Authorization: Bearer cyt_next_REPLACE_WITH_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"merchant_ref":"order-1001","amount":"20.00","verification_method":"decimal"}' ``` ### 2. Open Response มี `payment_path` เช่น `/pay/pay_...` ให้เปิดหรือส่งให้ลูกค้า ### 3. Confirm ฟัง `payment.confirmed` ที่ webhook หรือ poll `GET /v1/checkouts/` จนสถานะเป็น `PAID` --- # เงินหนึ่งรายการ เดินทางอย่างไร? Source: https://payment.cytechteam.dev/docs#payment-flow ความเข้าใจวงจรของบิลสำคัญมาก โดยเฉพาะระบบเติมเครดิตหรือส่งสินค้าอัตโนมัติ ### หมดอายุ ครบ 15 นาทีแล้วยังไม่ยืนยัน ไม่ควรใช้ QR เดิม ให้สร้างออเดอร์ใหม่ด้วย merchant_ref ใหม่ ### หลักฐานจับคู่ไม่ได้ ไม่พบออเดอร์ที่ตรง หรือพบหลายออเดอร์ ระบบจะไม่สุ่มเลือกบิล ต้องตรวจเหตุการณ์และยอดรับเงินจริง การที่ลูกค้าเห็น QR หรืออัปโหลดรูปสลิป ไม่ได้แปลว่าบิลสำเร็จ ห้ามเปลี่ยนสถานะออเดอร์เองจนกว่าจะได้รับหลักฐานสถานะ PAID จาก Server --- # เลือกวิธีตรวจสอบยอดโอน Source: https://payment.cytechteam.dev/docs#methods เลือกให้เหมาะกับข้อมูลที่คุณรู้เกี่ยวกับผู้โอน และตรวจให้แน่ใจว่าเงื่อนไขตรงตามธุรกรรมจริง หนึ่งบิลเลือกได้หนึ่งวิธี และจะถูกจับคู่กับ LINE bank notification ที่ผ่านการตรวจผู้ส่งและเงื่อนไขอื่นของรายการ (บัญชีผู้รับ ยอดเงิน และเวลา) เท่านั้น | Method | Value | Match rule | | --- | --- | --- | | decimal | ไม่ต้องส่ง | เศษสตางค์ของยอดจริงตรงกับ expected cents | | name_exact | 2–150 chars | ชื่อผู้โอน normalize แล้วตรง exact | | account_last4 | 4 digits | เลขบัญชีผู้โอน 4 หลักท้ายตรง | | bank | Bank code/name | ธนาคารผู้โอนตรง | ### เลือกวิธีไหนให้เหมาะ? decimal: เหมาะกับบิลทั่วไปเมื่อยืนยันด้วยเศษสตางค์ แต่ถ้าเปิดบิลยอดเดียวกันหลายใบพร้อมกัน แนะนำ `amount_mode: "unique_cents"` เพื่อให้ระบบจัดสรรเศษสตางค์ไม่ซ้ำ name_exact: ใช้เมื่อทราบชื่อบัญชีผู้โอนที่จะแสดงในแจ้งเตือนอย่างแน่นอน · account_last4: ใช้เลขบัญชี ผู้โอน 4 หลักท้าย ไม่ใช่เลขบัญชีรับเงิน · bank: เหมาะเมื่อทราบธนาคารของผู้โอน ### แยกบิลยอดเท่ากันด้วย Unique Cents ``` curl -sS -X POST "https://payment.cytechteam.dev/v1/checkouts" \ -H "Authorization: Bearer cyt_next_REPLACE_WITH_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"merchant_ref":"order-1003","amount":"20.00","verification_method":"decimal","amount_mode":"unique_cents"}' ``` เช่น ร้านขอ 20.00 บาท แต่ระบบอาจคืน 20.01 บาท เพื่อแยกบิล อย่าแสดงยอด 20.00 แทนค่าที่ตอบกลับ โหมดนี้ใช้ได้เฉพาะจำนวนเต็มบาทและวิธี decimal เท่านั้น --- # เชื่อมต่อกับเว็บไซต์ บอท และระบบสมาชิก Source: https://payment.cytechteam.dev/docs#integrations ไม่ว่าลูกค้าจะกดซื้อจากหน้าเว็บ Discord bot หรือเกม ขั้นตอนหลักเหมือนกัน: Server ของคุณสร้างออเดอร์ → ขอ Checkout → ส่งลิงก์ให้ลูกค้า → รอ PAID → ส่งมอบบริการ ### เว็บขายสินค้า สร้างบิลเมื่อกดสั่งซื้อ บันทึก `merchant_ref` คู่กับหมายเลขออเดอร์ ส่งลิงก์จ่ายเงินไปหน้า checkout จากนั้นรอ Webhook ### เติมเครดิตผ่านบอท ให้ Backend ของบอทเรียก API แล้วส่ง payment link ไปให้ผู้ใช้ รอ PAID ก่อนเพิ่มเครดิต และบันทึก event ID กันเติมซ้ำ ### ต่ออายุสมาชิก สร้าง Checkout ใหม่ทุกงวดหรือทุกคำสั่งซื้อ ใช้เลขอ้างอิงใหม่ ไม่ถือว่าจ่ายแล้วเพียงเพราะเปิดลิงก์ชำระเงิน ### ตัวอย่าง Node.js — สร้างบิลจาก Backend ``` const response = await fetch('https://payment.cytechteam.dev/v1/checkouts', { method: 'POST', headers: { Authorization: 'Bearer ' + process.env.CYTECH_API_KEY, 'Content-Type': 'application/json' }, body: JSON.stringify({ merchant_ref: 'order-' + crypto.randomUUID(), amount: '20.00', verification_method: 'decimal' }) }); if (!response.ok) throw new Error('Checkout failed: ' + response.status); const { checkout } = await response.json(); const paymentUrl = 'https://payment.cytechteam.dev' + checkout.payment_path; console.log(paymentUrl, checkout.id); ``` ### ตัวอย่าง Python — สร้างบิลจาก Backend ``` import os import requests resp = requests.post( "https://payment.cytechteam.dev/v1/checkouts", headers={"Authorization": "Bearer " + os.environ["CYTECH_API_KEY"]}, json={"merchant_ref": "order-1002", "amount": "20.00", "verification_method": "decimal"}, timeout=15, ) resp.raise_for_status() checkout = resp.json()["checkout"] print("https://payment.cytechteam.dev" + checkout["payment_path"]) ``` ### ตรวจสถานะหากยังไม่มี Webhook ``` curl -sS "https://payment.cytechteam.dev/v1/checkouts/pay_REPLACE_WITH_REAL_ID" \ -H "Authorization: Bearer cyt_next_REPLACE_WITH_YOUR_KEY" ``` Polling ควรทำจาก Backend ตามช่วงเวลาที่เหมาะสมและหยุดเมื่อ `PAID` , `EXPIRED` หรือ `CANCELLED` หากต้องการส่งมอบอัตโนมัติแนะนำใช้ Webhook เป็นช่องทางหลักและใช้ GET ตรวจสอบซ้ำได้ ### เชื่อมต่อ AI ด้วย MCP (Model Context Protocol) Docs MCP สำหรับอ่านคู่มือสาธารณะผ่าน `https://payment.cytechteam.dev/v1/mcp/docs` โดยไม่ต้องล็อกอิน ใช้ค้นหัวข้อและอ่าน Markdown เท่านั้น Manager MCP สำหรับอ่านข้อมูล Workspace โปรเจกต์ และ Checkout ผ่าน `https://payment.cytechteam.dev/v1/mcp/manager` รองรับ OAuth 2.1 ให้ล็อกอิน Payment แล้วเลือก Workspace และสิทธิ์บนหน้าขออนุญาต ไม่ต้องวาง Merchant API Key ลงในแอป AI รองรับ OAuth Discovery, Dynamic Client Registration, Authorization Code + PKCE (S256), Access/Refresh Token และเพิกถอนแอป AI ใน Console ได้ สิทธิ์อ่าน `mcp:read` แยกจากสิทธิ์สร้าง Checkout `mcp:write` โปรดตั้งค่า AI ให้ขออนุมัติก่อนสร้างบิลรับเงินจริง ผู้ใช้ที่ต้องการตั้งค่าแบบเก่าด้วย Merchant API Key ยังใช้ได้ใน MCP Client ที่รองรับ Bearer Header ดูตัวอย่างการเชื่อมต่อหลายแพลตฟอร์มได้ที่ ตั้งค่าบัญชี → MCP Integration --- # แยก Projects และจัดการ Workspaces Source: https://payment.cytechteam.dev/docs#projects Workspace ใช้จัดการพื้นที่ร้านและสิทธิ์การเข้าถึงใน Merchant Console ส่วน Project ใช้แบ่งระบบย่อยของร้าน เช่น เว็บ A, Discord Bot, ร้านค้า B โดยใช้รหัส `prj_...` ของ Project ใน Checkout หรือ API Key ที่ผูก Project ### Key ระดับร้าน API Key ที่ไม่ได้ผูก Project สามารถทำงานตามสิทธิ์ Merchant และเลือก Project ที่ต้องการสำหรับ Checkout ได้ ### Key จำกัด Project สิทธิ์จะถูกจำกัดใน Project เดียว ช่วยแยกข้อมูลและลดการเข้าถึง Checkout ของโปรเจกต์อื่นโดยไม่ตั้งใจ **Endpoint:** GET `/v1/projects` เรียกรายการโปรเจกต์ที่สิทธิ์ปัจจุบันเข้าถึงได้ เลือก Project จาก Console เมื่อใช้งานหลายระบบ และใช้ `project` ใน request เฉพาะเมื่อทราบ ID จริงแล้ว --- # การตรวจเงินด้วย LINE ธนาคาร Source: https://payment.cytechteam.dev/docs#bank-alerts Payment CytechTeam Dev ไม่ได้เชื่อมกับบัญชีธนาคารโดยตรง แต่รับข้อความแจ้งเตือนผ่าน LINE Worker แล้วตรวจสอบเงื่อนไข เช่น ผู้ส่งที่รู้จัก ยอดโอน ผู้รับ เวลาของรายการ และวิธีจับคู่ที่เลือกไว้ ### ตรวจแหล่งที่มา Worker ตรวจชื่อ Official Account ตามนโยบายที่กำหนดในระบบ บันทึกข้อมูลเพื่อ audit โดยไม่ได้เท่ากับการรับประกันการยืนยันตัวจากธนาคารโดยตรง ### จับคู่บิลที่ตรง ระบบไม่เดาว่าเงินเข้าบิลไหน เมื่อพบหลายบิลตรงกันจะทำเครื่องหมาย AMBIGUOUS และยังไม่ยืนยันบิลใด **Endpoint:** GET `/v1/merchant/bank-events?limit=50` ใช้สำหรับตรวจรายการแจ้งเตือนจากธนาคารที่ระบบรับไว้ภายใต้สิทธิ์ของร้าน ควรเปรียบเทียบกับข้อมูลในธนาคารจริงเมื่อเกิดความคลาดเคลื่อน ดูธนาคารที่ระบบระบุไว้ใน Bank coverage หรือเรียก `GET /v1/banks` เพื่อดูรายการที่ API ประกาศรองรับ --- # รับซองอั่งเป้า TrueMoney Source: https://payment.cytechteam.dev/docs#truemoney รับซองอั่งเป้า TrueMoney เข้า wallet ของร้าน ยิงครั้งเดียวต่อซอง ไม่ retry อัตโนมัติ ผ่านได้เฉพาะ `POST` เท่านั้น ### Request ``` curl -X POST "https://payment.cytechteam.dev/v1/merchant/truemoney/redeem" \ -H "Authorization: Bearer cyt_next_REPLACE_WITH_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"mobile":"0812345678","voucher":"https://gift.truemoney.com/campaign/?v=..."}' ``` ### States - `SUCCESS` — เงินเข้าแล้ว ยอดส่งผ่านตรง ไม่ปัดเป็น 0.00 - `FAILED` — upstream ตอบปฏิเสธชัดเจน (code จาก TrueMoney) - `PENDING_RECONCILIATION` — timeout/network ขาด ซองอาจถูกใช้ไปแล้ว ห้ามยิงซ้ำเอง ต้อง reconcile ซองเดิมเรียกซ้ำคืนแถวเดิม ( `200` + `duplicate:true` ) ซองเดิมแต่คนละเบอร์ได้ `409` . ส่ง `"retry":true` เพื่อยิงซ้ำเฉพาะเคสชั่วคราว (edge block, rate limit, timeout, 5xx) — `SUCCESS` กับ code สุดท้ายปฏิเสธด้วย `409` ยกเว้น `"retry":"force"` ที่ยิงซ้ำได้ครั้งเดียวสำหรับแถวเก่าที่บันทึกด้วยโค้ดรุ่นก่อน (ไม่ใช่ `SUCCESS` ). ประวัติรายการรับซองอยู่ที่ `GET /v1/merchant/truemoney/redemptions` และดูร่วมกับ Checkout ได้ที่หน้า ธุรกรรม หรือ `GET /v1/merchant/transactions?channel=truemoney` โดยกรอง `channel=all|checkout|truemoney` , `status` , `limit` , `offset` ได้ ประวัติรวมแสดงรหัสซองและเบอร์ผู้รับแบบปิดบางส่วน ไม่แสดงลิงก์ซองเต็ม รายการ TrueMoney ที่สำเร็จแสดงจำนวนเงินจริงตามผลตอบกลับ หากยังยืนยันยอดไม่ได้ ระบบจะแสดงว่าไม่ทราบยอดแทน 0.00 และจะไม่รวมยอดซองเข้ากับสถิติ Checkout โดยอัตโนมัติ เพื่อไม่ให้นับยอดซ้ำ --- # สร้าง Checkout Source: https://payment.cytechteam.dev/docs#create **Endpoint:** POST `/v1/checkouts` ### Body | Field | Type | Required | Notes | | --- | --- | --- | --- | | merchant_ref | string | yes | 1–128 chars: A-Z a-z 0-9 _ . : / - | | amount | string | yes | Positive, up to 2 decimals, max 9,999,999.99 | | verification_method | string | no | decimal (default), name_exact, account_last4, bank | | verification_value | string | conditional | Required except decimal | | amount_mode | string | no | exact (default) or unique_cents (decimal, whole baht) | | receiver_promptpay | string | no | Per-bill PromptPay; needs receiver_bank + receiver_last4 together, else merchant default | | receiver_bank | string | no | Per-bill receiver bank code | | receiver_last4 | string | no | Per-bill receiver last4 | ### Response ``` { "checkout": { "id": "pay_...", "merchant_ref": "order-1001", "amount": "20.00", "status": "PENDING", "verification_method": "decimal", "payment_path": "/pay/pay_...", "expires_at": "2026-10-25T12:15:00+00:00" } } ``` --- # ดึงข้อมูล Checkout และรายการ Source: https://payment.cytechteam.dev/docs#retrieve **Endpoint:** GET `/v1/checkouts/` คืน checkout ของ merchant นี้เท่านั้น ถ้าไม่พบจะได้ 404 แบบไม่เปิดเผยว่ามีอยู่จริงหรือไม่ **Endpoint:** POST `/v1/checkouts//cancel` ยกเลิกบิลที่ยังเป็น `PENDING` โดยส่ง JSON `{}` พร้อม Merchant API Key หรือ Console session บนเซิร์ฟเวอร์ จะได้ผลลัพธ์ `{"checkout":{"status":"CANCELLED",...}}` การกดซ้ำปลอดภัย (idempotent) แต่บิล `PAID` หรือหมดเวลาแล้วตอบ 409, คนละ Workspace/Project ได้ 404 ไม่ใช่การคืนเงิน และควรใช้ `merchant_ref` ใหม่เมื่อสร้างบิลทดแทน ``` curl -X POST "https://payment.cytechteam.dev/v1/checkouts/pay_REPLACE_WITH_REAL_ID/cancel" \ -H "Authorization: Bearer cyt_next_REPLACE_WITH_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{}' ``` หน้าจ่ายเงินมีปุ่มยกเลิกสำหรับผู้ถือ URL ของบิลผ่าน `POST /pay//cancel` (ต้องเป็น JSON และเรียกจาก Origin เดียวกัน) ระบบหยุดแสดง QR และแจ้ง `payment.cancelled` ผ่าน Webhook และ Custom Notification ที่สมัคร event นี้ไว้ หากโอนไปแล้วหรือโอนผิดหลังยกเลิก ต้องตรวจยอดและจัดการคืนเงินแยกต่างหาก **Endpoint:** GET `/v1/merchant/checkouts?status=PAID&limit=50&offset=0` รายการล่าสุดสำหรับ Console และรายงาน. รองรับ status PENDING, PAID, EXPIRED, CANCELLED **Endpoint:** GET `/v1/merchant/profile` ดูข้อมูล Merchant ปัจจุบัน ใช้ตรวจสอบ Key และรายละเอียดบัญชีรับเงินที่ตั้งค่าไว้ **Endpoint:** GET `/v1/merchant/overview` อ่านภาพรวมธุรกรรมของร้าน หรือระบุ Project เมื่อมีหลายโปรเจกต์ --- # หน้าชำระเงินสาธารณะและ QR Source: https://payment.cytechteam.dev/docs#public **Endpoint:** GET `/pay/` **Endpoint:** GET `/pay//status` **Endpoint:** GET `/pay//qr.png` หน้า public ไม่ต้องใช้ API key. QR จะถูกปฏิเสธเมื่อบิลไม่ใช่ PENDING. Status endpoint คืนเฉพาะสถานะที่ปลอดภัย หน้า `/pay/...` และ `/pay/.../status` ออกแบบให้ลูกค้าเข้าถึงได้โดยไม่เปิดเผย Key ส่วน endpoint `/v1/checkouts/...` ต้องเรียกจาก Backend ที่ยืนยันตัวแล้ว --- # Webhook: รับสถานะชำระเงินอัตโนมัติ Source: https://payment.cytechteam.dev/docs#webhook ตั้งค่าจุดรับในเมนู API & Checkout หรือใช้ `POST /v1/merchant/webhook` จากบัญชีที่มีสิทธิ์ Merchant และระบุ HTTPS URL ที่เข้าถึงจากอินเทอร์เน็ตได้ เมื่อยืนยันสำเร็จ ระบบเขียน outbox ใน transaction เดียวกับ PAID แล้วส่ง POST ไปยัง URL ของร้าน **Endpoint:** POST `https://merchant.example/payments` ### Headers | Header | Meaning | | --- | --- | | X-Cytech-Event-ID | ID สำหรับ deduplication | | X-Cytech-Timestamp | Unix seconds | | X-Cytech-Signature | HMAC-SHA256(secret, timestamp + "." + raw_body) | ``` { "type": "payment.confirmed", "data": { "id": "pay_...", "merchant_ref": "order-1001", "amount": "20.00", "status": "PAID", "confirmation_basis": "BANK_LINE_NOTIFICATION", "funds_received": true } } ``` Retries: bounded exponential backoff, สูงสุด 7 ครั้ง. ฝั่งร้านควรตอบ 2xx และ dedup ด้วย event ID ### ตรวจสอบลายเซ็น Webhook ด้วย Node.js บน Backend ติดตั้ง `npm install express` ใช้ Node.js แบบ ES Modules และกำหนด `CYTECH_WEBHOOK_SECRET` จาก Console (Secret แสดงครั้งเดียวเมื่อสร้างหรือ Rotate) คำนวณ HMAC จาก `timestamp + "." + raw_body` ด้วย Webhook Secret ที่ตั้งค่าของร้าน ตรวจ timestamp เพื่อป้องกัน replay และใช้การเปรียบเทียบแบบ timing-safe ก่อนอ่านข้อมูลคำสั่งซื้อ ``` import express from 'express'; import { createHmac, timingSafeEqual } from 'node:crypto'; const app = express(); app.post('/payments', express.raw({ type: 'application/json' }), (req, res) => { const ts = req.get('X-Cytech-Timestamp') || ''; const sent = req.get('X-Cytech-Signature') || ''; if (!/^\d+$/.test(ts) || Math.abs(Date.now()/1000 - Number(ts)) > 300) return res.sendStatus(401); const expected = createHmac('sha256', process.env.CYTECH_WEBHOOK_SECRET) .update(ts + '.').update(req.body).digest('hex'); const received = sent.replace(/^sha256=/i, ''); if (!/^[a-f0-9]{64}$/i.test(received) || !timingSafeEqual(Buffer.from(expected, 'hex'), Buffer.from(received, 'hex'))) return res.sendStatus(401); const event = JSON.parse(req.body.toString('utf8')); const eventId = req.get('X-Cytech-Event-ID'); // Queue a transaction: persist eventId uniquely, then fulfill PAID order once. // Acknowledge 2xx after durable processing or queuing. return res.sendStatus(204); }); app.listen(Number(process.env.PORT || 3000)); ``` คุณยังต้องทำส่วนบันทึก event ID และอัปเดตออเดอร์ในฐานข้อมูลจริง เพื่อไม่ให้ callback ที่ส่งซ้ำทำให้เติมเงินหรือส่งสินค้าซ้ำ --- # Idempotency และการป้องกันซ้ำ Source: https://payment.cytechteam.dev/docs#idempotency `(merchant_id, merchant_ref)` ไม่ซ้ำ. การเรียก create ซ้ำด้วย ref และข้อมูลเดิมจะคืน checkout เดิม. ถ้า ref เดิมแต่ยอด/วิธีตรวจสอบต่าง จะได้ `409` LINE message ID ซ้ำจะไม่สร้าง event ใหม่และไม่จ่ายบิลซ้ำ --- # รหัส HTTP Error Source: https://payment.cytechteam.dev/docs#errors | Status | Meaning | Example | | --- | --- | --- | | 401 | Missing/invalid credential | unauthorized | | 404 | Not found or not owned | not_found | | 409 | Conflict / duplicate ref mismatch | merchant_ref already belongs... | | 422 | Validation error | amount must have 0 to 2 decimals | | 500 | Internal error (no detail exposed) | internal_error | --- # ขีดจำกัดและข้อกำหนด Source: https://payment.cytechteam.dev/docs#limits - Checkout expiry: 15 minutes - Amount: positive, max 9,999,999.99 THB - merchant_ref: 1–128 token chars - API key limit: 10 active keys per merchant - Webhook body/outbox: bounded retries, สูงสุด 7 attempts - Console session: 30 days, ยกเลิกได้ด้วย Logout หรือ Password Reset --- # แก้ปัญหาที่พบบ่อย Source: https://payment.cytechteam.dev/docs#troubleshooting ตรวจจากขั้นตอนที่เกี่ยวข้องก่อนแก้ไขในระบบร้าน อย่าสร้าง Checkout หรือส่งมอบสินค้าซ้ำโดยไม่ได้ตรวจสถานะเดิม ตรวจว่า Header เป็น `Authorization: Bearer cyt_next_...` และ Key ไม่ถูกเพิกถอนหรือหมดสิทธิ์ ตรวจว่าใช้ Key ของร้าน/Project ที่ถูกต้อง ไม่ใช่ Session Cookie ของหน้าเว็บ ตรวจ `merchant_ref` ความยาว 1–128 ตัวอักษรและอักขระที่อนุญาต ยอดต้องเป็นสตริงเลขบวกทศนิยมไม่เกิน 2 ตำแหน่ง กรณีเลือก `name_exact` , `bank` หรือ `account_last4` ต้องระบุ `verification_value` หมายเลขอ้างอิงนี้เคยถูกสร้างด้วยข้อมูลไม่เหมือนเดิม ห้ามใช้ ref เดิมกับยอดใหม่ ให้สร้าง order ID ใหม่สำหรับคำสั่งซื้อใหม่ และเก็บ ref เดิมไว้สำหรับการ retry request เดิม ตรวจรายการเงินจริงกับธนาคารก่อน จากนั้นตรวจเวลาบิล (15 นาที), ยอดที่ลูกค้าโอน, ธนาคารและบัญชีผู้รับ 4 หลักท้าย, LINE Worker/Bank alerts, วิธีตรวจที่ระบุ และเหตุการณ์ UNMATCHED/AMBIGUOUS ห้ามปรับ PAID โดยเดา ตรวจ ID ว่าอยู่ในรูป `pay_...` และบิลยัง PENDING หากบิลหมดอายุหรือ PAID แล้ว API QR จะไม่ให้ใช้งาน ให้สร้างบิลใหม่หากยังต้องชำระ ตรวจ URL ต้องเป็น HTTPS แบบ Public, DNS/TLS ถูกต้อง และ endpoint ตอบ 2xx ได้ ตรวจ Firewall, Log ฝั่งรับ, Event ID และสถานะระบบที่ Status ระบบมี retry สูงสุด 7 ครั้ง จึงควรทำตัวรับให้ idempotent และมีทางเช็กด้วย GET ปลายทางตอบไม่แน่ชัด (เช่น timeout) ซองอาจถูกใช้แล้ว อย่าเรียก redeem ซ้ำทันที ตรวจประวัติและยอดใน Wallet ก่อน แล้วค่อยจัดการ reconciliation --- # แนวทางใช้งานจริงที่แนะนำ Source: https://payment.cytechteam.dev/docs#best-practices แยก Checkout ออกจากคำสั่งซื้อบันทึก pay_id, merchant_ref, ยอด และสถานะในฐานข้อมูลของคุณเสมอ ตรวจ Webhook signature จาก raw bodyอย่าเอา JSON ที่ parse แล้วไป serialize ใหม่ก่อน HMAC ส่งมอบครั้งเดียวเท่านั้นใช้ event ID หรือ order ID เป็น unique key และบันทึกว่าเคยเติมเครดิต/ส่งสินค้าแล้ว เก็บ API Key ใน Serverใช้ environment variables หรือ secret manager ไม่วางใน frontend, แอปที่แจก หรือ GitHub แยกโปรเจกต์ตามงานใช้ Project-scoped API Key เมื่อมีเว็บ บอท หรือผู้ดูแลหลายชุด ตรวจความพร้อมและทำแผนสำรองเฝ้าดู /status, มีวิธีตรวจยอดด้วยคน และรองรับความล่าช้าของ LINE notification --- # คำถามที่พบบ่อย (FAQ) Source: https://payment.cytechteam.dev/docs#faq ดูข้อมูลร้านและสร้างบิลผ่าน Merchant Console ได้ ส่วนการสร้างบิลจากเว็บ บอท หรือเติมเครดิตอัตโนมัติควรมี Backend สำหรับเก็บ API Key และรับ Webhook ใช้รูปแบบ PromptPay ที่หน้าตั้งค่าร้านรองรับและตรวจให้แน่ใจว่าปลายทางที่สร้าง QR ตรงกับบัญชีรับเงินจริง หากไม่มั่นใจให้ทดสอบกับธนาคารของคุณก่อนเปิดขายจริง ระบบนี้ใช้ LINE bank notification เป็นหลักฐานการรับเงิน ไม่ใช้ภาพสลิปเป็นตัวตัดสิน เพื่อหลีกเลี่ยงการยืนยันจากไฟล์ที่แก้ไขหรือใช้ซ้ำได้ ตัวอย่างทั้งหมดในหน้านี้ใช้ Live API ของ `payment.cytechteam.dev` อย่าทดสอบด้วยยอดจำนวนมาก และอย่าสมมติว่ามี Sandbox แยกหากยังไม่ได้รับข้อมูลยืนยันจากผู้ดูแลระบบ ตรวจรายการเงินจริงกับธนาคารและสถานะบิลก่อน อย่าจ่ายเครดิตหรือสร้างรายการ PAID เองโดยไม่พิสูจน์ ตรวจหาธุรกรรมที่ไม่ถูกจับคู่และดำเนินการตรวจสอบด้วยคน ไม่ใช่บริการชำระเงินของธนาคารหรือ Settlement API โดยตรง ระบบช่วยสร้างบิลและตรวจสอบข้อมูลการรับเงินจากการแจ้งเตือน LINE ธนาคาร ซึ่งมีข้อจำกัดขึ้นกับแหล่งข้อมูลภายนอก --- # ความปลอดภัยและขอบเขตบริการ Source: https://payment.cytechteam.dev/docs#security - Live LINE Worker ปัจจุบันตั้ง `CYTECH_LINE_SENDER_POLICY=name` ตรวจชื่อ LINE Official Account ที่ normalize แล้วแบบตรงตัวกับชื่อธนาคารที่รู้จัก โดยบันทึก MID เพื่อ audit แต่ไม่ได้ยืนยัน MID allowlist หรือ Verified/Premium badge ในโหมดนี้. โค้ดยังรองรับโหมด `mid` , `badge_name` และ `mid_or_badge_name` เมื่อกำหนดค่าต่างออกไป - Internal LINE bridge ใช้ HMAC signature และกรอบเวลา ±90 วินาที; การยืนยันแบบ `BANK_LINE_NOTIFICATION` ไม่ใช่ Bank Settlement โดยตรง - API keys และ Console sessions ถูกเก็บเป็น hash; Browser Console ใช้ Secure HttpOnly SameSite=Strict Cookie อายุ 30 วัน - Webhook URLs ต้องเป็น public HTTPS และห้าม resolve ไปยัง private/literal host - จำนวนเงินเก็บเป็นจำนวนเต็มหน่วยสตางค์