Skip to content

ยืนยันตัวตน / OTP ​

มีสองแบบ ยืนยันด้วย API key ทั้งคู่

SMS OTP ดูแลครบวงจร ตั้งแต่สร้างรหัส ส่ง ไปจนถึงตรวจสอบ

การทำงานRoute
ส่งรหัสPOST /sms/otp
ตรวจสอบรหัสPOST /sms/otp/{otpId}/verify
ส่งรหัสอีกครั้งPOST /sms/otp/{otpId}/resend
อ่านสถานะGET /sms/otp/{otpId}

ตรวจสอบอย่างเดียว ใช้กับรหัสที่ระบบสร้างจากที่อื่น เช่นตอนสมัครสมาชิก โดยอ้างอิงด้วย ref_code ไม่ใช่ session id

การทำงานRoute
ตรวจสอบรหัสPOST /otp/verify

เลือกแบบไหน

ถ้าเริ่มจากศูนย์ ใช้ POST /sms/otp ส่วน /otp/verify ใช้เมื่อมีระบบอื่นสร้างรหัสไว้แล้ว และส่ง ref_code มาให้ — รหัสที่คุณสร้างเองและส่งผ่าน SMS ของคุณเอง ตรวจสอบที่นั่นไม่ได้ เพราะระบบหาไม่เจอ

ส่ง OTP ​

bash
curl -X POST "$ME_BASE/sms/otp" \
  -H "API-Key: $ME_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
        "mode": "auto",
        "operator": "smart",
        "sender_name": "YourBrand",
        "recipient": "+66886578553",
        "config": { "length": 6, "type": "numeric", "validity_seconds": 300 }
      }'
json
{
  "id": "0f3c…",
  "mode": "auto",
  "recipient": "+66886578553",
  "ref_code": "A1B2",
  "expires_at": "2026-09-19T04:21:00Z",
  "status": "sent",
  "message_id": "tx-…"
}

เก็บ id ไว้ ใช้อ้างอิงตอนตรวจสอบ ส่งซ้ำ และอ่านสถานะ ส่วนที่แสดงให้ผู้ใช้เห็นคือ ref_code — ตัวรหัสจะไม่ถูกส่งกลับมา ระบบเก็บไว้เป็นค่าแฮชเท่านั้น จึงไม่มีทางดึงกลับได้

ฟิลด์หมายเหตุ
modeauto (ระบบสร้างและตรวจสอบให้) หรือ provided (คุณสร้างเอง ระบบส่งให้อย่างเดียว)
operatorais, dtac, true_corp หรือ smart ให้ระบบเลือกเส้นทางให้
sender_nameชื่อผู้ส่งที่องค์กรคุณได้รับอนุมัติ ดูรายละเอียดด้านล่าง
recipientรูปแบบ E.164
message_templateต้องมี ถ้าไม่ส่งมา ระบบใช้ข้อความมาตรฐาน
message_template_idid ของเทมเพลตที่คุณบันทึกไว้ ใช้พร้อม message_template ไม่ได้
configเฉพาะ auto — length 4–10, type, validity_seconds 1–3600
otp / ref_codeเฉพาะ provided — รหัสและเลขอ้างอิงของคุณเอง

sender_name ใช้ข้อตกลงเดียวกับ SMS ชื่อที่ยังไม่ได้รับอนุมัติ จะถูกปฏิเสธด้วย 403 ไม่ใช่เปลี่ยนให้เงียบๆ ดูรายชื่อที่ใช้ได้จาก GET /organization/{organizationId}/sender-names — route นั้นใช้ token ของผู้ใช้ ไม่ใช่ API-Key ดู ชื่อผู้ส่ง

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

เทมเพลตข้อความ ​

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

jsonc
// เขียนตรงๆ
{ "message_template": "{{otp}} คือรหัส OTP ของคุณ Ref: {{ref_code}}" }

