PKCryptolisting WebSocket
Panduan Koneksi

Terima pengumuman real-time dari Upbit, Bithumb, Binance, dan Bybit hanya dengan beberapa baris kode
Dapatkan API key Anda dari bot Telegram dan ikuti panduan di bawah untuk terhubung.

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 (Diterbitkan via Telegram)
SERVER LOCATION
AWS Seoul (ap-northeast-2) / AWS Tokyo (ap-northeast-1)
1. Sambungkan & Autentikasi
Anda harus mengirimkan pesan autentikasi segera setelah koneksi WebSocket terbentuk Jika autentikasi tidak selesai dalam 5 detikkoneksi akan otomatis berakhir
Untuk menerima pengumuman dari bursa tertentu saja, tambahkanexchange field.
⚠️ Catatan
wss://kr.pkcryptolisting.com(Korea) endpoint hanya mendukung UPBIT · BITHUMB.
wss://tokyo.pkcryptolisting.com(Tokyo) endpoint mendukung 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 Autentikasi
Jika berhasil, informasi plan, penundaan, dan tanggal kedaluwarsa akan dikembalikan.
✓ Berhasil (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 Pesan
Setelah autentikasi berhasil, pengumuman baru akan diterima secara otomatis. async for akan otomatis menghentikan loop saat koneksi berakhir.
# 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 dikirim dalam format berikut. symbol dapat berupa string tunggal, array, atau string kosong.
⚠️ Catatan
title, category Field diterima dalam UPBIT · BITHUMB untuk Bahasa Korea, dan dalam BINANCE · BYBIT untuk Bahasa Inggris asli.
detectedTimeWaktu saat mesin kami mendeteksi pengumuman (presisi mikrodetik)
{
  "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"
}
FieldTipeDeskripsi
titlestringJudul asli pengumuman bursa
categorystringKategori pengumuman — lihat daftar kategori di bawah
symbolstring | array Simbol koin yang diekstrak. Tunggal: "BTC", Ganda: ["BTC","ETH"], Kosong: "", Plan Free: "***"
exchangestring Bursa sumber: "Upbit", "Bithumb", "Binance", "Bybit"
detectedTimestring Waktu saat mesin kami mendeteksi pengumuman (presisi mikrodetik). Plan Basic menyertakan +30ms latensi tambahan
timezonestring Zona waktu dasar untuk detectedTime. KST (Upbit, Bithumb) atau UTC (Binance, Bybit)
urlstringTautan ke pengumuman asli
Perbedaan Plan
Semua plan berjalan di infrastruktur yang sama. Hanya latensi dan visibilitas simbol yang berbeda.
Free
Latensi 0ms
Simbol *** Disamarkan
Basic
+30ms Latensi Tambahan
Visibilitas Simbol Penuh
Premium
Latensi 0ms
Visibilitas Simbol Penuh
⚠️ Catatan
Dengan satu API Key, menghubungkan dari beberapa perangkat dalam satu region tidak diizinkan. Jika koneksi sudah aktif dan ada upaya koneksi lain dari tempat lain, upaya koneksi baru akan diblokir dengan kode error 4006.
Kode Error
Kode berikut dikembalikan saat koneksi atau autentikasi gagal.
CODEDeskripsiPenyelesaian
4001Waktu Autentikasi HabisKirim pesan auth dalam 5 detik setelah koneksi terbentuk.
4002JSON Tidak ValidPeriksa format JSON.
4003Pesan Autentikasi Hilangtype: "auth" pesan diperlukan.
4004Key Tidak ValidPeriksa key Anda di bot Telegram.
4005Langganan KedaluwarsaPerpanjang plan Anda melalui bot Telegram.
4006Koneksi GandaPutuskan sesi yang ada lalu sambungkan ulang.
4029Terlalu Banyak Permintaan (Rate Limit)Silakan coba lagi nanti.
Daftar Kategori
Ini adalah daftar nilai yang diterima. category nilai field dalam Bahasa Korea untuk UPBIT · BITHUMB, dan dalam Bahasa Inggris asli untuk BINANCE · BYBIT.
UPBIT 8 Kategori
안내Pengumuman layanan umum
거래Listing dan delisting market baru
입출금Penghentian dan pemulihan deposit/penarikan
점검Pemeliharaan sistem
디지털 자산Airdrop dan lainnya
NFTPengumuman terkait NFT
서비스+Layanan tambahan
이벤트Acara & Promosi
BITHUMB 12 Kategori
거래유의Penetapan peringatan investasi
거래지원종료Penghentian dukungan transaksi (Delisting)
공시Informasi keterbukaan
마켓 추가Penambahan market baru
수수료 이벤트Promosi biaya trading
신규서비스Peluncuran layanan baru
안내Pengumuman umum
업데이트Pembaruan Aplikasi & Layanan
이벤트Acara & Promosi
입출금Penghentian dan pemulihan deposit/penarikan
점검Pemeliharaan sistem
후기Ulasan Bithumb, dll.
BINANCE 8 Kategori
New Cryptocurrency ListingListing Mata Uang Kripto Baru
DelistingDelisting
Maintenance UpdatesPeningkatan Jaringan & Pemeliharaan Dompet
Crypto AirdropAirdrop
Latest Binance NewsBerita Terbaru Binance
Latest ActivitiesAktivitas & Promosi Terbaru
New Fiat ListingsListing Pasangan Fiat Baru
API UpdatesPembaruan API
BYBIT 9 Kategori
New ListingsListing Baru
DelistingsDelisting
Latest ActivitiesAktivitas Terbaru
EarnEarn
AlphaAlpha
Latest Bybit NewsBerita Terbaru Bybit
Maintenance UpdatesPembaruan Pemeliharaan
Partnership AnnouncementPengumuman Kemitraan
Listing BillboardPapan Listing
Contoh Kode Lengkap
Ini adalah kode lengkap yang berfungsi dengan penyambungan ulang otomatis dan exponential backoff. Cukup ganti YOUR_API_KEY dan langsung jalankan.
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 API Key

Dapatkan secara gratis dari bot Telegram.
Upgrade ke plan berbayar juga dapat dilakukan melalui bot.

Dapatkan via Telegram →