curl Upload: File to Link, Three Commands
The curl Upload File to Link Flow: POST, PUT, Confirm
POST for a presigned URL, curl -X PUT the bytes, POST confirm. The link is a permanent CDN URL you can paste into Discord, Slack, a CI log, or a support ticket.
This is the curl upload file to link flow: POST the file's metadata to get a presigned URL, PUT the bytes to that URL, then POST to confirm. Three commands, and what comes back is a permanent CDN address you can paste anywhere. curl is the whole SDK here. Every command below is copy-paste. Swap in an API key from your API keys page and a folder id from the dashboard. The auth header is the raw key value, with no Bearer prefix.
Step 1 asks the API for somewhere to put the bytes.
# Step 1: request a presigned upload URL
curl -sf -X POST https://api.cdn22.net/v1/files/<FOLDER_ID> \
-H "Authorization: $CDN22_API_KEY" \
-H "Content-Type: application/json" \
-d '{"filesMetadata":[{"name":"report.pdf","size":248173,"type":"application/pdf"}]}'
# Response
# {
# "success": true,
# "urls": [
# { "url": "https://<bucket>.s3.<region>.amazonaws.com/...&X-Amz-Signature=...",
# "id": "1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed",
# "key": "<owner>/<folder>/report.pdf" }
# ]
# }Step 2 sends the file itself. This PUT goes to storage, not to the API, so it carries no Authorization header at all. The signature baked into the presigned URL is the authorization. Sending your API key here is the single most common way this flow breaks.
# Step 2: PUT the bytes to the presigned URL. No auth header, and quote the URL.
curl -sf --upload-file ./report.pdf \
-H "Content-Type: application/pdf" \
"https://<bucket>.s3.<region>.amazonaws.com/...&X-Amz-Signature=..."--upload-file is the command-line face of libcurl's CURLOPT_UPLOAD: it streams the file straight from disk and implies -X PUT, so you never need both. curl -X PUT --data-binary @report.pdf moves the same bytes but buffers the file first, so prefer --upload-file for anything large. Add -# for a progress bar, and --retry 3 --retry-connrefused so a dropped connection re-attempts the transfer instead of failing the whole pipeline.
Step 3 finalizes the file, and the CDN URL goes live.
# Step 3: confirm the upload with the id from step 1
curl -sf -X POST https://api.cdn22.net/v1/files/confirm-upload \
-H "Authorization: $CDN22_API_KEY" \
-H "Content-Type: application/json" \
-d '{"ids":["1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed"]}'
# A public file is now served from:
# https://cdn.cdn22.net/<owner>/<folder>/report.pdfTo stop copy-pasting ids by hand, capture step 1's response and pull the fields out with jq. That is a complete uploader in about ten lines. Drop it in your shell profile and upload report.pdf works on any machine that has curl and jq.
upload() {
resp=$(curl -sf -X POST https://api.cdn22.net/v1/files/<FOLDER_ID> \
-H "Authorization: $CDN22_API_KEY" -H "Content-Type: application/json" \
-d "$(jq -n --arg n "$(basename "$1")" \
--argjson s "$(wc -c < "$1" | tr -d ' ')" \
'{filesMetadata:[{name:$n,size:$s,type:"application/octet-stream"}]}')")
curl -sf --retry 3 --upload-file "$1" "$(jq -r '.urls[0].url' <<< "$resp")"
curl -sf -X POST https://api.cdn22.net/v1/files/confirm-upload \
-H "Authorization: $CDN22_API_KEY" -H "Content-Type: application/json" \
-d "$(jq -c '{ids:[.urls[0].id]}' <<< "$resp")"
}Because every call is plain HTTPS on port 443, the same commands run from a laptop, a cron job, a Docker image, GitHub Actions, or GitLab CI with no credentials file to distribute. Unlike aws s3 cp, the only secret is the one API key already in your environment. Keep -f on the two API calls so a non-2xx response sets a non-zero exit code your CI step can actually catch.
Which link you get depends on the folder the file landed in. A file in a public folder is served straight from the CDN at a permanent URL, so the address never changes and the bytes cache at the edge. A file in a private folder is not reachable that way; you ask the API for a time-limited download URL instead.
# Time-limited link for a private file. expiresIn is seconds; 3600 = one hour.
curl -sf -H "Authorization: $CDN22_API_KEY" \
"https://api.cdn22.net/v1/files/signed/<FILE_ID>?expiresIn=3600"
# {"success":true,"url":"https://...&X-Amz-Expires=3600","expiresIn":3600}expiresIn accepts 60 to 604800 seconds (seven days is the presigning ceiling); omit it and you get the 600-second default. If you would rather hand out one stable address for a private file, POST /v1/p with {"fileId":"..."} returns a permanent link that redirects to a freshly signed URL on each visit, so the address you shared keeps working without you reissuing it.
Be precise about what expires there: expiresIn bounds how long a download URL stays valid, not how long the file lives. To expire the file itself, add ttlSeconds next to filesMetadata in step 1 (or an absolute expiresAt in ISO 8601). Once the TTL passes, the API stops issuing signed URLs for that file and a sweep removes the object and its metadata within the hour. Omit both fields and nothing changes: the file stays until you remove it with DELETE /v1/files/<id>.
# Step 1 with a one-hour file TTL. 60s minimum, 365 days maximum.
curl -sf -X POST https://api.cdn22.net/v1/files/<FOLDER_ID> \
-H "Authorization: $CDN22_API_KEY" \
-H "Content-Type: application/json" \
-d '{"filesMetadata":[{"name":"proof.pdf","size":248173,"type":"application/pdf"}],"ttlSeconds":3600}'A throwaway temp-file API is the other option here. Disposable one-command hosts win when you want zero setup and no account: no key, one curl, and it deletes itself on a schedule you do not set. cdn22.net is the better fit when the link has to keep working. A build artifact linked from release notes, an image a bot posts into a channel, a video a client opens next quarter, a PDF attached to a support ticket someone reopens: every one of those breaks the day the host expires the URL.
Here you get a CDN-backed address, folders you can list and re-fetch through the API, and deletion on your schedule instead of theirs. See temporary file hosting for the expiring-link side and the transfer.sh alternative for the self-hosted comparison.
Sharing the result is just pasting the URL, because that is all it is. Discord and Slack render a direct image or video link inline when the Content-Type is right, which is the usual reason to push a file to a CDN before posting instead of attaching it. The same three commands run server-side in a bot: Discord bot file storage and Slack file storage cover that setup.
Need the same flow from somewhere other than a shell? The full upload-a-file guide walks the identical three calls from curl, the browser, and Node.js. The cloud file storage API covers the wider endpoint set, the file upload API documents the upload endpoints on their own, file to link covers the same job from the dashboard when you are not in a terminal, file upload CLI covers shell ergonomics, API-key auth covers key handling and rotation, and Node.js and Python port the same three calls into a runtime.
Pricing is prepaid credits with no subscription: you pay for the storage and bandwidth you actually use, so a script pushing a few build artifacts costs a few cents. Create an API key and run the commands above against your own folder.
Benefits With No Complexity
Global CDN delivery
Edge-cached worldwide
Signed-URL security
What You Get
Unlimited files
Unlimited storage
Public + Private storage
CDN ready links
Prepaid credits
More coming soon
How cdn22.net Works
1. Upload
2. Copy
3. Use Anywhere
Why Developers Choose cdn22.net
A Better Way to Store & Deliver Files
| Throwaway temp-file API | aws s3 cp | scp / rsync | cdn22.net | |
|---|---|---|---|---|
| Upload with one command and no account | ||||
| Link still resolves months later | ||||
| Global CDN delivery on the file URL | ||||
| Single API key, no credentials file | ||||
| List and re-fetch past uploads over the API | ||||
| Expiring signed URLs for private files |
Calculate Your Needs
Storage
Egress
CDN Bandwidth
Need storage, egress, and request fees broken out — and compared against AWS list price for the same bytes? Use the CDN & storage cost calculator.
Create an API Key and Upload with curl
- Global CDN delivery
- Edge-cached worldwide
- Signed-URL security
- Unlimited files
- Unlimited storage
- Public + Private storage
- No subscription — prepaid credits keep spend predictable