# Langganan WebSocket

> Source: https://docs.blockvectra.com/id/guides/websocket-subscriptions/

BlockVectra menyediakan koneksi WebSocket aman (`wss://`) untuk streaming langganan peristiwa Ethereum secara real-time bersama permintaan JSON-RPC standar.

## Memilih WebSocket, Webhook, atau polling

Gunakan WebSocket untuk `newHeads` langsung dan `logs` terfilter ketika aplikasi Anda dapat mempertahankan koneksi. Gunakan [Blockchain Webhook API](https://docs.blockvectra.com/id/guides/webhook-push/) untuk menerima aktivitas dompet yang dipantau di endpoint HTTPS, dengan [verifikasi tanda tangan body mentah](https://docs.blockvectra.com/id/guides/webhook-push/#verify-signatures), percobaan ulang, dan replay kecocokan yang disimpan. Gunakan [polling HTTP](https://docs.blockvectra.com/id/guides/stablecoin-payments/) untuk pemantauan pembayaran ERC-20 terjadwal dan backfill log historis. Panduan stablecoin juga menunjukkan [penerima Webhook USDT / USDC](https://docs.blockvectra.com/id/guides/stablecoin-payments/#receive-payments-with-webhooks). Untuk perbandingan arsitektur berdasarkan dukungan chain, persyaratan penerima, dan kompromi pemulihan bagi pengembang dan AI Agent, lihat [panduan memilih Webhook, WebSocket, atau polling RPC](https://docs.blockvectra.com/id/guides/webhook-vs-websocket/).

Dukungan WebSocket berasal dari `ws` dan `subscriptions` dalam `GET /v1/chains`; dukungan Push berasal dari daftar `GET /v1/push/chains` yang memerlukan autentikasi. Chain tanpa WebSocket tetap dapat menggunakan Webhook alamat jika tercantum di sana.

Koneksi WebSocket yang terputus memerlukan langganan ulang dan backfill; koneksi tersebut tidak menerbitkan peristiwa kontrol Push `subscription.gap` atau `chain.reorg`. Untuk Webhook, celah memerlukan pemindaian rentang; pemberitahuan reorg memerlukan peristiwa yang diganti ditandai atau dibuang sebelum menyimpan peristiwa kanonis yang dikirim ulang otomatis. [Replay Push](https://docs.blockvectra.com/id/guides/webhook-push/#delivery-retries-and-replay) mengirim ulang kecocokan yang disimpan, bukan data sebelum alamat atau chain ditambahkan atau saat langganan offline. Tinjau [aturan penagihan](https://docs.blockvectra.com/en/guides/billing-rules/) dan [referensi error](https://docs.blockvectra.com/id/errors/) saat mengimplementasikan pemulihan.

## Chain yang tersedia

Anda dapat memeriksa apakah langganan WebSocket aktif di suatu jaringan dengan membaca `ws` (boolean) dan `subscriptions` (array tipe yang didukung) dalam `GET /v1/chains`.

Tabel di bawah mencerminkan jaringan dengan dukungan WebSocket yang diaktifkan:

| Rantai | Endpoint WebSocket (kunci di path) |
| --- | --- |
| Robinhood Chain | `wss://api.blockvectra.com/v1/robinhood_mainnet/{api_key}` |
| Robinhood Chain Testnet | `wss://api.blockvectra.com/v1/robinhood_testnet/{api_key}` |

## Koneksi dan autentikasi

Klien membuat koneksi WebSocket TLS aman (`wss://`). API key dapat disediakan dengan dua cara:

* **API key pada jalur**: `wss://api.blockvectra.com/v1/{chain}/{api_key}`
* **API key pada header**: `wss://api.blockvectra.com/v1/{chain}` dengan header `x-api-key: {api_key}` atau `Authorization: Bearer {api_key}` saat handshake HTTP Upgrade.

Jika API key ada pada jalur, API key tersebut digunakan dan kedua header autentikasi diabaikan. Tanpa API key pada jalur, `x-api-key` yang tidak kosong diprioritaskan dibandingkan `Authorization: Bearer`. API WebSocket browser tidak dapat mengatur header ini; gunakan URL dengan API key pada jalur.

### Pemeriksaan penerimaan handshake

Handshake dapat gagal dengan:

* **Autentikasi**: API key yang tidak disertakan mengembalikan HTTP 401 ([`missing_api_key`](https://docs.blockvectra.com/id/errors/#missing_api_key)); API key yang tidak dikenal, dinonaktifkan, atau dicabut mengembalikan HTTP 401 ([`invalid_api_key`](https://docs.blockvectra.com/id/errors/#invalid_api_key)); jika autentikasi tidak tersedia sementara, responsnya HTTP 503 ([`auth_unavailable`](https://docs.blockvectra.com/id/errors/#auth_unavailable)).
* **Saldo akun**: Akun dengan saldo prabayar nol atau negatif mengembalikan HTTP 402 ([`balance_exhausted`](https://docs.blockvectra.com/id/errors/#balance_exhausted)); jika state penagihan tidak dapat dipastikan, responsnya HTTP 503 ([`billing_unavailable`](https://docs.blockvectra.com/id/errors/#billing_unavailable)).
* **Batas koneksi**: Melampaui batas per API key (20 koneksi) atau batas per akun (50 koneksi) mengembalikan HTTP 429 ([`ws_connection_limit`](https://docs.blockvectra.com/id/errors/#ws_connection_limit)).
* **Ketersediaan chain**: Meminta chain yang tidak dikenal atau tidak dilayani mengembalikan HTTP 404 ([`unknown_chain`](https://docs.blockvectra.com/id/errors/#unknown_chain)).
* **Kapasitas server**: Ketika server sibuk atau kelebihan beban, handshake mengembalikan HTTP 503 ([`overloaded`](https://docs.blockvectra.com/id/errors/#overloaded)) dengan header `Retry-After`.

Setelah terhubung, klien dapat mengirim permintaan JSON-RPC 2.0 standar (seperti `eth_blockNumber` atau `eth_call`) dan metode kontrol langganan dalam format frame teks UTF-8.

## Aturan penagihan

* Membuat koneksi, mempertahankan koneksi yang tidak aktif, dan heartbeat ping/pong tidak ditagih.
* Panggilan `eth_subscribe` dan `eth_unsubscribe` yang berhasil ditagih, termasuk pembatalan langganan yang mengembalikan `false`; panggilan gagal tidak ditagih. Panggilan JSON-RPC biasa mengikuti [aturan penagihan JSON-RPC](https://docs.blockvectra.com/en/guides/billing-rules/).
* Notifikasi `newHeads` dihitung sekali per hash blok per koneksi, terlepas dari jumlah langganan `newHeads` pada koneksi tersebut.
* Notifikasi `logs` dihitung sekali per langganan per hash blok dan fase yang memiliki log cocok; blok tanpa kecocokan tidak ditagih. Beberapa log yang cocok dalam blok dan fase yang sama tidak melipatgandakan biaya. Langganan terpisah dihitung secara terpisah, meskipun filternya tumpang tindih. Log reorganisasi (`removed: true`) membentuk unit terpisah; blok pengganti pada tinggi yang sama memiliki hash berbeda dan merupakan unit berbeda.
* Notifikasi hanya ditagih setelah berhasil ditulis ke buffer pengiriman socket; notifikasi dalam antrean atau yang dibuang tanpa ditulis tidak ditagih. Notifikasi yang masuk antrean sebelum jawaban `eth_unsubscribe` dihitung jika ditulis. Pesan WebSocket tidak membawa header penagihan HTTP; lihat penggunaan akun untuk CU yang diukur.

## Metode langganan

API mengimplementasikan antarmuka pub/sub Ethereum standar: `eth_subscribe` dan `eth_unsubscribe`.

### `newHeads`

Menerbitkan objek header blok baru setiap kali blok baru ditambahkan ke head chain.

* **Permintaan langganan**:
  ```json
  {"jsonrpc":"2.0","id":1,"method":"eth_subscribe","params":["newHeads"]}
  ```
* **Respons langganan**: Mengembalikan pengenal langganan heksadesimal yang bersifat opaque:
  ```json
  {"jsonrpc":"2.0","id":1,"result":"0x1"}
  ```
* **Frame notifikasi push**:
  ```json
  {"jsonrpc":"2.0","method":"eth_subscription","params":{"subscription":"0x1","result":{"number":"0x1b4","hash":"0x..."}}}
  ```

### `logs`

Menerbitkan peristiwa log yang cocok dengan kriteria filter yang ditentukan.

* **Persyaratan filter**: Setiap filter langganan `logs` **harus** menentukan `address` (alamat kontrak atau array alamat) atau `topic0` (posisi topic pertama, bukan null). Filter yang tidak menentukan keduanya (seperti `{}` atau `{"topics":[null,"0x..."]}`) ditolak dengan kode error `-32602` ([`logs_filter_required`](https://docs.blockvectra.com/id/errors/#logs_filter_required)).

* **Batas filter**: Maksimal 100 alamat; maksimal 4 posisi topic dengan maksimal 16 hash kandidat per posisi.

* **Kapasitas filter**: Jika filter log aktif mencapai kapasitas, langganan mengembalikan kode error `-32022` ([`ws_filter_capacity`](https://docs.blockvectra.com/id/errors/#ws_filter_capacity)).

* **Reorganisasi chain**: Jika blok dihapus akibat reorg chain, notifikasi log untuk log yang dihapus membawa `"removed": true`.

* **Permintaan langganan**:
  ```json
  {"jsonrpc":"2.0","id":2,"method":"eth_subscribe","params":["logs",{"address":"0x1234567890123456789012345678901234567890"}]}
  ```

### `eth_unsubscribe`

Mengakhiri langganan aktif menggunakan pengenal langganannya.

* **Permintaan pembatalan langganan**:
  ```json
  {"jsonrpc":"2.0","id":3,"method":"eth_unsubscribe","params":["0x1"]}
  ```
* **Respons pembatalan langganan**:
  ```json
  {"jsonrpc":"2.0","id":3,"result":true}
  ```

## Contoh yang dapat dijalankan

**viem v2 (TypeScript)**

Hubungkan menggunakan [viem](https://viem.sh) v2 melalui `createPublicClient` dan transport `webSocket`. Ganti `{chain}` dengan pengenal chain tujuan dan `{api_key}` dengan API key Anda:

```ts
import { createPublicClient, webSocket } from 'viem';

const apiKey = process.env.BLOCKVECTRA_API_KEY || '{api_key}';
const url = `wss://api.blockvectra.com/v1/robinhood_mainnet/${apiKey}`;

const client = createPublicClient({
  transport: webSocket(url),
});

// 1. Subscribe to new block headers (newHeads)
const unwatchBlocks = client.watchBlocks({
  onBlock: (block) => {
    console.log('New block header received:', block.number, block.hash);
  },
  onError: (error) => {
    console.error('watchBlocks error:', error);
  },
});

// 2. Subscribe to contract event logs (filter requires address or topic0)
const unwatchEvents = client.watchEvent({
  address: '0x1234567890123456789012345678901234567890',
  onLogs: (logs) => {
    console.log('Matching logs received:', logs);
  },
  onError: (error) => {
    console.error('watchEvent error:', error);
  },
});
```


  **Command line (websocat / wscat)**

Hubungkan menggunakan alat baris perintah seperti `websocat` atau `wscat` dan kirim frame JSON-RPC mentah:

```bash
# Connect with path-based API key using websocat
websocat "wss://api.blockvectra.com/v1/{chain}/{api_key}"

# Alternatively, pass the key via request header
websocat -H="x-api-key: {api_key}" "wss://api.blockvectra.com/v1/{chain}"

# Or connect using wscat
wscat -c "wss://api.blockvectra.com/v1/{chain}/{api_key}"
```

Kirim perintah langganan ke sesi interaktif:

```json
{"jsonrpc":"2.0","id":1,"method":"eth_subscribe","params":["newHeads"]}
{"jsonrpc":"2.0","id":2,"method":"eth_subscribe","params":["logs",{"address":"0x1234567890123456789012345678901234567890"}]}
{"jsonrpc":"2.0","id":3,"method":"eth_unsubscribe","params":["0x1"]}
```


## Kode penutupan dan tindakan klien

Ketika server mengakhiri sesi WebSocket, server mengirim frame Close dengan kode penutupan tertentu dan alasan singkat. Tabel di bawah mencantumkan kode penutupan yang diterbitkan server dan tindakan yang disarankan:

|           Kode penutupan | String alasan                    | Keterangan                                                                                                                                                           | Dapat dicoba ulang | Tindakan klien                                                                                                                                                                                                                                                                  |
| -----------------------: | -------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :----------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [1001](https://docs.blockvectra.com/id/errors/#1001) | `idle`                           | Koneksi tidak aktif tanpa langganan atau pesan selama 3600 detik (1 jam)                                                                                             |         Ya         | Sambungkan kembali sesuai kebutuhan.                                                                                                                                                                                                                                            |
| [1003](https://docs.blockvectra.com/id/errors/#1003) | `binary frames are not accepted` | Frame WebSocket biner diterima; hanya frame teks UTF-8 yang diterima                                                                                                 |        Tidak       | Jangan menyambungkan kembali secara otomatis. Perbarui klien untuk mengirim frame teks.                                                                                                                                                                                         |
| [1009](https://docs.blockvectra.com/id/errors/#1009) | `message too large`              | Payload masuk melebihi 1 MiB                                                                                                                                         |        Tidak       | Jangan menyambungkan kembali secara otomatis. Pecah permintaan besar atau kurangi ukuran payload.                                                                                                                                                                               |
| [1012](https://docs.blockvectra.com/id/errors/#1012) | `service restart`                | Server dimulai ulang, atau sesi mencapai masa hidup maksimum (24 jam)                                                                                                |         Ya         | Sambungkan kembali dengan backoff berjitter acak, buat ulang langganan, dan lakukan backfill data yang terlewat.                                                                                                                                                                |
| [1013](https://docs.blockvectra.com/id/errors/#1013) | `chain unavailable`              | Chain tidak tersedia                                                                                                                                                 |         Ya         | Sambungkan kembali dengan backoff eksponensial full jitter, buat ulang langganan, dan lakukan backfill data yang terlewat.                                                                                                                                                      |
| [1013](https://docs.blockvectra.com/id/errors/#1013) | `overloaded`                     | Server kelebihan beban sementara                                                                                                                                     |         Ya         | Sambungkan kembali dengan backoff eksponensial full jitter, buat ulang langganan, dan lakukan backfill data yang terlewat.                                                                                                                                                      |
| [4402](https://docs.blockvectra.com/id/errors/#4402) | `insufficient balance`           | Saldo akun habis                                                                                                                                                     |        Tidak       | Jangan menyambungkan kembali secara otomatis. [Top up saldo Anda, lalu sambungkan kembali](https://docs.blockvectra.com/en/guides/billing-rules/).                                                                                                                                                          |
| [4404](https://docs.blockvectra.com/id/errors/#4404) | `invalid api key`                | API key tidak dikenal, dinonaktifkan, atau dicabut                                                                                                                   |        Tidak       | Jangan menyambungkan kembali secara otomatis. Verifikasi atau rotasi API key di konsol sebelum menyambungkan kembali.                                                                                                                                                           |
| [4408](https://docs.blockvectra.com/id/errors/#4408) | `slow consumer`                  | Server menutup sesi yang antrean push-nya melampaui 512 KiB dan membuang notifikasi tertunda; klien mungkin tidak menerima frame penutupan (browser melaporkan 1006) |         Ya         | Perlakukan koneksi terputus tak terduga (tidak menerima frame penutupan, browser melaporkan 1006) seperti 4408: sambungkan kembali dengan backoff, buat ulang langganan, dan lakukan backfill data yang dibuang dengan `eth_getLogs`; kurangi langganan, atau baca lebih cepat. |
| [4429](https://docs.blockvectra.com/id/errors/#4429) | `push rate exceeded`             | Laju notifikasi melebihi 1,000 push/detik                                                                                                                            |         Ya         | Kurangi langganan atau persempit filter; sambungkan kembali dengan backoff, berlangganan ulang, dan lakukan backfill.                                                                                                                                                           |
| [4503](https://docs.blockvectra.com/id/errors/#4503) | `billing unavailable`            | Penagihan tidak tersedia sementara                                                                                                                                   |         Ya         | Kondisi sementara; sambungkan kembali dengan backoff eksponensial full jitter.                                                                                                                                                                                                  |

## Penyambungan kembali dan backoff eksponensial

Untuk mencegah lonjakan penyambungan kembali serentak ketika koneksi terputus, klien harus mengimplementasikan backoff eksponensial dengan full jitter:

* **Rumus backoff**: Sebelum percobaan penyambungan kembali ke-n (n = 0, 1, 2, ...), tunggu durasi yang dipilih secara acak dari distribusi seragam:
  ```
  delay = random(0, min(20s, 0.5s * 2^n))
  ```
* **Reset penghitung**: Reset penghitung percobaan ulang n menjadi 0 hanya setelah mempertahankan koneksi stabil tanpa terputus selama setidaknya `60 seconds`.
* **Kode penutupan 1012**: Tambahkan penundaan awal acak sebelum percobaan penyambungan kembali pertama untuk menghindari lonjakan penyambungan kembali serentak.
* **Kode yang tidak dapat dicoba ulang**: Jangan menyambungkan kembali secara otomatis pada [4402](https://docs.blockvectra.com/id/errors/#4402), [4404](https://docs.blockvectra.com/id/errors/#4404), [1003](https://docs.blockvectra.com/id/errors/#1003), atau [1009](https://docs.blockvectra.com/id/errors/#1009).

### Backfill data yang terlewat setelah penyambungan kembali

Langganan WebSocket tidak bertahan lintas koneksi; notifikasi yang diterbitkan saat koneksi terputus tidak disimpan di server. Setelah tersambung kembali, klien sebaiknya menjalankan strategi mengejar ketertinggalan:

1. **Backfill log dengan `eth_getLogs`**:
   * Simpan secara persisten nomor blok tertinggi yang berhasil diproses (`last_processed_block`).
   * Segera panggil `eth_subscribe("logs", ...)` saat tersambung kembali untuk menangkap peristiwa langsung.
   * Kueri blok yang terlewat melalui `eth_getLogs` dengan `fromBlock: last_processed_block + 1` dan `toBlock: "latest"` (atau blok pertama yang diterima dari aliran langsung).
   * Jika celah koneksi terputus melebihi `max_logs_block_range` jaringan (dari `GET /v1/chains`), bagi kueri menjadi potongan yang tidak melebihi batas tersebut.
   * Lakukan deduplikasi entri log di batas kueri menggunakan tuple unik `(blockHash, transactionHash, logIndex)`.
2. **Backfill header blok dengan `eth_getBlockByNumber`**:
   * Catat nomor dan hash blok terbaru yang diterima sebelum koneksi terputus.
   * Berlangganan ulang ke `newHeads`.
   * Kueri `eth_getBlockByNumber("latest", false)` dan ambil blok perantara yang terlewat secara berurutan. Verifikasi kesinambungan chain melalui `parentHash` untuk mendeteksi reorg.

## Batas

| Batas                                      | Nilai                                                                    | Hasil saat terlampaui                                               |
| ------------------------------------------ | ------------------------------------------------------------------------ | ------------------------------------------------------------------- |
| Langganan per koneksi WebSocket            | 100                                                                      | `-32022` [`subscription_limit`](https://docs.blockvectra.com/id/errors/#subscription_limit)     |
| Langganan `newHeads` per koneksi WebSocket | 4                                                                        | `-32022` [`subscription_limit`](https://docs.blockvectra.com/id/errors/#subscription_limit)     |
| Persyaratan filter langganan `logs`        | Harus menentukan `address` atau `topic0` (posisi pertama dalam `topics`) | `-32602` [`logs_filter_required`](https://docs.blockvectra.com/id/errors/#logs_filter_required) |

## Langkah berikutnya

* [Jelajahi direktori kumpulan data](https://blockvectra.com/id/data/) untuk melihat semua kumpulan data yang diindeks BlockVectra.
* [Lihat paket gratis dan harga](https://blockvectra.com/id/pricing/#free) untuk memeriksa apa saja yang tercakup dalam akun Anda.
* [Masuk ke konsol](https://console.blockvectra.com/login/?next=%2Fkeys%2F) untuk membuat API key.
