เอกสาร API — ส่งชัวร์ (REST API v1)

API สำหรับตรวจสอบความเสี่ยงการจัดส่ง COD และรายงานผลการจัดส่ง สำหรับร้านค้าสมาชิกระดับ API ที่ผ่านการยืนยันตัวตน (KYC) แล้วเท่านั้น

Base URL (ระหว่างพัฒนา): http://localhost:3000

> 💡 OpenAPI 3.0 Spec: สามารถดาวน์โหลดข้อกำหนด API ฉบับเต็มในรูปแบบ OpenAPI 3.0 / Swagger / Postman ได้ที่ [/api/openapi.json](file:///api/openapi.json) (หรือ URL https://www.sendsures.com/api/openapi.json)

การยืนยันตัวตน (Authentication)

สร้าง API key ได้จากหน้า ตั้งค่า → API keys ในคอนโซลร้านค้า ระบบแสดงคีย์เพียงครั้งเดียวตอนสร้าง — โปรดเก็บไว้ในที่ปลอดภัย

ส่งคีย์ผ่านเฮดเดอร์ Authorization ในทุกคำขอ:

Authorization: Bearer ss_live_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

รหัสข้อผิดพลาด (Error codes)

เมื่อเกิดข้อผิดพลาด ระบบตอบกลับในรูปแบบเดียวกันทุกจุด:

{
  "error": {
    "code": "RATE_LIMITED",
    "message_th": "มีการเรียกใช้งานถี่เกินไป กรุณาลองใหม่ภายหลัง",
    "message_en": "Rate limit exceeded"
  }
}
| code | HTTP | ความหมาย |
|---|---|---|
| PHONE_REQUIRED | 400 | ไม่ได้ระบุหมายเลขโทรศัพท์ (จำเป็นทุกครั้ง) |
| INVALID_TH_PHONE | 400 | รูปแบบหมายเลขโทรศัพท์ไทยไม่ถูกต้อง |
| UNAUTHORIZED | 401 | ไม่มีสิทธิ์ / API key ไม่ถูกต้องหรือถูกยกเลิก |
| KYC_REQUIRED | 403 | บัญชีร้านค้ายังไม่ผ่านการยืนยันตัวตน (KYC) |
| RATE_LIMITED | 429 | เรียกใช้งานเกินเพดานที่กำหนด |
| INSUFFICIENT_CREDITS | 402 | เครดิตไม่เพียงพอสำหรับการตรวจสอบ |
| DUPLICATE_TRACKING | 409 | หมายเลขพัสดุนี้ถูกรายงานไปแล้วโดยร้านของคุณ |
| NOT_FOUND | 404 | ไม่พบข้อมูลที่ต้องการ |
| VALIDATION_ERROR | 400 | ข้อมูลที่ส่งมาไม่ผ่านการตรวจสอบรูปแบบ |
| INTERNAL | 500 | ข้อผิดพลาดภายในระบบ |

POST /api/v1/check — ตรวจสอบความเสี่ยงเบอร์โทรศัพท์

ต้องใช้ scope check — ตรวจสอบได้ทีละหนึ่งเบอร์ต่อคำขอ โดย phone เป็นคีย์ค้นหาเพียงอย่างเดียว ส่วน name และ address เป็นข้อมูลประกอบ (ไม่บังคับ) ใช้ปรับระดับความเชื่อมั่นหรือเพิ่มสัญญาณที่อยู่เท่านั้น

คำขอ:

{
  "phone": "0891234567",
  "name": "สมชาย ใจดี",
  "address": "99/12 ม.4 ต.บางรักน้อย อ.เมือง จ.นนทบุรี",
  "ref": "ORDER-1234"
}

ตัวอย่าง curl:

curl -X POST http://localhost:3000/api/v1/check \
  -H "Authorization: Bearer ss_live_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" \
  -H "Content-Type: application/json" \
  -d '{"phone":"0891234567","name":"สมชาย ใจดี","ref":"ORDER-1234"}'

ผลลัพธ์ 200:

{
  "phone_masked": "08X-XXX-4567",
  "score": 67,
  "band": "ORANGE",
  "confidence": "HIGH",
  "recommended_action": "REQUEST_DEPOSIT_OR_TRANSFER",
  "stats": {
    "no_data": false,
    "verified_rejections_6m": 3,
    "verified_rejections_24m": 3,
    "distinct_merchants": 3,
    "total_value_thb": 4150,
    "successful_deliveries_12m": 0,
    "last_event_month": "2026-05"
  },
  "name_match": "match",
  "address_signal": { "has_history": false, "verified_events": 0 },
  "notes": [],
  "disclaimer": "ข้อมูลนี้เป็นสถิติจากรายงานของร้านค้าสมาชิก...",
  "checked_at": "2026-07-26T04:00:00Z"
}

คำอธิบายฟิลด์สำคัญ:

POST /api/v1/reports — ส่งรายงานผลการจัดส่ง

ต้องใช้ scope report — ทุกรายงานต้องมีหมายเลขพัสดุ (tracking number) และจะถูกตรวจสอบกับข้อมูลผู้ให้บริการขนส่งก่อนมีผลต่อคะแนนเสมอ รายงานที่ยังไม่ผ่านการตรวจสอบไม่ถูกนำไปคำนวณ

ประเภทรายงาน (type):

| type | ความหมาย |
|---|---|
| cod_rejected | ผู้รับปฏิเสธรับพัสดุ / พัสดุตีกลับ |
| cancelled_after_ship | ยกเลิกออเดอร์หลังจัดส่งแล้ว |
| return_abuse | การคืนสินค้าที่ผิดปกติ |
| successful_delivery | เหตุการณ์เชิงบวก: รับพัสดุและชำระ COD สำเร็จ |

คำขอ:

{
  "type": "cod_rejected",
  "phone": "0891234567",
  "tracking_no": "MOCKR123456",
  "carrier": "flash",
  "order_value_thb": 1290,
  "order_date": "2026-07-10",
  "customer_name": "สมชาย ใจดี",
  "address": "99/12 ม.4 ต.บางรักน้อย อ.เมือง จ.นนทบุรี"
}

ตัวอย่าง curl:

curl -X POST http://localhost:3000/api/v1/reports \
  -H "Authorization: Bearer ss_live_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" \
  -H "Content-Type: application/json" \
  -d '{"type":"cod_rejected","phone":"0891234567","tracking_no":"MOCKR123456","carrier":"flash","order_value_thb":1290,"order_date":"2026-07-10"}'

ผลลัพธ์ 201:

{ "id": "8b6f8a1e-1234-4cde-9abc-1234567890ab", "verification_status": "pending" }

GET /api/v1/reports — รายการรายงานของร้านคุณ

ดูเฉพาะรายงานของร้านตัวเองเท่านั้น (ไม่มีการเข้าถึงข้อมูลร้านอื่น)

พารามิเตอร์: status (pending | verified | unverifiable | contradicted | disputed | removed), limit (ค่าเริ่มต้น 50), cursor (ค่า next_cursor จากหน้าก่อนหน้า รูปแบบ <ISO datetime>|<uuid>)

curl "http://localhost:3000/api/v1/reports?status=verified&limit=20" \
  -H "Authorization: Bearer ss_live_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"

DELETE /api/v1/reports/:id — ถอนรายงาน

ถอนได้เฉพาะรายงานของร้านตัวเองที่ยังมีสถานะ pending เท่านั้น

curl -X DELETE http://localhost:3000/api/v1/reports/8b6f8a1e-1234-4cde-9abc-1234567890ab \
  -H "Authorization: Bearer ss_live_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"

GET /api/v1/me — ข้อมูลบัญชีร้านค้า

โปรไฟล์ร้าน ระดับการใช้งาน (tier) ยอดเครดิตคงเหลือ และการใช้งานวันนี้

curl http://localhost:3000/api/v1/me \
  -H "Authorization: Bearer ss_live_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"

POST /api/v1/bulk-check — ตรวจสอบหลายเบอร์ในคำขอเดียว

ส่งรายการได้สูงสุด 2,000 รายการต่อคำขอ ประมวลผลแบบ synchronous แต่ละรายการนับเป็นหนึ่งการตรวจสอบตามเพดานการใช้งานปกติ ผลลัพธ์เป็นอาร์เรย์ของผลตรวจ (หรือ error รายแถว)

curl -X POST http://localhost:3000/api/v1/bulk-check \
  -H "Authorization: Bearer ss_live_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" \
  -H "Content-Type: application/json" \
  -d '{"items":[{"phone":"0891234567","ref":"A-1"},{"phone":"0612345678","ref":"A-2"}]}'

POST /api/ingest/feed — รับข้อมูลจากคู่ค้าอัตโนมัติ

ปลายทางสำหรับพันธมิตร push ข้อมูลเข้าระบบ ใช้ Authorization: Bearer ss_feed_... (Feed token สร้างจากหน้า "นำเข้าข้อมูลจัดส่ง" สำหรับคลังสินค้า/OMS หรือผู้ดูแลระบบสร้างให้พันธมิตรขนส่ง) ส่งได้สูงสุด 500 รายการต่อครั้ง, 60 ครั้ง/นาที

Feed แบบร้านค้า (คลังสินค้า / Fulfillment / OMS) — แต่ละรายการกลายเป็นรายงานของร้าน (สถานะรอตรวจสอบ เข้าคิวยืนยันกับขนส่งตามปกติ):

curl -X POST http://localhost:3000/api/ingest/feed \
  -H "Authorization: Bearer ss_feed_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" \
  -H "Content-Type: application/json" \
  -d '{
    "events": [
      {
        "status": "ปฏิเสธรับ",
        "phone": "0891234567",
        "tracking_no": "TH0123456789012",
        "carrier": "flash",
        "order_value_thb": 1290,
        "order_date": "2026-07-10"
      }
    ]
  }'

