Interface Third-Party
Crie uma ferramenta que o BakoshApp possa controlar: exponha quatro endpoints HTTP em uma porta local, e seu programa reage a presentes, curtidas, seguidores e chat do TikTok e do Kick.
O BakoshApp pode executar ações dentro do seu programa. Sua ferramenta expõe uma pequena API HTTP em uma porta local; o BakoshApp lê a sua lista de ações e chama uma sempre que um evento do TikTok ou do Kick corresponde ao acionador do usuário. Qualquer coisa que você possa controlar por código — luzes inteligentes, um microcontrolador, uma soundboard, outro jogo, seu próprio bot — pode reagir a uma live sem um mod do BakoshApp.
Como tudo se encaixa
- Sua ferramenta escuta em
http://127.0.0.1:8833. - O usuário a conecta em Configurações → Third-Party (host e porta) e a verifica com Testar conexão.
- Na aba Ações de um mod, o usuário clica em Adicionar novo, escolhe um acionador e, em Todas as ações → Externos, configura uma Third-Party Action: o BakoshApp preenche duas listas com suas categorias e ações.
- A cada evento correspondente, o BakoshApp chama sua ferramenta, e o seu código faz o trabalho.
A conexão é de mão única: o BakoshApp chama você, nunca o contrário.
Porta e endereço
- 8833 é o padrão. O usuário pode alterá-la em Configurações → Third-Party; avise seus usuários de qual porta digitar se você usar outra.
- A porta 8832 não pode ser usada: é nela que o próprio BakoshApp escuta (é assim que o TikFinity encontra o BakoshApp), e a configuração a recusa.
- Não há autenticação. Escute em
127.0.0.1, não em0.0.0.0, para que a API não fique acessível pela rede. - O BakoshApp sempre usa HTTP simples.
Endpoints
Sua ferramenta deve expor os quatro. Toda resposta é um JSON com um membro data.
1. Informações do app
Identifica sua ferramenta. O BakoshApp a mostra como "Connected with Mock Tool 1.0 by Bakosh" em Configurações e no configurador de ações.
GET /api/app/info
{ "data": { "name": "Mock Tool", "version": "1.0", "author": "Bakosh" } }2. Categorias
A primeira lista no configurador.
GET /api/features/categories
{
"data": [
{ "categoryId": "smart_device_control", "categoryName": "Control Smart Devices" },
{ "categoryId": "serial_port_control", "categoryName": "Control Serial Port" }
]
}3. Ações
A segunda lista: as ações de uma categoria. O categoryId é codificado para URL.
GET /api/features/actions?categoryId=smart_device_control
{
"data": [
{ "actionId": "turn_lights_on", "actionName": "Turn Lights On" },
{ "actionId": "turn_lights_off", "actionName": "Turn Lights Off" }
]
}As listas mostram seus itens na ordem em que você os retorna. Uma ação que o usuário já salvou, mas que você não retorna mais, permanece no topo da lista, para que ela não mude silenciosamente.
categoryId e actionId são tudo o que o BakoshApp armazena de uma ação configurada. Mantenha-os estáveis: renomear um id quebra configurações existentes. Os nomes são só para exibição e podem mudar a qualquer momento.
4. Executar
Chamado toda vez que um evento correspondente executa a ação.
POST /api/features/actions/exec
{
"categoryId": "smart_device_control",
"actionId": "turn_lights_on",
"context": {
"triggerTypeId": 4,
"eventType": "gift",
"source": "eulerstream",
"platform": "tiktok",
"userId": "123456789",
"username": "testuser",
"nickname": "Test User",
"giftName": "Rose",
"giftId": 5655,
"repeatCount": 3,
"diamondCount": 1,
"coins": 1,
"profilePictureUrl": "https://…"
}
}Responda com um array data vazio assim que aceitar a requisição:
{ "data": [] }Tempos de resposta
- O BakoshApp espera até 5 segundos pelos três endpoints GET e 10 segundos pelo
exec. Uma requisição que falha ou expira não é repetida. - Se a ação tiver Quantidade acima de 1, o BakoshApp chama o
execesse número de vezes, uma após a outra: ele espera sua resposta, depois o Intervalo da linha, e chama de novo. - As chamadas da mesma linha vêm uma de cada vez; linhas diferentes podem chamar você em paralelo.
Por isso, responda rápido e faça o trabalho demorado em segundo plano — os espectadores podem enviar presentes mais rápido do que uma porta serial consegue processar.
O objeto context
O context descreve o evento que executou a ação. Só estão presentes os campos que existem para aquele evento — verifique antes de ler.
| Campo | Tipo | Presente |
|---|---|---|
triggerTypeId | number | sempre — veja abaixo |
eventType | string | sempre — gift, like, chat, follow, share, joined, subscribe, tikfinity ou test |
source | string | sempre — eulerstream (TikTok), kick, tikfinity ou test |
platform | string | eventos do TikTok e do Kick — tiktok ou kick |
username | string | sempre — o nome de usuário do espectador |
nickname | string | eventos do TikTok e do Kick — o nome de exibição |
userId | string | eventos do TikTok e do Kick |
profilePictureUrl | string | geralmente (os links de avatar do TikTok expiram) |
comment | string | mensagens de chat; no Kick, também a mensagem anexada a um presente |
giftName | string | presentes |
giftId | number | presentes do TikTok |
repeatCount | number | presentes do TikTok — presentes na sequência (streak); assinaturas presenteadas no Kick — número de destinatários |
diamondCount | number | presentes — valor em Diamonds (TikTok) ou preço em Kicks (Kick) |
coins | number | o mesmo que diamondCount |
likeCount | number | curtidas |
subMonth | number | assinaturas |
Eventos retransmitidos pelo TikFinity trazem apenas triggerTypeId (sempre 0), source, eventType e username.
Tipos de acionador
O triggerTypeId é o tipo do acionador que o usuário configurou, então um presente escolhido pelo nome e um presente identificado pelo valor são diferenciados:
| Id | Acionador |
|---|---|
| 1 | Compartilhar |
| 3 | Mín-Máx (faixa de valor do presente) |
| 4 | Presente |
| 6 | Entrou |
| 7 | Like |
| 9 | Seguir |
| 10 | Subscribe / Super Fan |
| 11 | Chat |
| 0 | TikFinity, ou qualquer outra coisa |
Trate ids desconhecidos como 0; mais podem ser adicionados.
O botão Testar
Testar na linha da ação (e sua tecla de atalho) chama o exec com dados de exemplo: source e eventType são test, o triggerTypeId vem do acionador da linha, o espectador é bakosh_app, e o presente é uma Rose (giftId 5655). Não há platform.
Relatando problemas
Retorne uma message para descrever o que deu errado:
{ "message": "Serial port COM3 is not available" }- Nos endpoints GET, qualquer
messagefaz o BakoshApp tratar a resposta como um erro, mesmo com HTTP 200. - No
exec, amessageé gravada no console e no arquivo de log do BakoshApp como um aviso. O usuário não recebe um pop-up.
Status de erro HTTP também são respeitados; sem uma message, o log mostra apenas o código de status.
Funcionando com o TikFinity também
A interface é igual à interface de terceiros do TikFinity — os mesmos quatro caminhos e nomes de campo — então uma ferramenta pode atender aos dois. As portas são diferentes: o TikFinity procura ferramentas na 8832, que o BakoshApp ocupa enquanto está em execução, então dê ao BakoshApp outra porta.
O TikFinity é um app web e precisa de cabeçalhos CORS (Access-Control-Allow-Origin: * e afins) além de respostas às requisições de preflight OPTIONS. O BakoshApp não precisa deles, mas enviá-los não causa nenhum problema. O BakoshApp envia mais campos de context do que o TikFinity — ignore os que você não usar.
Uma ferramenta completa e funcional
Sem dependências — salve como tool.mjs e execute node tool.mjs:
import http from 'node:http';
const PORT = 8833;
const APP_INFO = { name: 'Mock Tool', version: '1.0', author: 'Bakosh' };
const CATALOG = [
{
categoryId: 'smart_device_control',
categoryName: 'Control Smart Devices',
actions: [
{ actionId: 'turn_lights_on', actionName: 'Turn Lights On' },
{ actionId: 'turn_lights_off', actionName: 'Turn Lights Off' },
],
},
];
// Wildcard CORS keeps the same tool usable from TikFinity as well.
const CORS = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': '*',
'Access-Control-Allow-Methods': '*',
};
const send = (res, status, body) => {
res.writeHead(status, { 'Content-Type': 'application/json', ...CORS });
res.end(JSON.stringify(body));
};
const readBody = (req) =>
new Promise((resolve) => {
let raw = '';
req.on('data', (c) => { raw += c; });
req.on('end', () => { try { resolve(JSON.parse(raw || '{}')); } catch { resolve({}); } });
});
// Your actual work goes here. Return a string to report a problem.
function runAction(categoryId, actionId, context) {
console.log(`${categoryId}/${actionId} fired by ${context.username ?? 'someone'} on ${context.platform ?? context.source}`);
// turnLightsOn() …
return null;
}
http.createServer(async (req, res) => {
const url = new URL(req.url, `http://127.0.0.1:${PORT}`);
if (req.method === 'OPTIONS') { // preflight (TikFinity only)
res.writeHead(204, CORS);
return res.end();
}
if (req.method === 'GET' && url.pathname === '/api/app/info') {
return send(res, 200, { data: APP_INFO });
}
if (req.method === 'GET' && url.pathname === '/api/features/categories') {
return send(res, 200, {
data: CATALOG.map(({ categoryId, categoryName }) => ({ categoryId, categoryName })),
});
}
if (req.method === 'GET' && url.pathname === '/api/features/actions') {
const cat = CATALOG.find((c) => c.categoryId === url.searchParams.get('categoryId'));
return send(res, 200, { data: cat ? cat.actions : [] });
}
if (req.method === 'POST' && url.pathname === '/api/features/actions/exec') {
const body = await readBody(req);
const problem = runAction(body.categoryId ?? '', body.actionId ?? '', body.context ?? {});
return problem ? send(res, 200, { message: problem }) : send(res, 200, { data: [] });
}
send(res, 404, { message: `No such endpoint: ${url.pathname}` });
}).listen(PORT, '127.0.0.1', () => console.log(`Listening on http://127.0.0.1:${PORT}`));Testando sua ferramenta
- Inicie sua ferramenta.
- No BakoshApp, abra Configurações → Third-Party, confira o host e a porta, e clique em Testar conexão. Você deve ver o nome, a versão e o autor da sua ferramenta.
- Na aba Ações de um mod, clique em Adicionar novo, escolha um acionador e clique em Próximo. Em Todas as ações → Externos, clique em Configure ao lado de Third-Party Action, escolha sua categoria e ação, e salve.
- Clique em Testar na nova linha — sua ferramenta recebe um
execcomeventType: "test". - Entre ao vivo e verifique se eventos reais chegam.
Se o configurador disser "Não foi possível conectar! Verifique sua integração.", verifique se a ferramenta escuta em 127.0.0.1, se a porta corresponde às Configurações, e se GET /api/app/info retorna sua resposta dentro de data.