PKCryptolisting WebSocket
Panduan Sambungan

Terima pengumuman masa nyata daripada Upbit, Bithumb, Binance, dan Bybit hanya dengan beberapa baris kod
Dapatkan kunci API anda daripada bot Telegram dan ikut panduan di bawah untuk menyambung.

ENDPOINT · KR
wss://kr.pkcryptolisting.com
Upbit · Bithumb
ENDPOINT · TOKYO
wss://tokyo.pkcryptolisting.com
Upbit · Bithumb · Binance · Bybit
PROTOCOL
WebSocket Secure (WSS)
AUTH
API Key (Dikeluarkan melalui Telegram)
SERVER LOCATION
AWS Seoul (ap-northeast-2) / AWS Tokyo (ap-northeast-1)
1. Sambung & Sahkan
Anda mesti menghantar mesej pengesahan sejurus selepas mewujudkan sambungan WebSocket Jika pengesahan tidak selesai dalam masa 5 saatsambungan akan tamat secara automatik
Untuk menerima notis daripada bursa tertentu sahaja, tambahexchange medan.
⚠️ Nota
wss://kr.pkcryptolisting.com(Korea) titik akhir hanya menyokong UPBIT · BITHUMB.
wss://tokyo.pkcryptolisting.com(Tokyo) titik akhir menyokong semua bursa termasuk 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. Respons Pengesahan
Apabila berjaya, maklumat pelan, kelewatan, dan tarikh tamat tempoh dikembalikan.
✓ Berjaya (auth_ok)
{
  "type":       "auth_ok",
  "plan":       "premium",
  "delay_ms":   0,
  "expires_at": "2026-06-30",
  "message":   "Connected..."
}
✕ Gagal (error)
{
  "type":    "error",
  "code":    4004,
  "message": "Invalid key"
}
3. Menerima Mesej
Setelah disahkan, pengumuman baharu akan diterima secara automatik. async for akan memutuskan gelung secara automatik apabila sambungan tamat.
# 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. Format Data
Data pengumuman dihantar dalam format berikut. symbol boleh menjadi rentetan tunggal, tatasusunan, atau rentetan kosong.
⚠️ Nota
title, category Medan diterima dalam UPBIT · BITHUMB untuk Bahasa Korea, dan dalam BINANCE · BYBIT untuk bahasa Inggeris asal.
detectedTimeMasa apabila enjin kami mengesan pengumuman (ketepatan mikrosaat)
{
  "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"
}
MedanJenisPenerangan
titlestringTajuk asal pengumuman bursa
categorystringKategori pengumuman — rujuk senarai kategori di bawah
symbolstring | array Simbol syiling yang diekstrak. Tunggal: "BTC", Berbilang: ["BTC","ETH"], Kosong: "", Pelan Percuma: "***"
exchangestring Bursa sumber: "Upbit", "Bithumb", "Binance", "Bybit"
detectedTimestring Masa apabila enjin kami mengesan pengumuman (ketepatan mikrosaat). Pelan Basic termasuk +30ms latensi tambahan
timezonestring Zon waktu asas untuk detectedTime. KST (Upbit, Bithumb) atau UTC (Binance, Bybit)
urlstringPautan ke pengumuman asal
Perbezaan Pelan
Semua pelan beroperasi atas infrastruktur yang sama. Hanya latensi dan keterlihatan simbol yang berbeza.
Free
0ms Latensi
Simbol *** Disamarkan
Basic
+30ms Latensi Tambahan
Keterlihatan Simbol Penuh
Premium
0ms Latensi
Keterlihatan Simbol Penuh
⚠️ Nota
Dengan satu Kunci API, menyambung daripada berbilang peranti dalam satu rantau tidak dibenarkan. Jika sambungan sudah aktif dan percubaan lain dibuat dari tempat lain, percubaan sambungan baharu akan disekat dengan kod ralat 4006.
Kod Ralat
Kod berikut dikembalikan apabila sambungan atau pengesahan gagal.
CODEPeneranganPenyelesaian
4001Tamat Masa PengesahanHantar mesej auth dalam masa 5 saat selepas menyambung.
4002JSON Tidak SahSahkan format JSON.
4003Mesej Pengesahan Tiadatype: "auth" mesej diperlukan.
4004Kunci Tidak SahSemak kunci anda dalam bot Telegram.
4005Langganan Tamat TempohPerbaharui pelan anda melalui bot Telegram.
4006Sambungan PenduaPutuskan sesi sedia ada dan sambung semula.
4029Terlalu Banyak Permintaan (Had Kadar)Sila cuba lagi kemudian.
Senarai Kategori
Ini ialah senarai nilai yang diterima. category nilai medan adalah dalam bahasa Korea untuk UPBIT · BITHUMB, dan dalam bahasa Inggeris asal untuk BINANCE · BYBIT.
UPBIT 8 Kategori
안내Pengumuman perkhidmatan am
거래Penyenaraian dan penyahsenaraian pasaran baharu
입출금Penggantungan dan penyambungan semula deposit/pengeluaran
점검Penyelenggaraan sistem
디지털 자산Airdrop dan lain-lain
NFTPengumuman berkaitan NFT
서비스+Perkhidmatan tambahan
이벤트Acara & Promosi
BITHUMB 12 Kategori
거래유의Penetapan amaran pelaburan
거래지원종료Penamatan sokongan transaksi (Penyahsenaraian)
공시Maklumat pendedahan
마켓 추가Penambahan pasaran baharu
수수료 이벤트Promosi yuran dagangan
신규서비스Pelancaran perkhidmatan baharu
안내Pengumuman am
업데이트Kemas kini Aplikasi & Perkhidmatan
이벤트Acara & Promosi
입출금Penggantungan dan penyambungan semula deposit/pengeluaran
점검Penyelenggaraan sistem
후기Ulasan Bithumb dan lain-lain
BINANCE 8 Kategori
New Cryptocurrency ListingPenyenaraian Mata Wang Kripto Baharu
DelistingPenyahsenaraian
Maintenance UpdatesNaik Taraf Rangkaian & Penyelenggaraan Dompet
Crypto AirdropAirdrop
Latest Binance NewsBerita Terkini Binance
Latest ActivitiesAktiviti & Promosi Terkini
New Fiat ListingsPenyenaraian Pasangan Fiat Baharu
API UpdatesKemas Kini API
BYBIT 9 Kategori
New ListingsPenyenaraian Baharu
DelistingsPenyahsenaraian
Latest ActivitiesAktiviti Terkini
EarnProduk Deposit & Faedah
AlphaAlpha
Latest Bybit NewsBerita Terkini Bybit
Maintenance UpdatesKemas Kini Penyelenggaraan
Partnership AnnouncementPengumuman Perkongsian
Listing BillboardPapan Penyenaraian
Contoh Kod Penuh
Ini ialah kod berfungsi lengkap dengan sambungan semula automatik dan backoff eksponen. Cukup gantikan YOUR_API_KEY dan jalankan dengan segera.
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;
    }
}

Dapatkan Kunci API

Dapatkannya secara percuma daripada bot Telegram.
Naik taraf pelan berbayar juga boleh dilakukan melalui bot.

Dapatkan melalui Telegram →