ตัวอย่างการใช้งาน API นักข่าว

ดึงเฉพาะ สถานะเซิร์ฟเวอร์ BIT CITIES (ER:LC) ไปแสดงบนเว็บหรือโปรเจกต์ของคุณได้ฟรี ผ่าน JSON API หรือวิดเจ็ตสำเร็จรูป (มีกราฟผู้เล่นย้อนหลัง + 3 ธีม) โดยต้องแสดงเครดิตว่าข้อมูลมาจาก API นักข่าว BIT NEWS ทุกครั้ง

1 วิดเจ็ตสำเร็จรูป (ตัวอย่างสด)

วางแท็ก script ครั้งเดียว วิดเจ็ตจะดึงสถานะ + กราฟผู้เล่นย้อนหลัง และรีเฟรชอัตโนมัติ พร้อมแสดงเครดิตกลับมาที่ BIT NEWS ให้ในตัว รองรับ 3 ธีม: นักข่าว, มืด และ ขาว

ธีมนักข่าว · ไทย
ธีมมืด · ไทย
ธีมขาว · อังกฤษ
HTML — ฝังวิดเจ็ต (ธีมนักข่าว + กราฟ 6 ชม.)
<script src="https://bitnewsth.qd.je/widget.js" data-theme="news" data-lang="th" data-chart="true" data-chart-range="6h" data-interval="30" async></script>

ตัวเลือก: data-theme="news|dark|light" · data-lang="th|en" · data-chart="true|false" (เปิด/ปิดกราฟ) · data-chart-range="6h|24h|7d|30d" · data-interval="10-300" (วินาที) · data-target="#selector" (กำหนดตำแหน่งที่แสดง)

2 JSON API

