Start with four steps. Sign up for a free account, copy the API key, POST a file to the store endpoint, and use the CDN URL that comes back. Every transformation after that is a change to the URL. We ran the whole path below with real requests and left in what each one returned.
If you have not used us before, Filestack takes files off your hands, stores them, processes them on request, and serves them from a CDN. The rest of this page is that sentence turned into working calls.
Key takeaways
- A Filestack API key identifies an application and belongs in client-side upload code.
- One POST to the File API stores a file and returns a permanent handle.
- A stored handle becomes a live CDN URL as soon as the upload response returns.
- Image transformations are URL path segments placed before the file handle.
- A 403 usually identifies a task available on a higher plan, while a 400 often points to syntax.
Get your API key
Create a free account. The API key appears in the Developer Portal as soon as the first application is created, and it looks like AqIRTumTX7mHJiAGWmDUWz. That is the whole setup step. There is no SDK to install yet and no server to stand up.
The key travels in the URL, in the open, and it is meant to. It identifies the application, while the application secret stays on your server and out of client code.
Your first upload and the handle that comes back
The File API takes one HTTP request. If you have ever built an upload endpoint by hand, or wired up an api gateway file upload path just to get bytes into S3, this is the part that goes away.
Send the bytes directly:
curl -X POST \
--data-binary @lighthouse.jpg \
--header "Content-Type: image/jpeg" \
"https://www.filestackapi.com/api/store/S3?key=YOUR_API_KEY&filename=lighthouse.jpg"
Or hand it a web address and let Filestack fetch it, which is the fastest way to upload a file using REST API calls when the file is already online:
curl -X POST \
-d url="https://example.com/lighthouse.jpg" \
"https://www.filestackapi.com/api/store/S3?key=YOUR_API_KEY"
Running the first command with a 1024 by 1536 photograph returned this:
{
"url": "https://cdn.filestackcontent.com/T5T2GRrxSjeNBbsIMaA8",
"size": 319136,
"type": "image/jpeg",
"filename": "lighthouse.jpg"
}
That URL is live right now, and it is the file:
The last segment, T5T2GRrxSjeNBbsIMaA8, is the file handle. It is the only thing you need to keep. Store it next to the record it belongs to in your own database and you can rebuild every URL for that file from it, forever.
Your first transformation, one URL change
Transformations are path segments, dropped in front of your handle. The handle identifies the application, so no API key goes in a delivery URL:
https://cdn.filestackcontent.com/TASK/HANDLE
The uploaded lighthouse photograph was already a CDN asset. Add resize=width:400 and the 319,136 byte original comes back as 69,512 bytes in 0.57 seconds, with nothing stored, nothing pre-generated, and no build step.
https://cdn.filestackcontent.com/resize=width:400/T5T2GRrxSjeNBbsIMaA8
Crop it instead and you get a different file from the same handle:
https://cdn.filestackcontent.com/crop=dim:[200,380,700,700]/resize=width:400/T5T2GRrxSjeNBbsIMaA8
Two tasks ran there, left to right, in one request. Keep going and you can round the corners and drop a border on it without touching the original file:
https://cdn.filestackcontent.com/border=width:10,color:white/rounded_corners=radius:30/resize=width:400/T5T2GRrxSjeNBbsIMaA8
Format is a task too. Asking for WebP at full size returned 322,232 bytes against the 319,136 byte JPEG, which is to say it came back very slightly larger, because the source was already compressed. Chaining the resize first is what actually moves the number, down to 54,984 bytes. Deciding when to convert to webp rather than serve the original is its own question, and the format comparison is already written up.
Watermarking, pixelation, and collages use the same URL structure, with each task added as a segment. Free-plan facial detection tasks such as blur faces follow that structure too. This is the part of the product that does the most work for the least code, and the full set of operations is covered in the image editing api guide. Every task and its parameters are listed in the processing API reference, which is the page to keep open while you experiment.
Where the file lives now
Nowhere you have to configure. The moment the upload response came back, that CDN URL was live and public.
You can confirm what the API thinks it is holding:
https://cdn.filestackcontent.com/metadata/T5T2GRrxSjeNBbsIMaA8
which returned:
{
"filename": "lighthouse.jpg",
"mimetype": "image/jpeg",
"size": 319136,
"uploaded": 1785470987436.446,
"writeable": true
}
The imagesize task on the same handle returns {"height":1536,"width":1024}, which is the source of truth for what you are resizing down from. Cached copies live for 30 days by default and you can set your own window with cache=expiry:3600, which returned the original 319,136 bytes in 0.40 seconds. How the edge nodes and cache windows actually behave is covered in the file delivery walkthrough.
What broke, and how to tell which thing broke
Four failures account for nearly all of the first hour.
A 403 on a transformation. The key is fine and the handle is fine. That task runs on the higher plans, and it will be one of the AI-backed ones such as OCR, tagging, captioning or video conversion. Document work is where developers meet this first, so if you came looking for a pdf ocr api or a receipt ocr api, the pricing page shows which plan carries it.
A 400 with brackets in the URL. Tasks that take a list, such as crop=dim:[200,380,700,700], need percent-encoded square brackets when sent from curl. Browsers do it for you and curl does not:
curl "https://cdn.filestackcontent.com/crop=dim:%5B200,380,700,700%5D/T5T2GRrxSjeNBbsIMaA8"
A response that is byte-identical to your input. Some tasks are accepted and quietly do nothing, usually because there was nothing for them to act on. The no-metadata stripper on a file with no metadata is the clearest example. A 200 is not proof that something happened, so compare sizes.
Everything else is usually the handle.
The next thing to try
Three directions, all reachable from what you already have.
Give users an upload UI. The File Picker mounts in the browser and brings Google Drive, OneDrive, Box, Instagram, webcam capture, and direct URL sources with it. None of that needs backend work.
Wire the store call into your framework. It is one POST, so it drops into whatever you already run. A fast api upload file route, a rails api file upload action, an asp net core api file upload controller, or an angular upload file to api service makes the same store request shown in this article.
Try the operations nobody covers yet. pdfconvert turns a document into a formatted PDF, urlscreenshot renders any web page to an image with no upload at all, and zip bundles several handles into one archive.
You now have a stored file, a permanent handle and a transformed URL, which is every moving part of the API in about ten minutes. Everything after this is more task names in the same place.
Joshua is a web developer with over 4 years of experience building responsive, high-performance websites and web applications. Currently working as an AI Automation Specialist, he combines modern web development with automation to create efficient, scalable digital solutions. He shares practical insights on WordPress, web development, and emerging technologies.
Read More →