// หรืออ้างด้วย id จาก /template-message/organization/{organizationId}
{ "message_template_id": "8f1c…" }

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

id ของเทมเพลตจะถูกแปลงเป็นข้อความก่อนประกอบเป็น SMS การแก้เทมเพลตทีหลัง จึงไม่กระทบข้อความที่ส่งไปแล้ว รวมถึงการส่งซ้ำ ซึ่งใช้ข้อความ ณ ตอนส่งครั้งแรก

ส่งซ้ำอย่างปลอดภัย ​

ใส่ Idempotency-Key แล้วการยิงซ้ำจะได้ OTP เดิมกลับมา ไม่ใช่รหัสใหม่ การอ้างเทมเพลตด้วย id กับการพิมพ์ข้อความเดียวกันตรงๆ นับเป็นคำขอเดียวกัน เพราะ key ครอบข้อความที่แปลงแล้ว

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

ตรวจสอบ OTP จาก SMS OTP ​

bash
curl -X POST "$ME_BASE/sms/otp/$OTP_ID/verify" \
  -H "API-Key: $ME_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "otp": "884213" }'
json
{ "id": "0f3c…", "verified": false, "status": "pending", "attempts_remaining": 2 }

รหัสผิดได้ 200 ไม่ใช่ 4xx

คำขอถูกต้องดีอยู่ แค่รหัสผิดเท่านั้น ให้ดูที่ verified ไม่ใช่ status code

attempts_remaining จะหายไปเมื่อ session ถูกล็อก ซึ่งไม่เท่ากับ 0 หน้าจอที่แสดง "เหลือ N ครั้ง" ควรไม่แสดงอะไรเลยในกรณีนั้น

ตรวจสอบรหัสที่สร้างจากที่อื่น ​

bash
curl -X POST "$ME_BASE/otp/verify" \
  -H "API-Key: $ME_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
        "phone_number": "+66886578553",
        "code": "884213",
        "ref_code": "A1B2",
        "purpose": "signup"
      }'
ฟิลด์หมายเหตุ
phone_numberรูปแบบ E.164
codeรหัสที่ผู้ใช้กรอก
ref_codeรหัสอ้างอิงที่ได้ตอนสร้างรหัส
emailไม่บังคับ
purposeขอบเขตการใช้สิทธิ์ เช่น signup, welcome_credit
json
{
  "is_valid": true,
  "status": "verified",
  "message": "OK",
  "is_new": true
}

is_new อาจไม่มีค่า ซึ่งไม่เท่ากับ false ​

is_new ตอบคำถามว่า "หมายเลขนี้ใช้สิทธิ์สำหรับ purpose นี้เป็นครั้งแรกหรือไม่" ค่านี้จะไม่ถูกส่งมาเมื่อไม่มีอะไรให้ตอบ คือไม่ได้ส่ง purpose มา หรือระบบบันทึกสิทธิ์ติดต่อไม่ได้

ความต่างนี้สำคัญมากถ้าคุณใช้ค่านี้ตัดสินการให้สิทธิ์

ts
// ถูกต้อง: ถ้าไม่มีค่า ให้ระงับไว้ ไม่ใช่จ่ายสิทธิ์ทั้งที่ยังไม่รู้
if (res.is_new === true) grantWelcomeCredit();

การถือว่าไม่มีค่าเท่ากับ false นั้นปลอดภัย แต่ถ้าเขียนกลับด้าน (if (!res.is_new)) จะกลายเป็นจ่ายสิทธิ์ทุกครั้งที่เกิดข้อผิดพลาด แทนที่จะไม่จ่ายเลย

API key เป็นตัวระบุโปรเจกต์ ​

Key จะ resolve ไปยังโปรเจกต์เดียว และการใช้สิทธิ์จะถูกบันทึกกับโปรเจกต์นั้น key ที่ resolve ไม่ได้จะถูกปฏิเสธด้วย 401 — ดู การยืนยันตัวตน