Upload a File With curl and Get a CDN URL

The 3-Command curl Upload: POST, PUT, Confirm

POST for a presigned URL, curl -X PUT the bytes, POST confirm — three copy-paste commands and your file has a permanent CDN link.

curl is the whole SDK here. Uploading a local file to cdn22.net and getting a permanent CDN URL back takes three HTTP calls in a fixed order: POST the file's metadata to get a presigned URL, PUT the bytes to that URL, then POST to confirm. 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.

bash
# 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 already baked into the presigned URL is the authorization. Sending your API key here is the single most common way this flow breaks.

bash
# 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.

bash
# 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.pdf

To 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.

bash
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.

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, 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

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

aws s3 cpscp / rsyncFTP clientcdn22.net
Three plain HTTP calls, no SDK
Single API key, no credentials file
All traffic over HTTPS/443 (proxy-friendly)
Returns a shareable delivery URL
Built into Linux/macOS/Windows 10+

Calculate Your Needs

Storage

0GB

Egress

0GB

CDN Bandwidth

0GB
Total: $0.000/month

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
Create Your API Key

Frequently Asked Questions

What exactly are the three curl commands?
POST /v1/files/{folderId} with file metadata returns {success, urls:[{url,id}]}; curl --upload-file to that presigned url (no auth header — the URL signature is the auth); POST /v1/files/confirm-upload with {"ids":["ID"]} to finalize. The confirmed file is then served from a CDN URL.
How do I fix curl: (26) couldn't open file?
Exit code 26 means curl could not read the local path you passed. Check the path is correct relative to your current directory, that the file is readable, that a name containing spaces is quoted, and that you used --upload-file ./report.pdf (a plain path) or --data-binary @report.pdf (with the leading @). Omitting the @ makes curl send the literal filename as the body instead of the file.
Why does the presigned PUT return 403 SignatureDoesNotMatch?
Almost always because an Authorization header was sent on step 2. The presigned URL authorizes itself, so adding your API key breaks it. Also quote the URL in your shell so & does not split the command, and re-run step 1 if the URL has expired — presigned URLs are short-lived.
What Content-Type should curl send?
The two API calls are application/json. On the step-2 PUT, send the file's real MIME type (for example application/pdf or image/png) and keep it consistent with the type you declared in step 1 — a wrong Content-Type is what makes a browser download an image instead of rendering it.
How do I avoid copy-pasting the URL and ID?
Capture step 1's response in a variable and pull .urls[0].url and .urls[0].id with jq -r, then reference those vars in steps 2 and 3. Wrapped in a shell function, the whole uploader is about ten lines.
How do I authenticate?
Pass your API key as the raw Authorization header value — no Bearer prefix — on the POST calls. The PUT to the presigned URL needs no header. Create and rotate keys from the API keys page in your dashboard.
Can I show a progress bar or retry large uploads?
Yes. Add -# to the PUT step for a progress bar, and --retry 3 --retry-connrefused so a dropped connection re-attempts the byte transfer. --upload-file streams from disk, so file size is not bounded by memory.
When should I read the full upload guide instead?
Use this page when curl is the whole integration. Read /guides/upload-file when you need the identical three calls from a browser file input or a Node.js backend, or want the full response fields documented.
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
ContactGuidesGlossaryStatusLegal