SMSTH Public API v1

เชื่อมระบบของคุณ (เว็บไซต์ ร้านค้าออนไลน์ POS CRM แอป) เข้ากับ SMSTH เพื่อส่ง SMS แจ้งเตือน ส่ง OTP ยืนยันตัวตน และยิงแคมเปญ โดยใช้เครดิตเดียวกับบัญชีบนเว็บ 1 เครดิต = 1 ข้อความ

Base URL: https://likesms.me/v1 · รูปแบบข้อมูล: JSON (UTF-8) · HTTPS เท่านั้น

เริ่มต้น 5 นาที

  1. เข้าสู่ระบบ likesms.me แล้วไปที่เมนู API สำหรับนักพัฒนา
  2. กด สร้าง API key แล้วคัดลอกเก็บไว้ทันที (ระบบแสดงครั้งเดียว)
  3. ตรวจชื่อผู้ส่ง (Sender) ที่บัญชีใช้ได้ด้วย GET /v1/senders
  4. ส่งข้อความแรก:
curl -X POST https://likesms.me/v1/sms/send \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"to":"0812345678","sender":"MYBRAND","message":"คำสั่งซื้อ #1024 จัดส่งแล้ว","ref":"order-1024"}'
  1. เก็บ id ที่ได้กลับมา ใช้เช็คสถานะด้วย GET /v1/messages/{id} หรือรอ webhook แจ้งกลับ
เก็บ API key ไว้ฝั่งเซิร์ฟเวอร์เท่านั้น ห้ามใส่ในโค้ดหน้าเว็บ (JavaScript) หรือแอปมือถือ ถ้าหลุดให้กด สร้าง key ใหม่ ทันที key เดิมจะใช้ไม่ได้

การยืนยันตัวตน

ส่ง API key ใน header ทุก request

Authorization: Bearer sk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

ถ้าระบบของคุณตั้ง header Authorization ไม่ได้ ใช้ X-API-Key: sk_live_... แทนได้

รูปแบบ Response

สำเร็จ (HTTP 200):

{ "success": true, "data": { "...": "..." } }

ผิดพลาด (HTTP 4xx/5xx):

{ "success": false, "error": { "code": "INSUFFICIENT_CREDITS", "message": "เครดิตไม่เพียงพอ ต้องการ 50 เครดิต แต่มีเพียง 8 เครดิต", "details": { "required": 50, "available": 8 } } }

ให้ตรวจ error.code ในโค้ด (ค่าคงที่) ส่วน error.message เป็นภาษาไทยสำหรับแสดงผล

Rate limit

Error codes

codeHTTPความหมาย / ควรทำอะไร
UNAUTHORIZED401ไม่มี key, key ผิด หรือบัญชีถูกระงับ
HTTPS_REQUIRED403เรียกผ่าน http:// — เปลี่ยนเป็น https://
IP_NOT_ALLOWED403IP ไม่อยู่ใน allow-list ของบัญชี
SENDER_NOT_ALLOWED403บัญชีไม่มีสิทธิ์ใช้ sender นี้ — ดู GET /v1/senders
NOT_FOUND404ไม่พบ endpoint หรือข้อมูล (หรือเป็นของบัญชีอื่น)
METHOD_NOT_ALLOWED405ใช้ GET/POST ไม่ตรงกับ endpoint
VALIDATION_ERROR422ข้อมูลไม่ครบ/ผิดรูปแบบ ดู message
OTP_INVALID422รหัส OTP ผิดหรือหมดอายุ
INSUFFICIENT_CREDITS402เครดิตไม่พอ — เติมเครดิตที่เว็บ ระบบไม่หักเครดิตในกรณีนี้
RATE_LIMITED429เรียกถี่เกิน รอตาม Retry-After
PROVIDER_ERROR502เครือข่ายปลายทางปฏิเสธ เช่น พบคำต้องห้าม (เครดิตถูกคืนอัตโนมัติ)
INTERNAL_ERROR500ระบบขัดข้องชั่วคราว ลองใหม่ภายหลัง

Endpoints

MethodPathใช้ทำอะไร
POST/v1/sms/sendส่ง SMS 1–100 เบอร์ ทันที
POST/v1/sms/bulkส่งแคมเปญ 1–1,000 เบอร์ ทันทีหรือตั้งเวลา
POST/v1/otp/sendส่งรหัส OTP
POST/v1/otp/verifyตรวจรหัส OTP
GET/v1/messages/{id}สถานะข้อความ
GET/v1/campaigns/{id}สถานะแคมเปญ
GET/v1/account/balanceเครดิตคงเหลือ
GET/v1/sendersชื่อผู้ส่งที่ใช้ได้

