PKCryptolisting WebSocket
Hướng dẫn tích hợp

Nhận thông báo theo thời gian thực từ Upbit, Bithumb, Binance và Bybit chỉ với vài dòng mã.
Lấy API key từ bot Telegram và làm theo hướng dẫn bên dưới để kết nối.

ENDPOINT · KR
wss://kr.pkcryptolisting.com
Chỉ Upbit · Bithumb
ENDPOINT · TOKYO
wss://tokyo.pkcryptolisting.com
Upbit · Bithumb · Binance · Bybit
PROTOCOL
WebSocket Secure (WSS)
AUTH
API Key (Cấp qua Telegram)
SERVER LOCATION
AWS Seoul (ap-northeast-2) / AWS Tokyo (ap-northeast-1)
1. Kết nối & Xác thực
Bạn phải gửi tin nhắn xác thực ngay sau khi thiết lập kết nối WebSocket Nếu không xác thực trong vòng 5 giâykết nối sẽ tự động chấm dứt
Để chỉ nhận thông báo từ một sàn giao dịch cụ thể, thêm exchange trường.
⚠️ Lưu ý
wss://kr.pkcryptolisting.com(Korea) endpoint chỉ hỗ trợ UPBIT · BITHUMB.
wss://tokyo.pkcryptolisting.com(Tokyo) endpoint hỗ trợ tất cả sàn giao dịch bao gồm UPBIT · BITHUMB · BINANCE · BYBIT .
pip install websockets
npm install ws
go get github.com/gorilla/websocket
[dependencies]
tokio = { version = "1", features = ["full"] }
tokio-tungstenite = { version = "0.21", features = ["native-tls"] }
futures-util = "0.3"
serde_json = "1"
url = "2"
import asyncio, json, websockets

async def connect():
    async with websockets.connect("wss://kr.pkcryptolisting.com") as ws: # or wss://tokyo.pkcryptolisting.com for all 4 exchanges 

        # send auth message
        await ws.send(json.dumps({
            "type":     "auth",
            "key":      "YOUR_API_KEY",   # issued via Telegram bot
            # "exchange": "Upbit"  # optional: "Upbit" | "Bithumb" (omit for all)
        }))

asyncio.run(connect())
// npm install ws
const WebSocket = require("ws");
const ws = new WebSocket("wss://kr.pkcryptolisting.com"); // or wss://tokyo.pkcryptolisting.com for all 4 exchanges 
ws.on("open", () => {
  // send auth message
  ws.send(JSON.stringify({ type: "auth", key: "YOUR_API_KEY",   // issued via Telegram bot
    // exchange: "Upbit"  // optional: "Upbit" | "Bithumb" (omit for all)
  }));
});
// go get github.com/gorilla/websocket
conn, _, _ := websocket.DefaultDialer.Dial("wss://kr.pkcryptolisting.com", nil) 
 // or wss://tokyo.pkcryptolisting.com for all 4 exchanges 
// send auth message
auth, _ := json.Marshal(map[string]string{"type": "auth", "key": "YOUR_API_KEY"})
// "exchange": "Upbit"  // optional: "Upbit" | "Bithumb" (omit for all)
conn.WriteMessage(websocket.TextMessage, auth)
let url = url::Url::parse("wss://kr.pkcryptolisting.com").unwrap();
 // or wss://tokyo.pkcryptolisting.com for all 4 exchanges 
