Discord Bot File Storage

Discord File Hosting for Bots: Permanent Image and Attachment URLs

Discord file hosting for bots: permanent CDN URLs for images, embeds, and attachments.

Discord bot file storage

Discord's attachment CDN was built to render chat messages, not to back a bot's data layer. Since 2024, cdn.discordapp.com links carry signed expiry parameters (ex, is, hm), so an attachment URL you saved in a database eventually returns a 404 once the signature times out. If your bot persists user avatars, generated images, moderation evidence, or ticket transcripts by stashing the raw Discord URL, those references rot. Re-hosting the bytes on storage you control fixes that permanently.

Two jobs share one upload path here. The first is Discord file hosting for assets your bot emits: renders, charts, transcripts, generated audio. The second is the moment Discord refuses the file outright. A single message is capped at 10 MB on the free tier and up to 100 MB on a boosted server, so a bot that can't upload images past that ceiling should stop fighting the limit and post a link instead.

A public cdn22.net URL resolves straight to the bytes, Discord unfurls it in the channel, and the user downloads from the nearest edge rather than through Discord's transfer path.

Re-hosting an incoming attachment is the same three calls. Fetch the bytes from message.attachments.first().url while the signature is still valid, push them through the upload, and persist the returned CDN URL instead of Discord's. That URL carries no expiry token, so it can sit in your database for years and still resolve.

js
client.on('messageCreate', async (msg) => {
  const att = msg.attachments.first();
  if (!att) return;
  const bytes = Buffer.from(await (await fetch(att.url)).arrayBuffer());
  // 1) POST /v1/files/{folderId} -> { urls: [{ url, id }] }
  const meta = await api.post(`/v1/files/${FOLDER}`, {
    filesMetadata: [{ name: att.name }],
  });
  const { url, id } = meta.urls[0];
  // 2) PUT the bytes straight to the presigned URL
  await fetch(url, { method: 'PUT', body: bytes });
  // 3) confirm to finalize
  await api.post('/v1/files/confirm-upload', { ids: [id] });
  msg.reply(`Stored permanently: ${cdnUrlFor(id)}`);
});

Nothing about this is Node-specific. The same three calls run from a shell, so a discord.py bot, a Go worker, or a deploy script can host images for a Discord bot with curl and no SDK. Read the key from the environment; never paste it into source or a slash-command handler.