เรียกด้วย GET ได้เลย ไม่ต้องมีคีย์ · จำกัด 120 ครั้ง/นาที ต่อ IP · แคช 15–60 วินาที · ทุก endpoint เรียกได้ทั้ง /api/public/* และ /api/public/v1/*

GET https://bitnewsth.qd.je/api/public/server-status
GET https://bitnewsth.qd.je/api/public/server-status/history?range=6h
GET https://bitnewsth.qd.je/api/public/server-status/summary?range=24h
GET https://bitnewsth.qd.je/api/public/server-status/stream
JSON — ตัวอย่างผลลัพธ์สด
กำลังโหลดข้อมูล...
JavaScript — ตัวอย่างการเรียกใช้
fetch('https://bitnewsth.qd.je/api/public/server-status')
  .then(res => res.json())
  .then(data => {
    console.log(data.server.status);       // online | offline | maintenance
    console.log(data.server.playerCount);  // จำนวนผู้เล่น
    console.log(data.server.maxPlayers);   // ความจุเซิร์ฟเวอร์
    console.log(data.roster.departments);  // รายชื่อผู้เล่นแยกตามหน่วยงาน (v1.1.0)
    console.log(data.joinUrl);            // ลิงก์เข้าเซิร์ฟเวอร์
    // ต้องแสดงเครดิต "ข้อมูลจาก API นักข่าว BIT NEWS" คู่กับสถานะที่นำไปแสดง
  })
  .catch(err => console.error('โหลดสถานะไม่สำเร็จ', err));

ฟิลด์ที่ให้ใช้: server.status, server.statusText, server.statusLabel, server.playerCount, server.maxPlayers, server.queueCount, server.staffCount, server.capacityPercent, session, roster, movement, notice, joinUrl, updatedAt — ข้อมูลอื่นของเว็บไม่เปิดผ่าน API นี้
ส่วน history จะคืน points[] (at, players, queue, staff, maxPlayers, status) รองรับ range=6h|24h|7d|30d สำหรับเอาไปวาดกราฟเอง — เลือกเฉพาะฟิลด์ที่อยากได้ด้วย ?fields=players,queue ทั้ง summary (พีค/เฉลี่ย/คิว/uptime %) และ stream (SSE แจ้งเตือนเมื่อสถานะเปลี่ยน) ดูรายละเอียดต่อจากหัวข้อ 5

ตัวอย่างผลลัพธ์ของ /server-status (เพิ่มใน v1.1.0)

JSON
{
  "ok": true,
  "api": "BIT NEWS Journalist API",
  "apiVersion": "1.1.0",
  "server": {
    "status": "online",
    "statusText": "เปิดให้บริการ",
    "statusLabel": "เปิดให้บริการขณะนี้",
    "playerCount": 6,
    "maxPlayers": 50,
    "queueCount": 0,
    "staffCount": 2,
    "capacityPercent": 12
  },
  "session": {
    "openedAt": "2026-10-12T06:27:05.000Z",
    "openedForMs": 1980000,
    "closedAt": "2026-10-12T07:00:47.000Z",
    "closedForMs": 2940000
  },
  "roster": {
    "listedPlayerCount": 6,
    "departments": [
      { "key": "1556545073297100871", "name": "ประชาชน", "emojiUrl": "https://cdn.discordapp.com/emojis/1556545073297100871.png", "count": 2,
        "players": [ { "name": "NEW4024v", "badge": null }, { "name": "popkark27", "badge": null } ] },
      { "key": "1550999320587927702", "name": "Bit Cities Police Department", "emojiUrl": "https://cdn.discordapp.com/emojis/1550999320587927702.png", "count": 1,
        "players": [ { "name": "BoqR_64", "badge": "PD-01" } ] }
    ]
  },
  "movement": {
    "lastJoin":  { "name": "popkark27", "badge": null, "at": "2026-10-12T07:48:00.000Z", "atLabel": "12 ตุลาคม 2569" },
    "lastLeave": { "name": "NEW4024v", "badge": null, "at": "2026-10-12T07:45:00.000Z", "atLabel": "12 ตุลาคม 2569" }
  },
  "notice": "เซิร์ฟเวอร์ไม่ได้เปิดให้บริการตลอด 24 ชั่วโมง เวลาเปิดให้บริการอาจเปลี่ยนแปลงตามจำนวนผู้เล่นและผู้ดูแล",
  "joinUrl": "https://erlc.gg/join/BIT",
  "updatedAt": "2026-10-12T07:50:12.000Z",
  "credit": {
    "required": true,
    "text": "ข้อมูลจาก API นักข่าว BIT NEWS",
    "provider": "BIT NEWS",
    "url": "https://bitnewsth.qd.je/server-status",
    "terms": "https://bitnewsth.qd.je/terms"
  }
}

session คืนเวลาเปิด/ปิดรอบล่าสุดเป็น ISO 8601 พร้อมความยาวรอบเป็นมิลลิวินาที · roster.departments[].emojiUrl คือ URL รูปโมโดจิหน่วยงานจาก Discord CDN (อาจเป็น null ถ้าบอทไม่ได้แนบรูปมา) · roster.departments[].players[].badge คือรหัสประจำตัวในเซิร์ฟเวอร์ คืน null ได้ · ทุกฟิลด์ชุดใหม่นี้เป็นข้อมูลที่บอทสถานะรายงานจริง ถ้าบอทยังไม่ได้ส่งมา จะได้ค่า null หรืออาร์เรย์ว่าง ไม่ใช่ค่าที่ระบบเดาขึ้นมา

3 คู่มือ API กราฟ (History API) ฉบับละเอียด

API นี้คืนจุดข้อมูลย้อนหลังแบบย่อ สำหรับนำไปวาดกราฟจำนวนผู้เล่นและสถานะเซิร์ฟเวอร์เอง เหมาะกับทำแดชบอร์ด สถิติ หรือกราฟฝังเว็บ โดยไม่เปิดเผยข้อมูลอื่นของเว็บ

1. Endpoint

GET https://bitnewsth.qd.je/api/public/server-status/history

2. Query parameters

พารามิเตอร์ประเภทค่าเริ่มต้นคำอธิบาย
range string 6h ช่วงเวลาย้อนหลัง รองรับ 6h (6 ชั่วโมง), 24h (24 ชั่วโมง), 7d (7 วัน), 30d (30 วัน) — หากส่งค่าอื่น ระบบจะใช้ 6h แทน
fields string ทั้งหมด เลือกฟิลด์ของจุดกราฟที่อยากได้ คั่นด้วยจุลภาค เช่น ?fields=players,queue — at และ status คงไว้เสมอ (ใช้ลดขนาดไฟล์เวลาเอาไปวาดกราฟเล็กๆ)

3. ตัวอย่างผลลัพธ์ (200 OK)

JSON
{
  "ok": true,
  "api": "BIT NEWS Journalist API",
  "apiVersion": "1.1.0",
  "range": "24h",
  "rangeLabel": "24 ชั่วโมง",
  "rangeMs": 86400000,
  "sampleCount": 288,
  "fields": ["at", "players", "queue", "staff", "maxPlayers", "status"],
  "points": [
    { "at": 1790982600000, "players": 12, "queue": 0, "staff": 1, "maxPlayers": 50, "status": "online" },
    { "at": 1790983200000, "players": 27, "queue": 3, "staff": 2, "maxPlayers": 50, "status": "online" },
    { "at": 1790983800000, "players": 0,  "queue": 0, "staff": 0, "maxPlayers": 50, "status": "offline" }
  ],
  "updatedAt": "2026-10-03T05:10:00.000Z",
  "credit": {
    "required": true,
    "text": "ข้อมูลจาก API นักข่าว BIT NEWS",
    "provider": "BIT NEWS",
    "url": "https://bitnewsth.qd.je/server-status",
    "terms": "https://bitnewsth.qd.je/terms"
  }
}

4. คำอธิบายฟิลด์ทั้งหมด

ฟิลด์ประเภทคำอธิบาย
okbooleantrue เมื่อโหลดข้อมูลสำเร็จ
api / apiVersionstringชื่อ API และเวอร์ชันที่ตอบกลับมารอบนี้
rangestringช่วงเวลาที่ยังผลจริงหลังตรวจสอบค่าแล้ว
rangeLabelstringชื่อช่วงเวลาแบบอ่านง่ายเช่น 24 ชั่วโมง
rangeMsnumberความยาวของช่วงเวลา หน่วยเป็นมิลลิวินาที (6h = 21600000, 24h = 86400000, 7d = 604800000, 30d = 2592000000)
sampleCountnumberจำนวนจุดทั้งหมดของช่วงนั้น ก่อนระบบย่อข้อมูล
fieldsarrayฟิลด์ที่จุดกราฟมีจริงในรอบนี้ (เปลี่ยนตาม ?fields=)
pointsarrayจุดกราฟ เรียงจากเก่าไปใหม่ (ถูกย่อให้ไม่เกิน ~121 จุด เพื่อให้ไฟล์เล็ก)
points[].atnumberเวลาของจุดนั้น เป็น Unix timestamp หน่วยมิลลิวินาที (UTC)
points[].playersnumber | nullจำนวนผู้เล่น ณ เวลานั้น — อาจเป็น null กรณีไม่มีข้อมูล ควรกันค่าไว้ก่อนวาดกราฟ
points[].queuenumber | nullจำนวนคนรอคิวเฉลี่ยของช่วงนั้น (สานกราฟคิวได้เลย ไม่ต้องยิงเพิ่ม)
points[].staffnumber | nullจำนวนผู้ดูแลในเซิร์ฟเวอร์เฉลี่ยของช่วงนั้น
points[].maxPlayersnumber | nullความจุเซิร์ฟเวอร์ที่ระบบรู้ถึง ณ ช่วงนั้น
points[].statusstringสถานะเซิร์ฟเวอร์ ณ จุดนั้น: online / offline / maintenance
updatedAtstring | nullเวลาของจุดล่าสุด รูปแบบ ISO 8601
creditobjectข้อมูลเครดิตที่ต้องแสดง: required, text, provider, url, terms

5. การทำงานของระบบ & ข้อควรทราบ

  • แคช 60 วินาที (มี stale-while-revalidate 120 วินาที) — เรียกถี่กว่านี้จะได้ข้อมูลเดิม แต่มี ETag ตรวจให้ ถ้าไม่เปลี่ยนจะคืน 304 ไม่ส่ง body ซ้ำ
  • Rate limit 120 ครั้ง/นาที/IP — เกินจะได้ HTTP 429 พร้อม header Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset
  • CORS เปิด Access-Control-Allow-Origin: * เรียกจากเว็บไซต์ใดก็ได้ ไม่ต้องมีคีย์
  • ระบบบันทึกสถานะอัตโนมัติเป็นช่วงสั้น ๆ แล้วนำมาสรุปเป็นจุดกราฟ — จุดล่าสุดอาจช้ากว่าเวลาจริงเล็กน้อย
  • หาก sampleCount มากกว่าจำนวนจุดที่ได้รับ แปลว่าระบบย่อจุดแล้ว (จุดแรกและจุดสุดท้ายถูกเก็บไว้เสมอ)
  • เวลาเป็น UTC (Unix ms) — แปลงเป็นเวลาไทยได้ด้วย toLocaleString('th-TH', { timeZone: 'Asia/Bangkok' })
  • ต้องแสดงเครดิต “ข้อมูลจาก API นักข่าว BIT NEWS” ควบคู่กับกราฟที่นำไปแสดงเสมอ

6. ตัวอย่างโค้ดดึงข้อมูลไปวาดกราฟ

JavaScript
async function loadChartPoints(range = '24h') {
  const res = await fetch(
    'https://bitnewsth.qd.je/api/public/server-status/history?range=' + range,
    { headers: { Accept: 'application/json' } }
  );
  if (!res.ok) throw new Error('โหลดไม่สำเร็จ: HTTP ' + res.status);
  const data = await res.json();

  // เวลาสิ้นสุด = ปัจจุบัน, เริ่มต้น = ย้อนหลังตาม rangeMs
  const endAt = Date.now();
  const startAt = endAt - data.rangeMs;

  // แปลงจุดเป็นพิกัด: x ตามเวลา, y ตามจำนวนผู้เล่น
  const xOf = at => ((at - startAt) / data.rangeMs) * chartWidth;
  const maxPlayers = Math.max(...data.points.map(p => p.players || 0), 1);
  const yOf = v => chartHeight - (v / maxPlayers) * chartHeight;

  // วาดเส้น (ข้ามจุดที่ players = null ได้)
  const path = data.points
    .filter(p => p.players != null)
    .map((p, i) => (i ? 'L' : 'M') + xOf(p.at) + ' ' + yOf(p.players))
    .join(' ');

  // อย่าลืมแสดงเครดิต "ข้อมูลจาก API นักข่าว BIT NEWS" ใต้กราฟ
  return { points: data.points, path, credit: data.credit };
}

7. กรณีผิดพลาด

HTTPตัวอย่างผลลัพธ์เกิดเมื่อ
429{ "error": "ส่งคำขอเร็วเกินไป กรุณาลองใหม่ภายหลัง" }เรียกเกิน 120 ครั้ง/นาที จาก IP เดียวกัน (ดู header Retry-After)
500{ "ok": false, "error": "ไม่สามารถโหลดประวัติสถานะได้" }ระบบฐานข้อมูลขัดข้องชั่วคราว
503{ "error": "ระบบกำลังบำรุงรักษา กรุณาลองใหม่ภายหลัง" }เว็บอยู่ในโหมดบำรุงรักษา

4 ตัวอย่างกราฟสดจาก API

กราฟด้านล่างดึงข้อมูลจริงจาก /api/public/server-status/history โดยตรง สลับช่วงเวลาได้ — เป็นตัวอย่างการนำ points[] ไปวาดกราฟ (ชี้เมาส์บนกราฟเพื่อดูรายละเอียด)

กำลังโหลด...

เส้นชมพู = ค่าสูงสุดในช่วงที่เลือก · แถบใต้กราฟ: เขียว = เปิด, เหลือง = ปรับปรุง, แดง = ปิด · ข้อมูลจาก API นักข่าว BIT NEWS

5 มาตรฐาน HTTP · เวอร์ชัน v1 · กรณีข้อผิดพลาด

API ทุกตัวตอบกลับในรูปแบบเดียวกัน (JSON + header ครบ) — เรียกได้ทั้ง /api/public/* (เดิม) และ /api/public/v1/* (เวอร์ชันปัจจุบัน เหมือนกันทุก field) แนะนำให้ยึด v1 ไว้นานเพราะมันคือ path ที่ดึงไปใช้ได้นาน ๆ โดยไม่หลุดของที่เคยเขียนไว้

1. Header ที่สำคัญ

Headerตัวอย่างใช้ทำอะไร
ETag + If-None-Match"a1b2c3"เก็บ ETag จากรอบก่อนแล้วยิงใหม่พร้อม If-None-Match — ถ้าไม่เปลี่ยนจะได้ 304 Not Modified ประหยัด bandwidth
Cache-Controlpublic, max-age=60, stale-while-revalidate=120บอก CDN/browser ว่าจะแคชได้นานเท่าไรต่อ endpoint
X-RateLimit-Limit120โควต้าสูงสุดต่อนาที
X-RateLimit-Remaining97โควต้าที่เหลือในนาทีนี้ — เหลือต่ำควรผ่อนการเรียก
X-RateLimit-Reset1790982000เวลาที่โคว toutes รีเซ็ต (Unix seconds)
Retry-After23เมื่อถูก 429 — รอกี่วิก่อนยิงใหม่
X-API-Version1.0.0เวอร์ชันของข้อมูลที่ตอบกลับ
X-Data-CreditBIT NEWS Journalist APIแหล่งที่มาข้อมูล (ใช้กับ log/ตรวจสอบได้)

2. ยกตัวอย่าง v1

JavaScript — เรียก v1 + ถือ ETag ไว้ใช้รอบถัดไป
let etag = null;

async function fetchStatus() {
  const headers = { Accept: 'application/json' };
  if (etag) headers['If-None-Match'] = etag;      // ส่ง ETag รอบเก่ากลับไป

  const res = await fetch('https://bitnewsth.qd.je/api/public/v1/server-status', { headers });
  if (res.status === 304) return null;            // ไม่มีอะไรเปลี่ยน — ไม่ต้องอัปเดตจอ

  etag = res.headers.get('ETag');                 // เก็บไว้ใช้รอบหน้า

  const limit = res.headers.get('X-RateLimit-Remaining');
  if (Number(limit) < 5) console.warn('ใกล้เกินโควต้าแล้ว เหลือ ' + limit);

  const data = await res.json();
  // อย่าลืมแสดงเครดิต "ข้อมูลจาก API นักข่าว BIT NEWS"
  return data.server;
}

3. แบบแผนข้อผิดพลาด (เหมือนกันทุก endpoint)

HTTPcodeตัวอย่างผลลัพธ์เกิดเมื่อ
404NOT_FOUND { "ok": false, "error": "ไม่พบ endpoint นี้", "code": "NOT_FOUND", "docs": ".../api-demo" } path ไม่มีในระบบ — ดูรายการทั้งหมดที่ /api/public
429RATE_LIMITED { "ok": false, "error": "ส่งคำขอเร็วเกินไป กรุณาลองใหม่ภายหลัง", "code": "RATE_LIMITED" } เกิน 120 ครั้ง/นาที/IP (ดู Retry-After)
429TOO_MANY_CONNECTIONS { "ok": false, "error": "การเชื่อมต่อสดจาก IP นี้ครบจำนวนแล้ว", "code": "TOO_MANY_CONNECTIONS" } เปิด SSE เกิน 3 การเชื่อมต่อจาก IP เดียว
500HISTORY_UNAVAILABLE / SUMMARY_UNAVAILABLE { "ok": false, "error": "ไม่สามารถโหลดประวัติสถานะได้", "code": "HISTORY_UNAVAILABLE" } ฐานข้อมูลกราฟขัดข้องชั่วคราว — ลองใหม่ภายหลัง

ทุก error มี ok: false, error (ข้อความไทย), code (ตอนเขียนโปรแกรม), และ docs (ลิงก์คู่มือ) — แนะนำให้ ternary ตาม code ไม่ใช่ตามข้อความ เพราะข้อความอาจปรับรูปได้

6 สถิติสรุป (Summary) & OpenAPI

Summary — สรุปช่วงที่เลือกเป็นตัวเลขเดียวจบ ไม่ต้องเอาจุดกราฟมาคำนวนเอง เหมาะกับทำ “สถิติ 30 วัน” หรือการ์ด pequenoบนหน้าแรก ส่วน OpenAPI — สเปกมาตรฐานนำไป import ใน Postman/Insomnia หรือ generate client ได้ทันที

GET https://bitnewsth.qd.je/api/public/server-status/summary?range=24h
GET https://bitnewsth.qd.je/api/public/openapi.json
JSON — ตัวอย่างผลลัพธ์ Summary
{
  "ok": true,
  "api": "BIT NEWS Journalist API",
  "apiVersion": "1.1.0",
  "range": "24h",
  "rangeLabel": "24 ชั่วโมง",
  "rangeMs": 86400000,
  "summary": {
    "sampleCount": 17280,
    "peakPlayers": 43,
    "peakAt": "2026-10-08T13:20:00.000Z",
    "minPlayers": 0,
    "avgPlayers": 24,
    "peakQueue": 6,
    "avgQueue": 1,
    "uptimePercent": 31,
    "openHours": 7.4,
    "maintenanceHours": 0,
    "offlineHours": 16.6,
    "hasData": true
  },
  "updatedAt": "2026-10-08T18:45:00.000Z",
  "credit": { "required": true, "text": "ข้อมูลจาก API นักข่าว BIT NEWS" }
}

range ไม่ส่งมาหรือส่งผิด = 24h ( summary เริ่มกลางวัน ส่วน history ยังคง 6h เหมือนเดิม) — uptimePercent เป็น null เมื่อช่วงนั้นยังไม่มีข้อมูลเลย

7 เรียลไทม์กับ SSE (ไม่ต้องวน fetch เอง)

เปิดสตรีมหนึ่งครั้ง แล้วรอรับเหตุการณ์มาวาดต่อ — ระบบ poll ให้อยู่ในตัว ส่งต่อเฉพาะตอนค่ามีเปลี่ยนแปลงจริง (ผู้เล่น/คิว/สถานะ) พร้อม ping ค้างการเชื่อมต่อทุก 15 วิ เหมาะกับหน้าจอที่เปิดทิ้งไว้ทั้งวัน

ยังไม่เชื่อมต่อ
กด “เชื่อมต่อสตรีม” เพื่อทดสอบ — เหตุการณ์ที่เข้ามาจะโชว์ที่นี่
JavaScript — ใช้ EventSource กับ SSE
const source = new EventSource('https://bitnewsth.qd.je/api/public/server-status/stream');

source.addEventListener('snapshot', (ev) => {
  const data = JSON.parse(ev.data);      // มาครบชุดหนึ่งรอบ ตอนเพิ่งเชื่อมต่อ
  render(data.server);
});

source.addEventListener('status', (ev) => {
  const data = JSON.parse(ev.data);      // ส่งต่อก็ต่อเมื่อค่าเปลี่ยนจริง
  render(data.server);
});

source.onerror = () => {
  // browser จะพยายาม reconnect เอง หากเน็ตหลุด
  console.warn('สตรีมหลุด กำลังลองใหม่...');
};

// อย่าลืมแสดงเครดิต "ข้อมูลจาก API นักข่าว BIT NEWS" ใต้สถานะที่นำไปแสดง

เหตุการณ์: snapshot (ตอนเชื่อมต่อ), status (เมื่อค่าเปลี่ยน), heart beat : ping ทุก 15 วิ · จำกัด 3 การเชื่อมต่อต่อ IP · ปิดแล้วคำนวณแบนด์วิดท์แค่ไม่กี่ KB/ชม. · ไม่ต้องมีคีย์เหมือน endpoint อื่น

เงื่อนไขการใช้งาน:

ทุกการนำข้อมูลไปใช้ (ทั้ง JSON API และวิดเจ็ต) ต้องแสดงเครดิตว่า “ข้อมูลจาก API นักข่าว BIT NEWS” อย่างชัดเจน โดยลิงก์กลับมาที่หน้าสถานะเซิร์ฟเวอร์ และห้ามดัดแปลงหรือลบเครดิตในวิดเจ็ต

📰 ข้อมูลจาก API นักข่าว BIT NEWS