let (mut ws, _) = connect_async(url).await.unwrap();
// send auth message
let auth = serde_json::json!({"type": "auth", "key": "YOUR_API_KEY"
  // "exchange": "Upbit"  // optional: "Upbit" | "Bithumb" (omit for all)
}).to_string();
ws.send(Message::Text(auth)).await.ok();
2. Phản hồi xác thực
Khi xác thực thành công, thông tin về gói, độ trễ và ngày hết hạn sẽ được trả về.
✓ Thành công (auth_ok)
{
  "type":       "auth_ok",
  "plan":       "premium",
  "delay_ms":   0,
  "expires_at": "2026-06-30",
  "message":   "Connected..."
}
✕ Thất bại (error)
{
  "type":    "error",
  "code":    4004,
  "message": "Invalid key"
}
3. Nhận tin nhắn
Sau khi xác thực, các thông báo mới sẽ được nhận tự động khi phát hiện. async for sẽ tự động thoát vòng lặp khi kết nối chấm dứt.
# message loop — exits cleanly on disconnect
    async for raw in ws:
        msg      = json.loads(raw)
        msg_type = msg.get("type")
    
        if msg_type == "auth_ok":
            print(f"connected  plan={msg['plan']}  delay={msg['delay_ms']}ms")
    
        elif msg_type == "error":
            print(f"error {msg['code']}: {msg['message']}")
            break
    
        elif msg_type == "plan_updated":  # plan changed
            print(f"plan updated: {msg['plan']}  delay={msg['delay_ms']}ms")
    
        else:  # announcement
            print(f"[{msg['exchange']}] {msg['title']}")
            print(f"  symbol={msg['symbol']}  detected={msg['detectedTime']} {msg.get('timezone', '')}")
// message loop — exits cleanly on disconnect
    ws.on("message", (raw) => {
      const msg = JSON.parse(raw);
      if (msg.type === "auth_ok")
        console.log(`connected  plan=${msg.plan}  delay=${msg.delay_ms}ms`);
      else if (msg.type === "error") { console.log(`error ${msg.code}: ${msg.message}`); ws.close(); }
      else if (msg.type === "plan_updated")  // plan changed
        console.log(`plan updated: ${msg.plan}  delay=${msg.delay_ms}ms`);
      else {  // announcement
        console.log(`[${msg.exchange}] ${msg.title}`);
        console.log(`  symbol=${msg.symbol}  detected=${msg.detectedTime} ${msg.timezone || ''}`);
      }
    });