ค่า status รองรับทั้งไทย/อังกฤษ: จัดส่งสำเร็จ|delivered, ปฏิเสธรับ|refused|returned|rts, ยกเลิกหลังส่ง|cancelled, ตีกลับโดยมิชอบ|return_abuse

Feed แบบขนส่ง (Flash / ไปรษณีย์ไทย / J&T / อื่น ๆ — ผู้ดูแลระบบสร้างให้) — ส่งเฉพาะเลขพัสดุ + สถานะ (ไม่มีข้อมูลส่วนบุคคล) ระบบเก็บเป็นหลักฐานให้เครื่องยืนยันรายงาน ใช้แทนการเรียก API ขนส่ง:

curl -X POST http://localhost:3000/api/ingest/feed \
  -H "Authorization: Bearer ss_feed_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" \
  -H "Content-Type: application/json" \
  -d '{
    "events": [
      { "tracking_no": "TH0123456789012", "status": "5", "occurred_at": "2026-07-27T09:00:00+07:00" }
    ]
  }'

ผลลัพธ์ทั้งสองแบบ: { "total": n, "inserted": n, "duplicates": n, "invalid": n, "errors": [...] }

นำเข้าไฟล์ Excel/CSV — หน้า /app/import รองรับไฟล์ .xlsx/.csv สูงสุด 2,000 แถว (หัวตารางไทยหรืออังกฤษ: สถานะ/status, เบอร์โทร/phone, เลขพัสดุ/tracking_no, ขนส่ง/carrier, มูลค่า/order_value_thb, วันที่/order_date, ชื่อผู้รับ/customer_name, ที่อยู่/address) พร้อมไฟล์ต้นแบบให้ดาวน์โหลดในหน้าเดียวกัน


