Sign in with Google, then generate a key from your account page. It's shown once — copy it somewhere safe. Free tier only for now — pro/business are planned but not live yet.
| tier | free (only tier currently available) |
|---|---|
| requests | 20 per minute, 500 per day |
| max file size | 5MB per file (per entry too, if it's a zip) |
| zip total uncompressed size | 50MB across all entries |
| zip entry count | 2000 max per archive |
One endpoint, works the same everywhere — POST the raw file bytes as the request body, with your key in the Authorization header.
curl -X POST https://rawpx.pages.dev/api/v1/upload \ -H "Authorization: Bearer rk_your_key_here" \ -H "X-Filename: photo.png" \ -H "Content-Type: image/png" \ --data-binary @photo.png
Windows' built-in curl is actually an alias for Invoke-WebRequest, which uses different flags — use this instead:
Invoke-WebRequest -Method POST -Uri "https://rawpx.pages.dev/api/v1/upload" `
-Headers @{ "Authorization" = "Bearer rk_your_key_here"; "X-Filename" = "photo.png" } `
-ContentType "image/png" `
-InFile "C:\path\to\photo.png"
(Or install real curl.exe and use the macOS/Linux command above as-is — Windows ships it too, just call it as curl.exe to bypass the alias.)
Only call this from server-side code (Node, a backend route, a Cloudflare Worker of your own, etc). Never from client-side browser JS — anyone could read your key out of the page.
const fileBuffer = await fs.readFile("photo.png"); // or however you have the bytes
const res = await fetch("https://rawpx.pages.dev/api/v1/upload", {
method: "POST",
headers: {
"Authorization": "Bearer rk_your_key_here",
"X-Filename": "photo.png",
"Content-Type": "image/png",
},
body: fileBuffer,
});
const data = await res.json();
console.log(data.url);
import requests
with open("photo.png", "rb") as f:
res = requests.post(
"https://rawpx.pages.dev/api/v1/upload",
headers={
"Authorization": "Bearer rk_your_key_here",
"X-Filename": "photo.png",
"Content-Type": "image/png",
},
data=f.read(),
)
print(res.json()["url"])
{ "status": "uploaded", "url": "https://rawpx-files.pages.dev/f/<hash>.png", "delete_url": "..." }
If the exact file already exists (uploaded by anyone), you get "status": "exists" back instantly instead — no re-upload happens.
Same endpoint, same headers — just point it at a .zip. It gets unzipped server-side, every file inside is hashed and deduped individually, and you get an archive link back instead:
{ "status": "uploaded", "archive_url": "https://rawpx-files.pages.dev/archive/<hash>", "entry_count": 12, "new_files_uploaded": 9 }
There's no separate download API and no auth needed to download — that's the whole point of the raw links. Once you have a url from an upload response, it's just a normal public GET request, from anything: a browser, curl, an <img> tag, a CSS background, whatever.
curl -O https://rawpx-files.pages.dev/f/<hash>.png
Invoke-WebRequest -Uri "https://rawpx-files.pages.dev/f/<hash>.png" -OutFile "photo.png"
| 401 | missing, invalid, or revoked key |
|---|---|
| 413 | file over 5MB |
| 429 | rate limited — back off and retry after a bit |