POST /v1/sms/send

ส่ง SMS ทันที หักเครดิตตามจำนวนเบอร์ เบอร์ที่ส่งไม่สำเร็จได้เครดิตคืนอัตโนมัติ

ฟิลด์ชนิดจำเป็นรายละเอียด
tostring หรือ arrayใช่เบอร์ไทย เช่น 0812345678, 081-234-5678, +66812345678 สูงสุด 100 เบอร์ (string คั่นด้วย , ได้)
senderstringใช่ชื่อผู้ส่งที่บัญชีมีสิทธิ์
messagestringใช่ข้อความ สูงสุด 1,000 ตัวอักษร (ภาษาไทย 70 ตัวอักษรต่อ 1 SMS)
refstringไม่รหัสอ้างอิงของคุณ (≤64) จะส่งกลับใน webhook และ GET /v1/messages/{id}
{
  "to": ["0812345678", "12"],
  "sender": "MYBRAND",
  "message": "รหัสสมาชิกของคุณคือ A1024",
  "ref": "member-1024"
}

Response:

{
  "success": true,
  "data": {
    "messages": [
      { "id": 5012, "to": "0812345678", "status": "sending" },
      { "to": "12", "status": "failed", "error": "เบอร์โทรศัพท์ไม่ถูกต้อง: 12", "error_type": "invalid_number" }
    ],
    "accepted": 1,
    "failed": 1,
    "credits_used": 1,
    "credits_remaining": 842
  }
}

ถ้าส่งไม่สำเร็จเลยสักเบอร์ จะได้ error (VALIDATION_ERROR เมื่อทุกเบอร์ผิดรูปแบบ หรือ PROVIDER_ERROR) พร้อม details.messages

POST /v1/sms/bulk

สร้างแคมเปญ (แสดงในหน้า แคมเปญ บนเว็บด้วย) ส่งข้อความเดียวกันถึงทุกเบอร์ เบอร์ซ้ำถูกตัดอัตโนมัติ หักเครดิตตอนสร้าง ถ้าส่งไม่สำเร็จทั้งแคมเปญจะคืนเครดิตทั้งหมด

ฟิลด์ชนิดจำเป็นรายละเอียด
toarray หรือ stringใช่1–1,000 เบอร์ ทุกเบอร์ต้องถูกรูปแบบ
senderstringใช่ชื่อผู้ส่ง
messagestringใช่≤1,000 ตัวอักษร
namestringไม่ชื่อแคมเปญ (ไม่ใส่ = API วันที่ เวลา)
schedule_atstringไม่ISO 8601 เช่น 2026-10-01T09:00:00+07:00 ต้องเป็นอนาคต ไม่เกิน 30 วัน ไม่ระบุ timezone = เวลาไทย
refstringไม่รหัสอ้างอิงของคุณ
{
  "to": ["0812345678", "0898765432"],
  "sender": "MYBRAND",
  "message": "โปรวันนี้ ลด 20% ทุกรายการ ถึง 22:00",
  "name": "โปรเย็นวันศุกร์",
  "schedule_at": "2026-10-02T17:00:00+07:00"
}
{
  "success": true,
  "data": {
    "campaign_id": 311,
    "name": "โปรเย็นวันศุกร์",
    "total": 2,
    "status": "scheduled",
    "scheduled_at": "2026-10-02T17:00:00+07:00",
    "credits_used": 2,
    "credits_remaining": 840
  }
}

status เป็น sending เมื่อส่งทันที หรือ scheduled เมื่อตั้งเวลา

POST /v1/otp/send

ส่งรหัส OTP (ระบบสร้างรหัสให้) 1 เบอร์ต่อครั้ง ใช้ 1 เครดิต

ฟิลด์ชนิดจำเป็นรายละเอียด
tostringใช่เบอร์ผู้รับ 1 เบอร์
senderstringใช่ชื่อผู้ส่ง
refstringไม่รหัสอ้างอิงของคุณ
{
  "success": true,
  "data": {
    "message_id": 5013,
    "to": "0812345678",
    "token": "b7f1c2e0-...",
    "ref_code": "ABCD",
    "credits_used": 1,
    "credits_remaining": 839
  }
}