Webhooks — เหตุการณ์ score.changed

เมื่อระดับความเสี่ยง (band) ของเบอร์ที่ร้านคุณเคยตรวจสอบหรือรายงานภายใน 90 วันมีการเปลี่ยนแปลง ระบบส่ง POST ไปยัง endpoint ที่ตั้งค่าไว้ (หน้า ตั้งค่า → Webhooks):

{
  "event": "score.changed",
  "phone_masked": "08X-XXX-4567",
  "old_band": "YELLOW",
  "new_band": "ORANGE",
  "occurred_at": "2026-07-26T04:00:00Z"
}

การตรวจสอบลายเซ็น: ทุกคำขอมีเฮดเดอร์ X-SongSure-Signature เป็นค่า hex ของ HMAC-SHA256 ของ raw body ด้วย secret ของ endpoint คุณ

// Node.js — ตรวจสอบลายเซ็น webhook
import { createHmac, timingSafeEqual } from "node:crypto";

function verifySongSureSignature(rawBody, signatureHeader, secret) {
  const expected = createHmac("sha256", secret).update(rawBody).digest("hex");
  return timingSafeEqual(Buffer.from(expected), Buffer.from(signatureHeader));
}

เพดานการใช้งาน (Rate limits)

| ระดับ | ตรวจสอบ/วัน | burst/นาที |
|---|---|---|
| free | 20 (จากนั้นหัก 1 เครดิต/ครั้ง) | 10 |
| pro | 2,000 | 60 |
| api | ตามโควตารายเดือนของร้านค้า (`monthly_quota`) | ตาม rate_limit_per_min ของคีย์ |

เมื่อเกินเพดาน ระบบตอบ HTTP 429 พร้อม code RATE_LIMITED


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