bash
# 1) reserve a slot -> presigned PUT url + file id
META=$(curl -s -X POST "https://api.cdn22.net/v1/files/$FOLDER_ID" \
  -H "Authorization: $CDN22_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"filesMetadata":[{"name":"rank-card.png"}]}')
PUT_URL=$(echo "$META" | jq -r '.urls[0].url')
FILE_ID=$(echo "$META" | jq -r '.urls[0].id')

# 2) upload the bytes, 3) confirm
curl -s -X PUT --upload-file rank-card.png "$PUT_URL"
curl -s -X POST https://api.cdn22.net/v1/files/confirm-upload \
  -H "Authorization: $CDN22_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"ids\":[\"$FILE_ID\"]}"

The Authorization header takes your raw API key with no Bearer prefix, and every endpoint is browsable in the hosted Swagger UI at api.cdn22.net/api-docs. The curl walkthrough covers the same three calls line by line, and the image upload API covers the image-specific path.

Embeds want a public URL. Set image.url or thumbnail.url on the embed to a permanent cdn22.net link and Discord fetches it through its own proxy, which means the URL has to still work whenever Discord refetches it. That rules out short-lived signed links in embed fields: a signed URL is the right tool for a moderation export or a paid download your backend hands to one person, not for artwork the whole channel renders.

Mark a file private at upload and no public URL is minted at all; your bot calls GET /v1/files/signed/{id} for a link that expires in ten minutes by default. Secure file sharing goes deeper on the signed-link mechanics, and permanent file links on the public side.

There is no format gate. PNG, JPEG, WebP, GIF, SVG, MP4, WAV, JSON, and log files all upload through the same endpoints and come back on a CDN URL, so image storage for rank cards and a 300 MB archived render use one bucket of credits rather than two vendors. Delivery runs on a global edge network with no distribution to configure, which is the part covered on file storage with CDN.

Give each bot its own project and API key. Revoking a leaked key then takes one bot offline instead of your whole fleet, and usage reads per project when you want to know which bot is actually spending. Billing is prepaid credits: storage, delivery, and requests draw from one balance, so a channel that goes viral spends credits you can watch rather than producing an invoice three weeks later. Create a project and upload one bot asset to see the URL you would put in an embed.

Bot asset workflow

From Bot Asset to Embed URL

One upload path covers a generated render, a re-hosted Discord attachment, and a private export your bot hands to a single moderator.

  1. Create a project and API key

    One project per bot, one key per project, stored in the bot's environment. Revoking a leaked key then only affects that bot. Start in the app.

  2. Upload from the bot or the dashboard

    Three calls: POST /v1/files/{folderId} for a presigned PUT target and id, PUT the bytes, POST /v1/files/confirm-upload. Drag and drop works too for artwork you ship with the bot. The upload a file guide walks the first one.

  3. Put the CDN URL in the embed

    A public file returns a direct link the embed's image field can use, so Discord renders it from the nearest edge. The same URL works in a slash-command reply, a webhook payload, or your dashboard. See permanent file links.

  4. Keep private assets signed

    Moderation evidence and ticket exports upload private, so no public URL exists. Call GET /v1/files/signed/{id} for a link that expires in ten minutes, and mint a fresh one per request instead of storing it. More on secure file sharing.

Before you ship the bot

  • Read the API key from an environment variable, never from source or a command handler.
  • Re-host an incoming attachment while its signature is still valid, then store your URL.
  • Use public URLs in embed image fields; Discord refetches them and a signed link will 404.
  • Uploading needs a cdn22.net account; the people clicking your links never need one.
  • Credits cover storage, delivery, and requests from one balance, so watch a viral channel's spend.

Benefits With No Complexity

Global CDN delivery

Your files are served from 450+ edge locations worldwide.

Edge-cached worldwide

Files are cached close to your users for fast delivery.

Signed-URL security

Private files stay protected with time-limited access.

What You Get

Unlimited files

Upload as many files as you need.

Unlimited storage

There is no storage limit.

Public + Private storage

Private files are fully secured.

CDN ready links

Upload directly to 450+ edge locations worldwide.

Prepaid credits

No subscription. Pay only for the storage and bandwidth you use.

More coming soon

We have plenty of features coming!

How cdn22.net Works

1. Upload

Create a project and upload your first file.

2. Copy

Copy the CDN link.

3. Use Anywhere

Paste and enjoy the blazing speed.

Why Developers Choose cdn22.net

A Better Way to Store & Deliver Files

Assets in your repoS3 or R2 aloneAd hoc image hostscdn22.net
Permanent URLs with no expiry signature
Upload at runtime with no redeploy
Global CDN delivery built in
Private files with signed URLs
No IAM policy, bucket policy, or CORS setup
Storage and delivery on one prepaid balance

Calculate Your Needs

Storage

0GB

Egress

0GB

CDN Bandwidth

0GB
Total: $0.000/month

Need storage, egress, and request fees broken out — and compared against AWS list price for the same bytes? Use the CDN & storage cost calculator.

Start Discord Bot Storage

  • Global CDN delivery
  • Edge-cached worldwide
  • Signed-URL security
  • Unlimited files
  • Unlimited storage
  • Public + Private storage
  • No subscription — prepaid credits keep spend predictable
Start Discord Bot Storage

Frequently Asked Questions

Why do Discord attachment URLs stop working?
Since 2024 Discord signs cdn.discordapp.com links with expiry parameters (ex, is, hm). Once the timestamp passes, the URL 404s, so any attachment link you saved in a database eventually breaks. Re-hosting the bytes on cdn22.net gives you an unsigned permanent CDN URL that does not expire.
How do I host images for a Discord bot?
Upload the image once through the three-call REST flow (POST /v1/files/{folderId} for a presigned PUT target and id, PUT the bytes, POST /v1/files/confirm-upload) and keep the CDN URL that comes back. Your bot then references that URL in embeds, replies, and webhooks instead of re-uploading the file on every message.
My Discord bot can't upload images. What now?
Discord caps a single message at 10 MB on the free tier and up to 100 MB on a boosted server, and the ceiling applies to your bot too. Rather than compressing until it fits, upload the image to cdn22.net and reply with the CDN link. Discord unfurls the link in the channel and the download comes from the edge, so file size stops being the constraint.
How do I move an incoming attachment into permanent storage?
Fetch the bytes from the attachment URL the moment your bot sees the message, while the signature is still valid. Then run the three-call upload and persist the returned CDN URL against whatever record referenced the attachment. Do it on receipt rather than in a nightly job, because the Discord signature expires in the meantime.
Can I use a cdn22.net URL in a Discord embed?
Yes, for public files. Set the embed's image.url or thumbnail.url to the permanent CDN URL and Discord fetches it through its media proxy. Use a public link rather than a signed one here: Discord refetches embed images later, and a short-lived signed URL will have expired by then.
Public URL or signed URL for bot assets?
Public for anything the channel is meant to see: rank cards, generated art, level-up graphics, documentation images. Private plus a signed URL for anything scoped to one person or one moderator, such as ticket transcripts, moderation evidence, or a data export. Both come from the same upload, selected with a flag at upload time.
What file types can a bot store?
There is no format gate. PNG, JPEG, WebP, GIF, and SVG for images; MP4 and WAV for media a bot generates; JSON, CSV, and plain logs for transcripts and exports. Everything goes through the same endpoints and comes back on a CDN URL, so one project holds a bot's whole asset set.
Can my bot serve files bigger than Discord's upload cap?
Your bot still cannot push past Discord's per-message limit, but it can reply with a cdn22.net URL of any size. The user clicks and downloads directly from the edge, which sidesteps Discord's transfer limits entirely.
Where should the API key live in a Discord bot?
In an environment variable, never in code or your repo, and never echoed back into a channel. Send it as the raw Authorization header on the metadata and confirm-upload calls, with no Bearer prefix. Use a separate project and key per bot so one revocation does not take down the rest of your fleet.
General Questions
Is there a subscription?
No. cdn22.net uses prepaid credits, so storage, bandwidth, and API usage are deducted from your balance as you go. The app explains the payment step before uploads are enabled — no monthly subscription and no per-user fees.
What is cdn22.net?
cdn22.net is a developer-first file platform that makes it simple to store, secure, and deliver files globally. It provides signed URLs, public/private access, and an API-first design so you can integrate file delivery into any app without the usual complexity.
How does billing work?
cdn22.net uses prepaid credits. As you use storage, bandwidth, and API requests, credits are deducted daily. When your balance runs low, we automatically recharge it using your saved card. If an auto-recharge doesn't go through, your files and links stay put — you simply update your payment method or top up manually to keep going. No monthly subscriptions — just simple usage-based pricing.
How secure is my data?
All files are encrypted at rest and in transit. You can use signed URLs for private files, control access with permissions, and rely on enterprise-grade infrastructure for data protection.

Related

cdn22.net
Copyright © 2026
All rights reserved
ContactGuidesGlossaryStatusSecurityLegal