เก็บ token ไว้ฝั่งเซิร์ฟเวอร์ แสดง ref_code ให้ผู้ใช้เทียบกับ SMS ที่ได้รับ

POST /v1/otp/verify

ฟิลด์ชนิดจำเป็นรายละเอียด
tokenstringใช่token จาก /v1/otp/send (ต้องเป็นของบัญชีนี้)
codestringใช่รหัสที่ผู้ใช้กรอก
{ "success": true, "data": { "verified": true, "message_id": 5013 } }

รหัสผิดหรือหมดอายุ: HTTP 422 OTP_INVALID

GET /v1/messages/{id}

{
  "success": true,
  "data": {
    "id": 5012,
    "to": "0812345678",
    "sender": "MYBRAND",
    "type": "plain",
    "status": "delivered",
    "ref": "member-1024",
    "created_at": "2026-09-25T14:03:05+07:00",
    "updated_at": "2026-09-25T14:03:11+07:00"
  }
}
statusความหมาย
queuedรอคิวส่ง
sendingส่งแล้ว รอรายงานการส่งถึง
deliveredถึงเครื่องผู้รับแล้ว
failedส่งไม่สำเร็จ

GET /v1/campaigns/{id}

{
  "success": true,
  "data": {
    "id": 311, "name": "โปรเย็นวันศุกร์", "status": "sending", "ref": null,
    "total": 2, "delivered": 1, "failed": 0, "pending": 1,
    "scheduled_at": "2026-10-02T17:00:00+07:00", "created_at": "2026-09-25T14:10:00+07:00"
  }
}

status ของแคมเปญ: queued (รอเวลา), processing, sending, delivered (จบ), failed, cancelled

GET /v1/account/balance

{ "success": true, "data": { "credits": 839, "unit": "credit", "note": "1 เครดิต = 1 ข้อความ" } }

GET /v1/senders

{ "success": true, "data": { "senders": ["MYBRAND", "MYSHOP"], "default": "MYBRAND" } }

ต้องการชื่อผู้ส่งใหม่ ติดต่อทีมงานทาง LINE เพื่อยื่นขออนุมัติ

Webhook แจ้งสถานะ

ตั้ง URL ในหน้า API สำหรับนักพัฒนา (ต้องเป็น https) ระบบจะส่ง POST เมื่อข้อความที่ส่งผ่าน API มีสถานะสุดท้าย (delivered / failed) และเมื่อแคมเปญจาก API จบ

POST /webhooks/smsth HTTP/1.1
Content-Type: application/json
X-SMSTH-Event: message.status
X-SMSTH-Delivery: 9812
X-SMSTH-Signature: sha256=5d41402abc4b2a76b9719d911017c592...
{
  "event": "message.status",
  "message_id": 5012,
  "to": "0812345678",
  "status": "delivered",
  "ref": "member-1024",
  "sender": "MYBRAND",
  "timestamp": "2026-09-25T14:03:11+07:00"
}

แคมเปญจบ (X-SMSTH-Event: campaign.status):

{
  "event": "campaign.status", "campaign_id": 311, "name": "โปรเย็นวันศุกร์", "status": "delivered", "ref": null,
  "total": 2, "delivered": 2, "failed": 0, "pending": 0, "timestamp": "2026-10-02T17:04:40+07:00"
}

กติกา:

ตรวจลายเซ็น

X-SMSTH-Signature = sha256= + HMAC-SHA256 ของ body ดิบ ด้วย webhook secret ของคุณ ตรวจทุกครั้งก่อนเชื่อข้อมูล

<?php
$secret = getenv('SMSTH_WEBHOOK_SECRET');
$body = file_get_contents('php://input');
$expected = 'sha256=' . hash_hmac('sha256', $body, $secret);
if (!hash_equals($expected, $_SERVER['HTTP_X_SMSTH_SIGNATURE'] ?? '')) {
    http_response_code(401);
    exit;
}
$event = json_decode($body, true);
// บันทึกสถานะ $event['message_id'] / $event['ref'] ในระบบของคุณ
http_response_code(200);
// Node.js + Express
const crypto = require('crypto');
app.post('/webhooks/smsth', express.raw({ type: 'application/json' }), (req, res) => {
  const expected = 'sha256=' + crypto.createHmac('sha256', process.env.SMSTH_WEBHOOK_SECRET).update(req.body).digest('hex');
  const got = req.get('X-SMSTH-Signature') || '';
  if (got.length !== expected.length || !crypto.timingSafeEqual(Buffer.from(got), Buffer.from(expected))) return res.sendStatus(401);
  const event = JSON.parse(req.body);
  res.sendStatus(200);
});
# Python + Flask
import hmac, hashlib, os
from flask import Flask, request, abort
app = Flask(__name__)

