API de logs
Mande logs por HTTP para o FiveDash com o mesmo formato do webhook do Discord: endpoint, autenticação, corpo, limites, respostas, erros e exemplos.
Mande logs por HTTP para o FiveDash com o mesmo formato do webhook do Discord: endpoint, autenticação, corpo, limites, respostas, erros e exemplos.
Cada log do FiveDash tem um link próprio que funciona como um webhook do Discord. Qualquer script, bot ou sistema que já manda para discord.com/api/webhooks/... passa a mandar para o FiveDash trocando só o link. Esta página é a referência completa desse endpoint, e mostra também o jeito mais rápido de mandar logs de dentro da cidade: o export do recurso fivedash.
| Jeito | Quando usar |
|---|---|
Export exports.fivedash:log | Scripts da cidade, no lado do servidor. Mais rápido, já lê o passaporte, o nome e os identificadores do jogador, e não expõe nenhum link. Recomendado |
| Link (webhook) | Scripts prontos que já mandam para um webhook do Discord, bots e sistemas fora da cidade |
No módulo Logs, clique no log na barra lateral.
Clique em Como mandar. Se o log está no modo export, clique em Usar webhook.
Copie o link e cole no script onde estava o link do Discord. Não compartilhe: com o link, qualquer um manda logs para esse log.
O link tem esta forma:
https://<endereço-dos-logs>/api/logs/<channelId>/<token>
Use sempre o link exatamente como o painel mostra. O endereço dos logs pode ser diferente do endereço do painel. Links antigos, no endereço do painel, continuam funcionando.
| Método | URL | O que faz |
|---|---|---|
POST | /api/logs/<channelId>/<token> | Grava um ou mais logs |
GET | /api/logs/<channelId>/<token> | Confere o link (responde como um webhook do Discord) |
Autenticação: o próprio token no caminho. Não precisa de cabeçalho Authorization.
| Parâmetro | Onde | O que é |
|---|---|---|
channelId | caminho | O ID do log (um UUID) |
token | caminho | O segredo do log |
wait | query | ?wait=true faz a resposta trazer a mensagem gravada (status 200), como no Discord. Sem ele, a resposta é 204 sem corpo |
| Cabeçalho | Obrigatório | O que faz |
|---|---|---|
Content-Type | Sim | application/json, multipart/form-data ou application/x-www-form-urlencoded |
Idempotency-Key | Não | Um ID seu para a mensagem (1 a 256 caracteres, sem caracteres de controle). Repetir o mesmo ID não grava o log duas vezes. Exige X-FiveDash-Event-At |
X-FiveDash-Event-At | Com Idempotency-Key | Quando aconteceu, em milissegundos Unix (ex.: 1762711200000). Precisa estar entre 7 dias atrás e 5 minutos à frente |
Sem esses dois cabeçalhos, cada POST grava logs novos, com a hora de chegada.
O mesmo corpo de um webhook do Discord:
{
"username": "meu-script",
"content": "Texto solto, opcional",
"embeds": [
{
"title": "Compra na loja",
"description": "João comprou 3 águas",
"color": 3066993,
"fields": [
{ "name": "Item", "value": "água", "inline": true },
{ "name": "Qtd", "value": "3", "inline": true }
],
"author": { "name": "Loja 24/7" },
"footer": { "text": "Cidade Exemplo" },
"image": { "url": "https://cdn.fivex.sh/cidade-exemplo/prints/print-0001.webp" },
"timestamp": "2026-11-09T18:00:00.000Z"
}
]
}
| Campo | Tipo | O que vira no FiveDash | Limite |
|---|---|---|---|
content | string | Texto do log. Sem title, a primeira linha vira o título | 2.000 caracteres |
username | string | O nome de quem mandou. Aparece como o Script do log e serve de filtro | 80 caracteres |
embeds | array | Cada embed vira um log separado | 10 embeds |
embeds[].title | string | Título do log | 256 |
embeds[].description | string | Texto do log | 4.096 |
embeds[].url | string | Link do título (http/https) | |
embeds[].color | number | Cor da faixa | |
embeds[].fields | array | Campos { "name", "value", "inline" } | 25 campos; name 256, value 1.024 |
embeds[].author.name | string | Autor | 256 |
embeds[].footer.text | string | Rodapé | 2.048 |
embeds[].image.url | string | Imagem grande (http/https) | |
embeds[].thumbnail.url | string | Miniatura (http/https) | |
embeds[].timestamp | string | Data do embed (ISO 8601) | 64 |
Outros campos do Discord (avatar_url, tts, components, allowed_mentions…) são aceitos e ignorados. Textos maiores que o limite são cortados.
O FiveDash também lê o texto para a busca e os filtros, sem você mudar nada no script:
| No texto | Vira |
|---|---|
Linhas como **Item:** água, Item: água, Item = água ou [Item]: água, e os fields | Pares de campo e valor |
Passaporte: 123, passport 123, user_id: 123, citizenid: 123, ou um campo como ID, Vítima ou Assassino com um número | ID de jogador |
<@123456789012345678> ou discord:123456789012345678 | Conta do Discord |
license:…, license2:…, steam:…, fivem:…, xbl:…, live:… | Identificadores |
vector3(1.0, 2.0, 3.0), x: 1.0, y: 2.0, z: 3.0 ou 1.0, 2.0, 3.0 | Coordenadas |
Isso vale até 10 jogadores, 10 Discords, 10 identificadores e 10 coordenadas por log.
Para scripts que mandam como o Discord aceita em multipart/form-data ou application/x-www-form-urlencoded:
| Campo do formulário | O que é |
|---|---|
payload_json | O mesmo JSON acima, como texto |
content | Usado se payload_json não tiver content |
username | Usado se payload_json não tiver username |
Arquivos (files[0], file…) | Aceitos, mas não são guardados: o log registra só quantos vieram |
Uma mensagem só com arquivo (sem texto e sem embed) também vira um log.
| Limite | Valor |
|---|---|
| Corpo JSON | 256 KB |
| Corpo multipart ou formulário | 4 MB |
| Embeds por mensagem | 10 (cada um vira um log) |
| Campos por embed | 25 |
| Status | Quando | Corpo |
|---|---|---|
204 | Gravado (sem ?wait=true) | vazio |
200 | Gravado, com ?wait=true | A mensagem, no formato do Discord (veja abaixo) |
200 | GET no link | Os dados do webhook |
Resposta com ?wait=true:
{
"id": "0193a5f0-0000-7000-8000-000000000000",
"type": 0,
"channel_id": "<channelId>",
"webhook_id": "<channelId>",
"author": { "id": "<channelId>", "username": "meu-script", "bot": true, "discriminator": "0000", "avatar": null },
"attachments": [],
"mentions": [],
"mention_roles": [],
"pinned": false,
"mention_everyone": false,
"tts": false,
"timestamp": "2026-11-09T18:00:00.123Z",
"edited_timestamp": null,
"flags": 0,
"components": [],
"content": "Texto solto, opcional",
"embeds": [{ "title": "Compra na loja" }]
}
Resposta do GET:
{ "type": 1, "id": "<channelId>", "name": "Loja", "avatar": null, "channel_id": "<channelId>", "guild_id": null, "application_id": null, "token": "<token>" }
Os erros seguem os códigos do Discord, para scripts que já tratam esses casos.
| Status | Corpo | Quando |
|---|---|---|
400 | {"code":50109,"message":"The request body contains invalid JSON."} | JSON inválido ou formulário malformado |
400 | {"code":50006,"message":"Cannot send an empty message"} | Sem content, sem embed com conteúdo e sem arquivo |
400 | {"code":50035,"message":"…"} | Conteúdo inválido, Idempotency-Key inválida, ou X-FiveDash-Event-At faltando ou fora do prazo (“data do evento inválida ou fora do prazo”) |
401 | {"code":50027,"message":"Invalid Webhook Token"} | O token não confere (por exemplo, depois de Gerar novo link) |
404 | {"code":10015,"message":"Unknown Webhook"} | O log não existe ou foi excluído |
409 | {"code":50035,"message":"destino do evento removido ou inválido"} | O log não está mais ativo |
413 | {"code":40005,"message":"Request entity too large"} | Corpo acima do limite |
429 | {"error":"too_many","message":"limite de eventos ou bytes por segundo atingido"} | Rápido demais para o servidor. Respeite o Retry-After (1 s) |
503 | {"error":"unavailable","message":"serviço temporariamente indisponível"} | Serviço ocupado ou fora. Tente de novo depois do Retry-After |
curl -X POST "https://<endereço-dos-logs>/api/logs/<channelId>/<token>" \
-H "Content-Type: application/json" \
-d '{
"username": "meu-script",
"embeds": [{
"title": "Compra na loja",
"fields": [{ "name": "Item", "value": "água" }, { "name": "Qtd", "value": "3" }]
}]
}'
Com confirmação e sem duplicar:
curl -X POST "https://<endereço-dos-logs>/api/logs/<channelId>/<token>?wait=true" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: compra-48213" \
-H "X-FiveDash-Event-At: 1762711200000" \
-d '{ "content": "Pedido 48213 entregue" }'
Multipart, como o Discord:
curl -X POST "https://<endereço-dos-logs>/api/logs/<channelId>/<token>" \
-F 'payload_json={"username":"meu-script","content":"Print anexado"}' \
-F "files[0]=@print.png"
No lado do servidor de um script que hoje manda para o Discord, troque só o link:
local LOG_URL = "https://<endereço-dos-logs>/api/logs/<channelId>/<token>"
local function sendLog(title, fields)
local embed = { title = title, color = 3066993, fields = {} }
for _, field in ipairs(fields) do
embed.fields[#embed.fields + 1] = { name = field[1], value = tostring(field[2]), inline = true }
end
PerformHttpRequest(LOG_URL, function(status)
if status ~= 204 then print(("[logs] FiveDash respondeu %s"):format(status)) end
end, "POST", json.encode({ username = GetCurrentResourceName(), embeds = { embed } }), {
["Content-Type"] = "application/json",
})
end
sendLog("Compra na loja", { { "Item", "água" }, { "Qtd", 3 } })
const LOG_URL = process.env.FIVEDASH_LOG_URL!; // o link do log, fora do código
await fetch(`${LOG_URL}?wait=true`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Idempotency-Key": "ban-9921",
"X-FiveDash-Event-At": String(Date.now()),
},
body: JSON.stringify({
username: "bot-da-staff",
embeds: [{ title: "Banimento", fields: [{ name: "Motivo", value: "RDM" }] }],
}),
});
Nos scripts da cidade, prefira o export do recurso fivedash. Ele não usa link, junta os logs em lotes, guarda na fila quando o painel está fora e preenche o passaporte, o nome e os identificadores do jogador sozinho:
exports.fivedash:log("mortes", {
title = "Morte registrada",
players = { { source = killer, label = "Assassino" }, { source = victim, label = "Vítima" } },
fields = { { "Arma", weapon } },
})
A Chave (mortes) é a do log no painel. Todas as opções estão em Exports, eventos e comandos.
Por baixo, o recurso usa dois endpoints próprios, autenticados pela chave do servidor (Authorization: Bearer fdk_…): GET /api/fivem/logs/channels (quais chaves existem) e POST /api/fivem/logs (lotes de até 500 logs, JSON com gzip opcional, até 2 MB). Eles são do recurso: não chame direto dos seus scripts.
Meu script manda para o Discord e para o FiveDash ao mesmo tempo? Não: você troca o link do Discord pelo do FiveDash. Se quiser os dois, o script precisa mandar duas vezes.
O FiveDash guarda os arquivos anexados?
Não. Ele aceita o envio (para não quebrar o script) e registra quantos arquivos vieram. Para guardar imagens, use a CDN e mande o link em image.url.
Recebi 401 depois de um tempo. Alguém clicou em Gerar novo link. Copie o link novo do painel e troque no script.
Uma mensagem com 3 embeds vira quantos logs?
Três: um por embed. O content vai junto do primeiro.