Descriptions are in English
private-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.
Channel parameters
Fill in your values — they appear in the channel name, in the code below and in the console. They are sent nowhere and never end up in the page URL.
is the numeric id of the key owner, returned by GET /user.
Channel name to subscribe to
private-fishaudio-voice-clones.{userId}
The name still contains placeholders in braces. You cannot subscribe with it: the server authorizes channels by exact name.
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-fishaudio-voice-clones.{userId}');
channel.bind('voice_clone.updated', (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('fishaudio-voice-clones.{userId}')
// the leading dot is for Laravel Echo; pusher-js has none
.listen('.voice_clone.updated', (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-fishaudio-voice-clones.{userId}"
ws = websocket.create_connection(WS_URL)
# 1. grab socket_id from the pusher:connection_established event
hello = json.loads(ws.recv())
socket_id = json.loads(hello["data"])["socket_id"]
# 2. authorize the private subscription with your API key
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. subscribe and listen for events
ws.send(json.dumps({"event": "pusher:subscribe",
"data": {"auth": auth, "channel": CHANNEL}}))
while True:
print(ws.recv())Payload example
Channel: private-fishaudio-voice-clones.{userId}
This is an example from the spec. There is no connection and none is simulated: subscribing for real needs your API key.
.voice_clone.updated
{
"voice_clone": {
"id": "<uuid>",
"provider": "fishaudio",
"display_name": "string",
"language": "ru",
"description": "string",
"status": "pending",
"voice_id": "string",
"attempts": 1,
"error": {
"reason": "string",
"message": "string"
},
"created_at": "<date-time>",
"completed_at": "<date-time>",
"failed_at": "<date-time>",
"banned_at": "<date-time>",
"ban_reason": "string"
}
}Channel events: 1
Every event has its own anchor, a full payload table with descriptions and enums, and a sample shape. Names are shown in Laravel Echo notation — with the leading dot.
.voice_clone.updated
Echo: .voice_clone.updated · pusher-js: voice_clone.updated
A Fish Audio voice clone was created or changed status (pending → cloning → ready or failed; archived after deletion; banned — blocked by a moderator). voice_id appears only once the clone is ready — put it into tts_settings.voice_id of a Fish Audio template.
Payload fields
voice_clonerequiredobject
Clone status. banned — a moderator blocked the clone: it is not accepted for new orders and cannot be deleted; the reason is in ban_reason.
The Fish Audio voice id (a 32-character hex string, not a UUID) — the value for tts_settings.voice_id of a template. Present only once the clone is ready, otherwise null.
errorrequiredobject | null
processing_error, max_retries, network, timeout, dispatch_failed, unbanned
Why a moderator blocked the clone, or null.
Payload example
{
"voice_clone": {
"id": "<uuid>",
"provider": "fishaudio",
"display_name": "string",
"language": "ru",
"description": "string",
"status": "pending",
"voice_id": "string",
"attempts": 1,
"error": {
"reason": "string",
"message": "string"
},
"created_at": "<date-time>",
"completed_at": "<date-time>",
"failed_at": "<date-time>",
"banned_at": "<date-time>",
"ban_reason": "string"
}
}Values come from the spec where the spec has them; the rest are type-based placeholders. This is the shape of the event, not a recording of a real one.
All channels and connection parameters·POST /broadcasting/auth
Feed this page to an AI
spec 0.0.1