@app.post("/webhooks/smsth")
def smsth_webhook():
    body = request.get_data()
    expected = "sha256=" + hmac.new(os.environ["SMSTH_WEBHOOK_SECRET"].encode(), body, hashlib.sha256).hexdigest()
    if not hmac.compare_digest(expected, request.headers.get("X-SMSTH-Signature", "")):
        abort(401)
    event = request.get_json()
    return "", 200

ตัวอย่างโค้ดส่ง SMS

<?php
$ch = curl_init('https://likesms.me/v1/sms/send');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('SMSTH_API_KEY'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'to' => '0812345678',
        'sender' => 'MYBRAND',
        'message' => 'คำสั่งซื้อ #1024 จัดส่งแล้ว',
        'ref' => 'order-1024',
    ], JSON_UNESCAPED_UNICODE),
]);
$res = json_decode(curl_exec($ch), true);
if (!$res['success']) {
    error_log('SMSTH ' . $res['error']['code'] . ': ' . $res['error']['message']);
}
// Node.js 18+
const res = await fetch('https://likesms.me/v1/sms/send', {
  method: 'POST',
  headers: { Authorization: `Bearer ${process.env.SMSTH_API_KEY}`, 'Content-Type': 'application/json' },
  body: JSON.stringify({ to: '0812345678', sender: 'MYBRAND', message: 'คำสั่งซื้อ #1024 จัดส่งแล้ว', ref: 'order-1024' }),
});
const json = await res.json();
if (!json.success) console.error(json.error.code, json.error.message);
# Python 3 + requests
import os, requests
r = requests.post(
    "https://likesms.me/v1/sms/send",
    headers={"Authorization": f"Bearer {os.environ['SMSTH_API_KEY']}"},
    json={"to": "0812345678", "sender": "MYBRAND", "message": "คำสั่งซื้อ #1024 จัดส่งแล้ว", "ref": "order-1024"},
    timeout=30,
)
data = r.json()
if not data["success"]:
    print(data["error"]["code"], data["error"]["message"])

ตัวอย่าง OTP ครบวงจร:

# 1) ส่ง OTP
curl -X POST https://likesms.me/v1/otp/send -H "Authorization: Bearer $SMSTH_API_KEY" \
  -H "Content-Type: application/json" -d '{"to":"0812345678","sender":"MYBRAND"}'
# 2) ผู้ใช้กรอกรหัส → ตรวจ
curl -X POST https://likesms.me/v1/otp/verify -H "Authorization: Bearer $SMSTH_API_KEY" \
  -H "Content-Type: application/json" -d '{"token":"TOKEN_จากข้อ1","code":"123456"}'

แนวปฏิบัติที่แนะนำ

คำถามพบบ่อย

ส่งแล้วหักเครดิตเท่าไร? 1 เครดิตต่อเบอร์ต่อครั้ง เบอร์ที่ส่งไม่สำเร็จคืนอัตโนมัติ

ข้อความยาวคิดอย่างไร? ระบบคิด 1 เครดิตต่อเบอร์ต่อคำขอ ข้อความยาวอาจถูกเครือข่ายแบ่งเป็นหลาย SMS ที่ปลายทาง แนะนำภาษาไทยไม่เกิน 70 ตัวอักษร

มี sandbox ไหม? v1 ยังไม่มี ทดสอบด้วยเบอร์ของคุณเองและดูประวัติในเมนู ประวัติ SMS (ข้อความจาก API จะแสดงรวมกัน)

ข้อความที่ส่งผ่าน API เห็นบนเว็บไหม? เห็น — ใน ประวัติ SMS และแคมเปญจาก /v1/sms/bulk อยู่ในหน้า แคมเปญ

ต้องการ sender ใหม่ / วอลุ่มสูง / ใบเสนอราคา? ติดต่อทีมงานทาง LINE จากหน้าแรก likesms.me

Changelog

อัปเดตล่าสุด 25/09/2026 · © 2026 SMSTH