Realtime: WebSocket üzerinden olaylar
Sipariş durumunu, ses klonlama ilerlemesini veya hediye kodlarını yoklamanız gerekmez: sunucu olayları WebSocket üzerinden kendisi gönderir. Protokol: Pusher, sunucu: Reverb; her abonelik özeldir ve API anahtarınızla yetkilendirilir. Aşağıda: bağlantı parametreleri, dört yetkilendirme adımı, kanallar ve en sık takılınan iki nokta.
Bağlantı parametreleri
Değerler düz metinden değil, AsyncAPI'den gelir. Sunucu adresi, port ve şema elle ayarlanmalıdır: burada Pusher bulut kümesi yok, sunucu bize ait.
| Parametre | Değer | Anlamı |
|---|---|---|
| Sunucu adresi | ws.lumean.app | WebSocket sunucusunun adresi: pusher-js'te wsHost, Laravel Echo'da wsHost ve wssHost. |
| Port | 443 | wsPort ve wssPort için aynı değer — TLS'siz ayrı bir port yoktur. |
| Şema | wss | wss, forceTLS: true anlamına gelir. Üretim alan adından düz ws bağlantısı kurulamaz. |
| Uygulama anahtarı | 7c4dd881d8116ac76fe89aff71d8c2ff | Reverb uygulama kimliği. Ne gizlidir ne de API anahtarınızdır — tüm istemciler aynısını kullanır. |
| Abonelik yetkilendirmesi | https://api.lumean.app/api/public/broadcasting/auth | İstemci, imza almak için socket_id değerini ve kanal adını buraya gönderir. API anahtarınız yalnızca bu HTTP isteğinde iletilir. |
İpucu
Abonelik nasıl yetkilendirilir
Özel bir kanalı öylece dinleyemezsiniz. İstemci kütüphanesi dört adımdan geçer; bunları bilmek, 403'ün hangi adımda geldiğini anlamanızı sağlar.
Soket açılır
İstemci, uygulama anahtarını kullanarak sunucuya bağlanır. API anahtarınız henüz devrede değildir — soket geçersiz bir anahtarla bile açılır.
socket_id gelir
Sunucu, pusher:connection_established ile yanıt verir; içinde bu bağlantıyı tanımlayan socket_id bulunur.
Abonelik imzalanır
İstemci, socket_id değerini ve kanal adını X-API-KEY başlığıyla POST /broadcasting/auth adresine gönderir. Sunucu anahtarı, izni ve kanalın sahipliğini kontrol eder, ardından bir imza döndürür. 401, 403 ve 429 buradan gelir.
Abone olundu, olaylar akıyor
İstemci imzayı geri iletir, kanal pusher:subscription_succeeded ile onaylar — ve kanal olayları ancak bundan sonra gelmeye başlar.
orders.readvoices.readreseller.read— üçüncü adımda kontrol edilen izinler: her kanalın kendi izni vardır, aşağıdaki kanal tablosuna bakın.
Bağlantı kod örnekleri
Üç istemci, aynı sıra. Koddaki anahtar bir yer tutucudur: kendi anahtarınızı yazın ama commit etmeyin.
import Pusher from 'pusher-js';
const pusher = new Pusher('7c4dd881d8116ac76fe89aff71d8c2ff', {
wsHost: 'ws.lumean.app',
wsPort: 443, wssPort: 443,
forceTLS: true,
enabledTransports: ['ws', 'wss'],
cluster: '',
channelAuthorization: {
endpoint: 'https://api.lumean.app/api/public/broadcasting/auth',
headers: { 'X-API-KEY': 'YOUR_API_KEY' },
},
});
const channel = pusher.subscribe('private-orders.{userId}');
channel.bind('policy_cooldown.applied', (data) => {
console.log(data);
});import Echo from 'laravel-echo';
import Pusher from 'pusher-js';
window.Pusher = Pusher;
const echo = new Echo({
broadcaster: 'pusher',
key: '7c4dd881d8116ac76fe89aff71d8c2ff',
wsHost: 'ws.lumean.app',
wsPort: 443, wssPort: 443,
forceTLS: true,
enabledTransports: ['ws', 'wss'],
cluster: '',
authEndpoint: 'https://api.lumean.app/api/public/broadcasting/auth',
auth: { headers: { 'X-API-KEY': 'YOUR_API_KEY' } },
});
echo.private('orders.{userId}')
// baştaki nokta Laravel Echo içindir; pusher-js'te yoktur
.listen('.policy_cooldown.applied', (e) => {
console.log(e);
});# pip install websocket-client requests
import json, requests, websocket
APP_KEY = "7c4dd881d8116ac76fe89aff71d8c2ff"
WS_URL = "wss://ws.lumean.app:443/app/" + APP_KEY + "?protocol=7&client=python&version=1.0"
CHANNEL = "private-orders.{userId}"
ws = websocket.create_connection(WS_URL)
# 1. socket_id değerini pusher:connection_established olayından alın
hello = json.loads(ws.recv())
socket_id = json.loads(hello["data"])["socket_id"]
# 2. özel aboneliği API anahtarınızla yetkilendirin
auth = requests.post("https://api.lumean.app/api/public/broadcasting/auth",
headers={"X-API-KEY": "YOUR_API_KEY"},
data={"socket_id": socket_id, "channel_name": CHANNEL},
).json()["auth"]
# 3. abone olun ve olayları dinleyin
ws.send(json.dumps({"event": "pusher:subscribe",
"data": {"auth": auth, "channel": CHANNEL}}))
while True:
print(ws.recv())Kanallar
Kanallar özeldir: adları private- ile başlar ve süslü parantez içindeki parametreyi kendiniz yerleştirirsiniz. Her kanal kendi iznini gerektirir — tabloda belirtilmiştir.
- WSprivate-orders.{userId}Events for every order of the account at once.14 olayorders.readKanalı aç
- WSprivate-order.task.{orderId}Events for a single order. Someone else's order is out of reach: subscription auth returns `403`.8 olayorders.readKanalı aç
- WSprivate-chunks.preview.{userId}The result of a background chunk-preview split calculation. Arrives for large texts submitted to `POST /orders/chunks/preview`.1 olayorders.readKanalı aç
- WSprivate-cartesia-voice-clones.{userId}Progress of your Cartesia voice clones: one event per status change of a clone created via `POST /voices/cartesia/clones` (or in the web dashboard). Key permission: `voices.read`.1 olayvoices.readKanalı aç
- WSprivate-fishaudio-voice-clones.{userId}Progress of your Fish Audio voice clones: one event per status change of a clone created via `POST /voices/fishaudio/clones` (or in the web dashboard). Key permission: `voices.read`.1 olayvoices.readKanalı aç
- WSprivate-giftcodes.{userId}Gift codes and reseller status of the key owner: a batch issued, a code changing status, the reseller status and the reseller application changing. Events never carry code values, only masks; the full code comes from `GET /reseller/codes` and `GET /reseller/codes/{uuid}`. Key permission: `reseller.read`.4 olayreseller.readKanalı aç
İki tuzak
.progress olayı iki kanalda var — farklı payload'larla
Aynı ad, farklı yapı. Kullanıcı siparişleri kanalında bir siparişin tamamlanan parçalarını sayar; tek sipariş kanalında ise yüzde cinsinden görev ilerlemesi ve tahmini kalan süredir. Her iki kanala bağlanan tek bir işleyici ikinci olayı birincisi gibi okur ve sessizce undefined alır.
// private-orders.{userId} → .progress
{ "order_id": "…", "completed": 3, "total": 7, "percent": 43 }// private-order.task.{orderId} → .progress
{ "task_id": "…", "progress": 43, "chunks_done": 3, "chunks_total": 7, "eta_seconds": 12 }İşleyicileri olay adına göre değil, kanala göre ayırın. Tam alan tabloları kanal sayfalarında.
Baştaki nokta: Echo'da zorunlu, pusher-js'te yanlış
Laravel Echo olay adlarının önüne uygulamanın ad alanını ekler, baştaki nokta bunu iptal eder. pusher-js'te hiç ad alanı yoktur, bu yüzden olay adında nokta bulunmaz. Karıştırırsanız abonelik çalışır, olay gelmez ve hiçbir hata da verilmez.
echo.private(channel).listen('.status.changed', handler)channel.bind('status.changed', handler)Yetkilendirme hataları
Üçü de soket üzerinden değil, POST /broadcasting/auth isteğine HTTP yanıtı olarak gelir. Soket o sırada zaten açıktır — bu yüzden “bağlandı” durumu izinleriniz hakkında hiçbir şey söylemez.
| Kod | Ne zaman olur | Ne yapmalı |
|---|---|---|
| 401 | X-API-KEY başlığı eksik ya da anahtar iptal edilmiş veya eksik kopyalanmış. | Anahtarı GET /user ile doğrulayın. Kütüphane anahtarı kurucusunda değil, abonelik yetkilendirme isteğinin başlıklarında alır. |
| 403 | Anahtar çalışıyor ancak bu kanal için izni yok (siparişler için orders.read, ses klonları için voices.read, hediye kodları için reseller.read) — ya da başka birinin kanalına abone oluyorsunuz: addaki userId ve orderId anahtar sahibine ait olmalıdır. | İzni panelinizde ekleyin ve kendi kimliğinizi yerleştirin. Abonelik size asla başkasının siparişini vermez. |
| 429 | Arka arkaya çok fazla yetkilendirme denemesi — genellikle hatalı anahtarla yeniden bağlanma döngüsü. | Yeniden bağlanmayı durdurun, anahtarı düzeltin, tekrar bağlanın. Üstel bekleme süresi yardımcı olur ama neden neredeyse her zaman bir üst satırdaki 401'dir. |
POST /broadcasting/auth
Bu uç nokta başvuruda bilerek yer almaz: kimse onu elle çağırmaz, istemci kütüphanesi çağırır. Ama bir abonelik 403 döndürdüğünde hata ayıklayacağınız istek tam olarak budur — bu yüzden burada belgelenmiştir.
Authorizes a subscription to a private WebSocket channel using your API key. Client
libraries (Laravel Echo, pusher-js) call this endpoint themselves — point their
authEndpoint at it and add X-API-KEY to the auth headers.
Available channels are your own orders (private-orders.{userId},
private-order.task.{orderId}) and chunk-preview results
(private-chunks.preview.{userId}, see POST /orders/chunks/preview) — permission
orders.read — plus your Cartesia voice clones
(private-cartesia-voice-clones.{userId}, see POST /voices/cartesia/clones) and
Fish Audio voice clones (private-fishaudio-voice-clones.{userId}, see
POST /voices/fishaudio/clones) — permission voices.read. Someone else's channel returns 403.
Subscribing removes the need to poll GET /orders/{order}: progress and completion
arrive as events.
Required key permission: orders.read.
İstek gövdesi
The WebSocket connection id delivered to the client in the pusher:connection_established event.
Channel name. A key may only reach its own channels: orders private-orders.{userId} and private-order.task.{orderId}, chunk previews private-chunks.preview.{userId} (permission orders.read), Cartesia voice clones private-cartesia-voice-clones.{userId} and Fish Audio voice clones private-fishaudio-voice-clones.{userId} (permission voices.read), reseller gift codes private-giftcodes.{userId} (permission reseller.read).
Olası yanıtlar
200Subscription authorized. The client receives the subscription auth token.
Subscription authorized. The client receives the subscription auth token.
{
"auth": "a1b2c3d4e5f67890abcdef1234567890abcdef1234567890abcdef1234567890"
}The channel subscription signature. Hand it back to the Pusher/Echo client verbatim — it fills the value in itself. This response carries no envelope: the protocol dictates the shape.
401The key is missing, unknown, disabled or expired.
The key is missing, unknown, disabled or expired.
Bu yanıtın gövdesi yok.
403The key lacks the permission the channel requires (orders.read for orders and chunk previews, voices.read for Cartesia and Fish Audio voice clones), or the channel belongs to someone else.
The key lacks the permission the channel requires (orders.read for orders and chunk previews, voices.read for Cartesia and Fish Audio voice clones), or the channel belongs to someone else.
Bu yanıtın gövdesi yok.
422Invalid socket_id/channel_name (for example a channel_name without the private- prefix).
Invalid socket_id/channel_name (for example a channel_name without the private- prefix).
Bu yanıtın gövdesi yok.
429Rate limit exceeded — 1200 requests per minute.
Rate limit exceeded — 1200 requests per minute.
Bu yanıtın gövdesi yok.
Kimlik doğrulama ve izinler·Rehber: yoklama yerine gerçek zamanlı
Bu sayfayı yapay zekâya verin
spesifikasyon 0.0.1