// message loop — exits cleanly on disconnect
    for {
        _, raw, err := conn.ReadMessage()
        if err != nil { break }
        var msg map[string]interface{}
        json.Unmarshal(raw, &msg)
        switch msg["type"] {
        case "auth_ok":  fmt.Printf("connected  plan=%v  delay=%vms
    ", msg["plan"], msg["delay_ms"])
        case "error":    fmt.Printf("error %v: %v
    ", msg["code"], msg["message"]); break
        case "plan_updated":  // plan changed
            fmt.Printf("plan updated: %v  delay=%vms
    ", msg["plan"], msg["delay_ms"])
        default:  // announcement
            fmt.Printf("[%v] %v
    ", msg["exchange"], msg["title"])
            fmt.Printf("  symbol=%v  detected=%v %v
    ", msg["symbol"], msg["detectedTime"], msg["timezone"])
        }
    }
// message loop — exits cleanly on disconnect
    while let Some(Ok(raw)) = ws.next().await {
        let msg: Value = serde_json::from_str(&raw.to_string()).unwrap_or_default();
        match msg["type"].as_str().unwrap_or("") {
            "auth_ok" => println!("connected  plan={}  delay={}ms", msg["plan"], msg["delay_ms"]),
            "error" => { println!("error {}: {}", msg["code"], msg["message"]); break; }
            "plan_updated" =>  // plan changed
                println!("plan updated: {}  delay={}ms", msg["plan"], msg["delay_ms"]),
            _ => {  // announcement
                println!("[{}] {}", msg["exchange"], msg["title"]);
                println!("  symbol={}  detected={} {}", msg["symbol"], msg["detectedTime"], msg["timezone"]);
            }
        }
    }
4. Định dạng dữ liệu nhận
Dữ liệu thông báo được gửi theo định dạng sau. symbol có thể là một chuỗi đơn, một mảng, hoặc một chuỗi rỗng.
⚠️ Lưu ý
title, category Các trường được nhận bằng UPBIT · BITHUMB cho tiếng Hàn, và bằng BINANCE · BYBIT cho tiếng Anh gốc.
detectedTimeThời điểm hệ thống của chúng tôi phát hiện thông báo (độ chính xác micro giây)
{
  "title":        "펏지펭귄(PENGU) 신규 거래지원 안내 (KRW, BTC, USDT 마켓)",
  "category":     "거래",
  "symbol":       "PENGU",       
  "exchange":     "Upbit",      
  "detectedTime": "2025-05-09 15:00:00.333851",
  "timezone":     "KST",
  "url":          "https://www.upbit.com/service_center/notice?id=5104&view=share"
}
TrườngLoạiMô tả
titlestringTiêu đề gốc của thông báo sàn giao dịch
categorystringDanh mục thông báo — tham khảo danh sách danh mục bên dưới
symbolstring | array Ký hiệu coin được trích xuất. Đơn lẻ: "BTC", Nhiều: ["BTC","ETH"], Trống: "", Gói Free: "***"
exchangestring Sàn giao dịch nguồn: "Upbit", "Bithumb", "Binance", "Bybit"
detectedTimestring Thời điểm hệ thống của chúng tôi phát hiện thông báo (độ chính xác micro giây). Gói Basic có +30ms độ trễ bổ sung
timezonestring Múi giờ cơ sở cho detectedTime. KST (Upbit, Bithumb) hoặc UTC (Binance, Bybit)
urlstringLiên kết đến thông báo gốc
Khác biệt giữa các gói
Tất cả các gói đều chạy trên cùng hạ tầng. Chỉ khác nhau về độ trễ và khả năng hiển thị ký hiệu.
Free
0ms độ trễ
Ký hiệu *** Đã che
Basic
+30ms độ trễ
Hiển thị đầy đủ ký hiệu
Premium
0ms độ trễ
Hiển thị đầy đủ ký hiệu
⚠️ Lưu ý
Với một API Key duy nhất, việc kết nối từ không cho phép nhiều thiết bị trong cùng một khu vực. Nếu một kết nối đang hoạt động và có nỗ lực kết nối khác từ nơi khác, nỗ lực kết nối mới sẽ bị chặn với mã lỗi 4006.
Mã lỗi
Các mã sau đây sẽ được trả về khi kết nối hoặc xác thực thất bại.
CODEMô tảCách xử lý
4001Hết thời gian xác thựcGửi tin nhắn auth trong vòng 5 giây sau khi kết nối.
4002JSON không hợp lệKiểm tra định dạng JSON.
4003Thiếu tin nhắn xác thựctype: "auth" tin nhắn bắt buộc.
4004Key không hợp lệKiểm tra key của bạn trong bot Telegram.
4005Gói đăng ký hết hạnGia hạn gói qua bot Telegram.
4006Kết nối trùng lặpNgắt kết nối hiện có và kết nối lại.
4029Quá nhiều yêu cầu (Giới hạn tốc độ)Vui lòng thử lại sau.
Danh mục
Đây là danh sách các giá trị được nhận. Giá trị trường category được nhận bằng tiếng Hàn cho UPBIT · BITHUMB, và bằng tiếng Anh gốc cho BINANCE · BYBIT.
UPBIT 8 danh mục
안내Thông báo dịch vụ chung
거래Niêm yết thị trường mới và hủy niêm yết
입출금Tạm dừng & nối lại nạp/rút
점검Bảo trì hệ thống
디지털 자산Airdrop và các mục khác
NFTThông báo liên quan đến NFT
서비스+Dịch vụ bổ sung
이벤트Sự kiện & Khuyến mãi
BITHUMB 12 danh mục
거래유의Chỉ định lưu ý giao dịch
거래지원종료Chấm dứt hỗ trợ giao dịch (Hủy niêm yết)
공시Thông tin công bố
마켓 추가Thêm thị trường mới
수수료 이벤트Ưu đãi phí giao dịch
신규서비스Ra mắt dịch vụ mới
안내Thông báo chung
업데이트Cập nhật ứng dụng & dịch vụ
이벤트Sự kiện & Khuyến mãi
입출금Tạm dừng & nối lại nạp/rút
점검Bảo trì hệ thống
후기Đánh giá khác về Bithumb
BINANCE 8 danh mục
New Cryptocurrency ListingNiêm yết tiền mã hóa mới
DelistingHủy niêm yết
Maintenance UpdatesNâng cấp mạng & bảo trì ví
Crypto AirdropAirdrop
Latest Binance NewsTin tức mới nhất từ Binance
Latest ActivitiesHoạt động & khuyến mãi mới nhất
New Fiat ListingsNiêm yết cặp tiền pháp định mới
API UpdatesCập nhật API
BYBIT 9 danh mục
New ListingsNiêm yết mới
DelistingsHủy niêm yết
Latest ActivitiesHoạt động mới nhất
EarnSản phẩm gửi tiết kiệm & lãi suất
AlphaAlpha
Latest Bybit NewsTin tức mới nhất từ Bybit
Maintenance UpdatesCập nhật bảo trì
Partnership AnnouncementThông báo hợp tác
Listing BillboardBảng tin niêm yết
Mã ví dụ đầy đủ
Đây là mã hoàn chỉnh có tự động kết nối lại và exponential backoff. Chỉ cần thay thế YOUR_API_KEY và chạy ngay lập tức.
import asyncio, json, websockets

KEY         = "YOUR_API_KEY"   # issued via Telegram bot
ENDPOINT    = "wss://kr.pkcryptolisting.com"
RETRIES     = 20

def handle_notice(evt: dict):
    exchange = evt.get("exchange", "")
    title    = evt.get("title", "")
    category = evt.get("category", "")
    symbol   = evt.get("symbol", "")
    detected = evt.get("detectedTime", "")
    timezone = evt.get("timezone", "")
    url      = evt.get("url", "")
    print(f"[{exchange}] [{category}] {title}")
    print(f"  symbol={symbol}")
    print(f"  detected={detected} {timezone}")
    print(f"  {url}")

async def listen():
    for attempt in range(RETRIES):
        try:
            async with websockets.connect(ENDPOINT) as ws:
                await ws.send(json.dumps({"type": "auth", "key": KEY}))

                async for raw in ws:
                    evt      = json.loads(raw)
                    evt_type = evt.get("type")

                    if evt_type == "auth_ok":
                        print(f"connected  plan={evt['plan']}  delay={evt['delay_ms']}ms  expires={evt['expires_at']}")
                        attempt = 0  # reset retry counter on success

                    elif evt_type == "error":
                        print(f"[{evt['code']}] {evt['message']}")
                        if evt["code"] in (4004, 4005, 4006, 4029):
                            return  # do not reconnect
                        break

                    elif evt_type == "plan_updated":
                        print(f"plan changed → {evt['plan']}  delay={evt['delay_ms']}ms  expires={evt['expires_at']}")

                    else:
                        handle_notice(evt)

        except websockets.ConnectionClosed as e:
            print(f"closed: {e}")
        except Exception as e:
            print(f"error: {e}")

        backoff = min(2 ** attempt, 300)
        print(f"retry in {backoff}s...")
        await asyncio.sleep(backoff)

if __name__ == "__main__":
    asyncio.run(listen())
// npm install ws
const WebSocket = require("ws");

const KEY      = "YOUR_API_KEY";   // issued via Telegram bot
const ENDPOINT = "wss://kr.pkcryptolisting.com";
const RETRIES  = 20;

function handleNotice(evt) {
  console.log(`[${evt.exchange}] [${evt.category}] ${evt.title}`);
  console.log(`  symbol=${evt.symbol}`);
  console.log(`  detected=${evt.detectedTime} ${evt.timezone || ''}`);
  console.log(`  ${evt.url}`);
}

function listen(attempt = 0) {
  if (attempt >= RETRIES) return;
  const ws = new WebSocket(ENDPOINT);
  ws.on("open", () => ws.send(JSON.stringify({ type: "auth", key: KEY })));
  ws.on("message", (raw) => {
    const evt = JSON.parse(raw);
    if (evt.type === "auth_ok") {
      console.log(`connected  plan=${evt.plan}  delay=${evt.delay_ms}ms  expires=${evt.expires_at}`);
      attempt = 0;  // reset retry counter on success
    } else if (evt.type === "error") {
      console.log(`[${evt.code}] ${evt.message}`);
      if ([4004,4005,4006,4029].includes(evt.code)) return;  // do not reconnect
      ws.close();
    } else if (evt.type === "plan_updated")
      console.log(`plan changed → ${evt.plan}  delay=${evt.delay_ms}ms  expires=${evt.expires_at}`);
    else handleNotice(evt);
  });
  ws.on("close", () => {
    const b = Math.min(2 ** attempt, 300);
    console.log(`retry in ${b}s...`);
    setTimeout(() => listen(attempt + 1), b * 1000);
  });
  ws.on("error", (e) => console.log(`error: ${e.message}`));
}

listen();
// go get github.com/gorilla/websocket
package main

import (
    "encoding/json"; "fmt"; "math"; "time"
    "github.com/gorilla/websocket"
)

const (key = "YOUR_API_KEY"; endpoint = "wss://kr.pkcryptolisting.com"; retries = 20)   // issued via Telegram bot

type Evt struct {
    Type,Plan,Message,ExpiresAt,Exchange,Title,Category,DetectedTime,Timezone,URL string
    Code,DelayMs int; Symbol interface{}
}

func handleNotice(e Evt) {
    fmt.Printf("[%s] [%s] %s
  symbol=%v
  detected=%s %s
",
        e.Exchange, e.Category, e.Title, e.Symbol, e.DetectedTime, e.Timezone, e.URL)
}

func listen() {
    for a := 0; a < retries; a++ {
        c, _, err := websocket.DefaultDialer.Dial(endpoint, nil)
        if err != nil { fmt.Println("error:", err) } else {
            b, _ := json.Marshal(map[string]string{"type":"auth","key":key})
            c.WriteMessage(websocket.TextMessage, b)
            for { _, raw, err := c.ReadMessage(); if err != nil { fmt.Println("closed:", err); break }
                var e Evt; json.Unmarshal(raw, &e)
                switch e.Type {
                case "auth_ok": fmt.Printf("connected  plan=%s  delay=%dms  expires=%s
",e.Plan,e.DelayMs,e.ExpiresAt); a=0  // reset retry counter on success
                case "error": fmt.Printf("[%d] %s
",e.Code,e.Message)
                    if e.Code==4004||e.Code==4005||e.Code==4006||e.Code==4029 { return }  // do not reconnect
                case "plan_updated": fmt.Printf("plan changed → %s  delay=%dms  expires=%s
",e.Plan,e.DelayMs,e.ExpiresAt)
                default: handleNotice(e)
                }
            }; c.Close()
        }
        bf := time.Duration(math.Min(math.Pow(2,float64(a)),300))*time.Second
        fmt.Printf("retry in %vs...
", bf.Seconds()); time.Sleep(bf)
    }
}
func main() { listen() }
use futures_util::{SinkExt, StreamExt};
use tokio_tungstenite::{connect_async, tungstenite::Message};
use serde_json::{json, Value};
use std::time::Duration;

const KEY: &str      = "YOUR_API_KEY";   // issued via Telegram bot
const ENDPOINT: &str = "wss://kr.pkcryptolisting.com";
const RETRIES: u32   = 20;

fn handle_notice(e: &Value) {
    println!("[{}] [{}] {}
  symbol={}
  detected={} {}
  {}",
        e["exchange"],e["category"],e["title"],e["symbol"],e["detectedTime"],e["timezone"],e["url"]);
}

#[tokio::main]
async fn main() {
    for attempt in 0..RETRIES {
        match connect_async(url::Url::parse(ENDPOINT).unwrap()).await {
            Ok((mut ws, _)) => {
                ws.send(Message::Text(json!({"type":"auth","key":KEY}).to_string())).await.ok();
                while let Some(Ok(raw)) = ws.next().await {
                    if let Ok(e) = serde_json::from_str::<Value>(&raw.to_string()) {
                        match e["type"].as_str().unwrap_or("") {
                            "auth_ok" => println!("connected  plan={}  delay={}ms  expires={}",
                                e["plan"],e["delay_ms"],e["expires_at"]),
                            "error" => {
                                println!("[{}] {}",e["code"],e["message"]);
                                let c=e["code"].as_i64().unwrap_or(0);
                                if [4004,4005,4006,4029].contains(&c) { return; }  // do not reconnect
                                break;
                            }
                            "plan_updated" => println!("plan changed → {}  delay={}ms  expires={}",
                                e["plan"],e["delay_ms"],e["expires_at"]),
                            _ => handle_notice(&e),
                        }
                    }
                }
            }
            Err(e) => println!("error: {}", e),
        }
        let b = (2u64.pow(attempt)).min(300);
        println!("retry in {}s...", b);
        tokio::time::sleep(Duration::from_secs(b)).await;
    }
}

Cấp API Key

Bạn có thể nhận miễn phí từ bot Telegram.
Cũng có thể nâng cấp gói trả phí thông qua bot.

Cấp qua Telegram →