API da CDN
Envie arquivos para a CDN do FiveDash a partir de scripts com chaves de envio: endpoints, autenticação, formatos, respostas, erros e exemplos em cURL, Lua e JS.
Envie arquivos para a CDN do FiveDash a partir de scripts com chaves de envio: endpoints, autenticação, formatos, respostas, erros e exemplos em cURL, Lua e JS.
A CDN do FiveDash guarda as imagens, vídeos e sons da cidade num link público e rápido. Para scripts que mandam arquivos sozinhos (prints do screenshot-basic, fotos de câmera, clipes), existe uma API simples com chaves de envio: cada chave manda arquivos só para uma pasta. Esta página é a referência dessa API, para quem desenvolve scripts.
402.fdm_ e aparece inteira uma vez só.Vá em CDN → Configurações e role até Chaves de envio (/<org>/<servidor>/cdn/configuracoes).
Clique em Nova chave. Em Nova chave de envio, dê um nome (ex.: Câmera do jogo).
Em Envia para, escolha a Pasta da chave. A chave só envia para essa pasta: se vazar, o estrago fica ali.
Marque Também pode apagar só se o script precisar limpar o que enviou.
Clique em Criar chave. Em Chave criada, clique em Copiar chave. Depois disso, só aparecem o começo e o fim. O mesmo diálogo traz o código pronto em duas abas: screenshot-basic (Lua) e HTTP (cURL), já com o endereço certo.
Na lista de Chaves de envio aparecem o nome, a pasta, Também apaga (quando pode apagar), quantos envios a chave fez e quando foi usada. Para cortar uma chave, use Revogar: os scripts com ela param de enviar na hora, e os arquivos já enviados continuam. Cada servidor pode ter até 50 chaves.
Use o endereço que aparece no diálogo Chave criada. No endereço padrão da CDN:
https://cdn.fivex.sh/api/v1/upload
| Método | Caminho | O que faz | Chave precisa de |
|---|---|---|---|
POST | /api/v1/upload | Envia um arquivo para a pasta da chave | qualquer chave |
DELETE | /api/v1/files/<id> | Apaga um arquivo que essa mesma chave enviou | Também pode apagar |
Não existe envio em base64 nem URL pré-assinada para scripts: o envio é sempre um multipart/form-data com o arquivo. (Os envios grandes em partes que o painel faz são só do painel.)
| Cabeçalho | Obrigatório | O que é |
|---|---|---|
Authorization | Sim | Bearer fdm_<64 caracteres hexadecimais> |
Content-Type | Sim, no upload | multipart/form-data; boundary=… (o cURL, o fetch e o screenshot-basic montam sozinhos) |
Idempotency-Key | Não | De 8 a 128 caracteres: letras, números, _, . e -. Repetir a mesma operação com o mesmo ID em até 24 horas não duplica o arquivo |
A chave define o servidor e a pasta. Não dá para escolher outra pasta no formulário.
POST /api/v1/upload
O formulário precisa ter um único campo, o arquivo, com o nome file (ou files[]). Outros campos fazem o envio ser recusado.
| Regra | Valor |
|---|---|
| Arquivos por chamada | 1 |
| Tamanho por chamada | até 20 MB (e nunca acima do tamanho máximo da seção Envios das configurações) |
| Nome do arquivo | O nome que vem no formulário, de 1 a 180 caracteres, sem /, \, %, ?, # nem espaços nas pontas. Se já existe um arquivo com esse nome na pasta, entra -1, -2… antes da extensão |
| Tipo do arquivo | O Content-Type da parte do arquivo, um destes: image/png, image/jpeg, image/webp, image/gif, image/svg+xml, video/mp4, video/webm, video/quicktime, audio/mpeg, audio/ogg, audio/wav, audio/mp4 |
| Conteúdo | Precisa bater com o tipo informado. Um .png que não é PNG é recusado (415) |
| Tempo | O corpo precisa chegar em até 2 minutos |
PNG, JPEG e WebP podem ser otimizados no envio, conforme a seção Imagens das configurações (qualidade, largura máxima e remoção de metadados). GIF, SVG, áudio e vídeo ficam como foram enviados.
200 OK:
{
"ok": true,
"id": "6f1d0c9e-2b7a-4c1e-9f3a-1a2b3c4d5e6f",
"url": "https://cdn.fivex.sh/cidade-exemplo/prints/print-0001.webp",
"file": {
"id": "6f1d0c9e-2b7a-4c1e-9f3a-1a2b3c4d5e6f",
"name": "print-0001.webp",
"folderId": "pasta_exemplo",
"kind": "image",
"mime": "image/webp",
"size": 183204,
"width": 1920,
"height": 1080,
"duration": null,
"src": "https://cdn.fivex.sh/cidade-exemplo/prints/print-0001.webp",
"thumb": null,
"optimizedSize": 120544,
"uploadedBy": "Chave: Câmera do jogo",
"createdAt": "2026-11-09T18:00:00.000Z",
"starred": false,
"trashedAt": null,
"hits": 0
}
}
| Campo | O que é |
|---|---|
id | O ID do arquivo. Guarde se o script for apagar depois |
url | O link público do arquivo. Use sempre este, não monte o link na mão (o nome pode ter ganhado -1) |
file.kind | image, video ou audio |
file.size | Bytes enviados |
file.optimizedSize | Bytes depois da otimização, quando ela aconteceu |
file.duration | Segundos, só para vídeo e áudio |
file.uploadedBy | Chave: <nome da chave> |
O link segue o formato https://cdn.fivex.sh/<endereço-da-cdn>/<pastas>/<nome>. Com domínio próprio (plano Ultra), o link usa o seu domínio.
DELETE /api/v1/files/<id>
Só funciona com uma chave que tem Também pode apagar, e só alcança arquivos que essa mesma chave enviou para a pasta dela. O arquivo é apagado na hora, sem passar pela lixeira, e o link para de responder. Repetir o mesmo DELETE com a mesma Idempotency-Key responde { "ok": true } de novo.
curl -X DELETE "https://cdn.fivex.sh/api/v1/files/6f1d0c9e-2b7a-4c1e-9f3a-1a2b3c4d5e6f" \
-H "Authorization: Bearer fdm_xxxxxxxx"
Resposta 200 OK:
{ "ok": true }
Os erros vêm como { "ok": false, "code": "…", "message": "…" }, com a mensagem em português.
| Status | code | Mensagem | Quando |
|---|---|---|---|
400 | invalid_request | “Envie um formulário multipart válido.” | O corpo não é multipart/form-data |
400 | invalid_request | “Envie um único arquivo por formulário.” | Mais de um campo no formulário |
400 | invalid_request | “Envie um arquivo no campo file.” | Sem arquivo, arquivo vazio ou maior que 20 MB |
400 | “Dados inválidos.” | Tipo de arquivo não aceito ou nome inválido | |
400 | invalid_request | “A chave de repetição é inválida.” | Idempotency-Key fora do formato |
401 | invalid_request | “Chave de envio inválida.” | Sem Authorization, formato errado ou chave que não existe |
401 | invalid_request | “A chave de envio foi revogada.” | A chave foi revogada no painel |
402 | invalid_request | “O plano da CDN venceu.” | O plano da CDN não está ativo |
403 | invalid_request | “Essa chave não pode apagar arquivos.” | DELETE sem Também pode apagar |
404 | invalid_request | “A pasta da chave não está disponível.” | A pasta da chave foi apagada ou está na lixeira |
404 | invalid_request | “Arquivo não encontrado.” | DELETE de um arquivo que não é dessa chave ou não existe |
405 | invalid_request | “Operação não permitida.” | Método ou caminho que não existe |
408 | invalid_request | “O envio demorou demais. Tente novamente.” | O corpo levou mais de 2 minutos |
409 | invalid_request | “A solicitação já foi usada com outros dados.” | Mesma Idempotency-Key com outro arquivo |
409 | invalid_request | “A chave de repetição expirou. Use uma nova chave.” | Idempotency-Key com mais de 24 horas |
413 | invalid_request | “A solicitação é grande demais.” / “O arquivo ultrapassa o tamanho permitido.” / “Imagens podem ter até 20 MB.” | Arquivo grande demais |
415 | invalid_request | “O conteúdo não corresponde ao formato informado.” | O conteúdo não é do tipo informado |
429 | quota_exceeded | “A franquia de armazenamento ou envios foi atingida.” | O servidor chegou no limite do plano |
429 | busy | “Há muitos envios em andamento. Tente novamente em instantes.” | Muitos envios ao mesmo tempo |
503 | unavailable | “A CDN está indisponível. Tente novamente.” | Falha temporária |
curl -X POST https://cdn.fivex.sh/api/v1/upload \
-H "Authorization: Bearer fdm_xxxxxxxx" \
-H "Idempotency-Key: print-20261109-0001" \
-F "file=@print.png"
Para vídeo e áudio, informe o tipo na parte do arquivo (o cURL não descobre todos sozinho):
curl -X POST https://cdn.fivex.sh/api/v1/upload \
-H "Authorization: Bearer fdm_xxxxxxxx" \
-F "file=@clipe.mp4;type=video/mp4"
O mesmo código que o painel mostra em Chave criada:
exports['screenshot-basic']:requestScreenshotUpload('https://cdn.fivex.sh/api/v1/upload', 'file', {
headers = { ['Authorization'] = 'Bearer fdm_xxxxxxxx' },
encoding = 'webp'
}, function(data)
local res = json.decode(data)
print(res.url) -- https://cdn.fivex.sh/cidade-exemplo/prints/print-….webp
end)
Para registrar o print num log, mande o res.url para o servidor com um evento do seu script e chame o export de logs lá, com image = url.
Num server_script em JavaScript, o Node 22 do FXServer já tem fetch, FormData e Blob. Assim a chave fica no servidor:
// server.js — a chave vem de uma convar: set cdn_upload_key "fdm_xxxxxxxx"
const KEY = GetConvar("cdn_upload_key", "");
async function uploadToCdn(bytes, name, type) {
const form = new FormData();
form.append("file", new Blob([bytes], { type }), name);
const response = await fetch("https://cdn.fivex.sh/api/v1/upload", {
method: "POST",
headers: { Authorization: `Bearer ${KEY}`, "Idempotency-Key": `upload-${name}` },
body: form,
});
const result = await response.json();
if (!result.ok) throw new Error(`${response.status} ${result.message}`);
return result.url;
}
exports("uploadToCdn", uploadToCdn);
A API aceita chamadas de qualquer origem (CORS liberado para Authorization, Content-Type e Idempotency-Key), então uma página NUI pode enviar direto. Lembre: a chave fica visível no cliente.
// Na NUI: envia um canvas como WebP
async function sendCanvas(canvas: HTMLCanvasElement, key: string) {
const blob: Blob = await new Promise((resolve) => canvas.toBlob((b) => resolve(b!), "image/webp", 0.9));
const form = new FormData();
form.append("file", blob, `foto-${Date.now()}.webp`);
const response = await fetch("https://cdn.fivex.sh/api/v1/upload", {
method: "POST",
headers: { Authorization: `Bearer ${key}` },
body: form,
});
const result = await response.json();
if (!result.ok) throw new Error(result.message);
return result.url as string;
}
Posso enviar para outra pasta com a mesma chave? Não. A pasta é da chave. Crie uma chave por pasta (ou por script).
Posso enviar em base64?
Não. Converta para bytes e envie como multipart/form-data no campo file.
O link do arquivo muda se eu renomear o arquivo ou a pasta no painel? Sim, o link segue o caminho atual. Se você mudar o Endereço da CDN, os links antigos param de responder: troque nos scripts.
Revoguei a chave. Os arquivos somem? Não. Os arquivos já enviados continuam. Só os envios novos com aquela chave são recusados.