Logs API
Send logs to FiveDash over HTTP in the same format as a Discord webhook: endpoint, auth, body, limits, responses, errors and examples.
Send logs to FiveDash over HTTP in the same format as a Discord webhook: endpoint, auth, body, limits, responses, errors and examples.
Every FiveDash log has its own link that works like a Discord webhook. Any script, bot or system that already sends to discord.com/api/webhooks/... can send to FiveDash by swapping only the link. This page is the full reference for that endpoint, and it also shows the fastest way to send logs from inside the city: the fivedash resource’s export.
| Way | When to use |
|---|---|
Export exports.fivedash:log | City scripts, server side. Faster, it already reads the player’s character ID, name and identifiers, and exposes no link. Recommended |
| Link (webhook) | Ready-made scripts that already send to a Discord webhook, bots and systems outside the city |
In the Logs module, click the log in the sidebar.
Click How to send. If the log is in export mode, click Use webhook.
Copy the link and paste it in the script where the Discord link was. Don’t share it: with the link, anyone can send logs to that log.
The link looks like this:
https://<logs-address>/api/logs/<channelId>/<token>
Always use the link exactly as the panel shows it. The logs address may be different from the panel’s address. Old links, on the panel’s address, keep working.
| Method | URL | What it does |
|---|---|---|
POST | /api/logs/<channelId>/<token> | Stores one or more logs |
GET | /api/logs/<channelId>/<token> | Checks the link (answers like a Discord webhook) |
Authentication: the token in the path itself. No Authorization header needed.
| Parameter | Where | What it is |
|---|---|---|
channelId | path | The log’s ID (a UUID) |
token | path | The log’s secret |
wait | query | ?wait=true makes the response carry the stored message (status 200), like Discord. Without it, the response is 204 with no body |
| Header | Required | What it does |
|---|---|---|
Content-Type | Yes | application/json, multipart/form-data or application/x-www-form-urlencoded |
Idempotency-Key | No | Your own ID for the message (1 to 256 characters, no control characters). Repeating the same ID doesn’t store the log twice. Requires X-FiveDash-Event-At |
X-FiveDash-Event-At | With Idempotency-Key | When it happened, in Unix milliseconds (e.g. 1762711200000). Must be between 7 days ago and 5 minutes ahead |
Without these two headers, each POST stores new logs, with the arrival time.
The same body as a Discord webhook:
{
"username": "my-script",
"content": "Loose text, optional",
"embeds": [
{
"title": "Store purchase",
"description": "John bought 3 waters",
"color": 3066993,
"fields": [
{ "name": "Item", "value": "water", "inline": true },
{ "name": "Qty", "value": "3", "inline": true }
],
"author": { "name": "24/7 Store" },
"footer": { "text": "Example City" },
"image": { "url": "https://cdn.fivex.sh/example-city/screenshots/print-0001.webp" },
"timestamp": "2026-11-09T18:00:00.000Z"
}
]
}
| Field | Type | What it becomes in FiveDash | Limit |
|---|---|---|---|
content | string | The log’s text. Without a title, its first line becomes the title | 2,000 characters |
username | string | Who sent it. Shows as the log’s Script and works as a filter | 80 characters |
embeds | array | Each embed becomes a separate log | 10 embeds |
embeds[].title | string | The log’s title | 256 |
embeds[].description | string | The log’s text | 4,096 |
embeds[].url | string | Title link (http/https) | |
embeds[].color | number | Stripe color | |
embeds[].fields | array | Fields { "name", "value", "inline" } | 25 fields; name 256, value 1,024 |
embeds[].author.name | string | Author | 256 |
embeds[].footer.text | string | Footer | 2,048 |
embeds[].image.url | string | Large image (http/https) | |
embeds[].thumbnail.url | string | Thumbnail (http/https) | |
embeds[].timestamp | string | The embed’s date (ISO 8601) | 64 |
Other Discord fields (avatar_url, tts, components, allowed_mentions…) are accepted and ignored. Text over the limit is cut.
FiveDash also reads the text for search and filters, with no change to your script:
| In the text | Becomes |
|---|---|
Lines like **Item:** water, Item: water, Item = water or [Item]: water, and the fields | Field and value pairs |
Passaporte: 123, passport 123, user_id: 123, citizenid: 123, or a field like ID, Victim or Killer with a number | Player ID |
<@123456789012345678> or discord:123456789012345678 | Discord account |
license:…, license2:…, steam:…, fivem:…, xbl:…, live:… | Identifiers |
vector3(1.0, 2.0, 3.0), x: 1.0, y: 2.0, z: 3.0 or 1.0, 2.0, 3.0 | Coordinates |
This covers up to 10 players, 10 Discords, 10 identifiers and 10 coordinates per log.
For scripts that send the way Discord accepts in multipart/form-data or application/x-www-form-urlencoded:
| Form field | What it is |
|---|---|
payload_json | The same JSON as above, as text |
content | Used if payload_json has no content |
username | Used if payload_json has no username |
Files (files[0], file…) | Accepted, but not stored: the log only records how many came |
A message with only a file (no text and no embed) also becomes a log.
| Limit | Value |
|---|---|
| JSON body | 256 KB |
| Multipart or form body | 4 MB |
| Embeds per message | 10 (each becomes a log) |
| Fields per embed | 25 |
| Status | When | Body |
|---|---|---|
204 | Stored (without ?wait=true) | empty |
200 | Stored, with ?wait=true | The message, in Discord’s format (see below) |
200 | GET on the link | The webhook’s data |
Response with ?wait=true:
{
"id": "0193a5f0-0000-7000-8000-000000000000",
"type": 0,
"channel_id": "<channelId>",
"webhook_id": "<channelId>",
"author": { "id": "<channelId>", "username": "my-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": "Loose text, optional",
"embeds": [{ "title": "Store purchase" }]
}
GET response:
{ "type": 1, "id": "<channelId>", "name": "Store", "avatar": null, "channel_id": "<channelId>", "guild_id": null, "application_id": null, "token": "<token>" }
Errors follow Discord’s codes, for scripts that already handle those cases. Some messages come in Portuguese.
| Status | Body | When |
|---|---|---|
400 | {"code":50109,"message":"The request body contains invalid JSON."} | Invalid JSON or malformed form |
400 | {"code":50006,"message":"Cannot send an empty message"} | No content, no embed with content and no file |
400 | {"code":50035,"message":"…"} | Invalid content, invalid Idempotency-Key, or X-FiveDash-Event-At missing or out of range (“data do evento inválida ou fora do prazo”) |
401 | {"code":50027,"message":"Invalid Webhook Token"} | The token doesn’t match (for example, after Generate new link) |
404 | {"code":10015,"message":"Unknown Webhook"} | The log doesn’t exist or was deleted |
409 | {"code":50035,"message":"destino do evento removido ou inválido"} | The log is no longer active |
413 | {"code":40005,"message":"Request entity too large"} | Body over the limit |
429 | {"error":"too_many","message":"limite de eventos ou bytes por segundo atingido"} | Too fast for the server. Honor Retry-After (1 s) |
503 | {"error":"unavailable","message":"serviço temporariamente indisponível"} | Service busy or down. Retry after Retry-After |
curl -X POST "https://<logs-address>/api/logs/<channelId>/<token>" \
-H "Content-Type: application/json" \
-d '{
"username": "my-script",
"embeds": [{
"title": "Store purchase",
"fields": [{ "name": "Item", "value": "water" }, { "name": "Qty", "value": "3" }]
}]
}'
With confirmation and no duplicates:
curl -X POST "https://<logs-address>/api/logs/<channelId>/<token>?wait=true" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: purchase-48213" \
-H "X-FiveDash-Event-At: 1762711200000" \
-d '{ "content": "Order 48213 delivered" }'
Multipart, like Discord:
curl -X POST "https://<logs-address>/api/logs/<channelId>/<token>" \
-F 'payload_json={"username":"my-script","content":"Screenshot attached"}' \
-F "files[0]=@print.png"
On the server side of a script that sends to Discord today, swap only the link:
local LOG_URL = "https://<logs-address>/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 answered %s"):format(status)) end
end, "POST", json.encode({ username = GetCurrentResourceName(), embeds = { embed } }), {
["Content-Type"] = "application/json",
})
end
sendLog("Store purchase", { { "Item", "water" }, { "Qty", 3 } })
const LOG_URL = process.env.FIVEDASH_LOG_URL!; // the log's link, outside the code
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: "staff-bot",
embeds: [{ title: "Ban", fields: [{ name: "Reason", value: "RDM" }] }],
}),
});
In city scripts, prefer the fivedash resource’s export. It uses no link, batches logs, keeps them in a queue while the panel is away and fills in the player’s character ID, name and identifiers on its own:
exports.fivedash:log("deaths", {
title = "Death recorded",
players = { { source = killer, label = "Killer" }, { source = victim, label = "Victim" } },
fields = { { "Weapon", weapon } },
})
The Key (deaths) is the log’s key in the panel. Every option is in Exports, events and commands.
Under the hood, the resource uses two endpoints of its own, authenticated by the server key (Authorization: Bearer fdk_…): GET /api/fivem/logs/channels (which keys exist) and POST /api/fivem/logs (batches of up to 500 logs, JSON with optional gzip, up to 2 MB). They belong to the resource: don’t call them directly from your scripts.
Does my script send to Discord and FiveDash at the same time? No: you swap the Discord link for the FiveDash one. If you want both, the script must send twice.
Does FiveDash keep attached files?
No. It accepts the upload (so the script doesn’t break) and records how many files came. To keep images, use the CDN and send the link in image.url.
I got 401 after a while. Someone clicked Generate new link. Copy the new link from the panel and update the script.
How many logs does a message with 3 embeds become?
Three: one per embed. The content goes with the first.