How to Upload and Download Files With a REST API
Published 2026-10-07 05:07:05.720699 by Carsten Blum
Your application needs somewhere to put files.
Maybe customers upload documents, your application generates PDFs, an ERP produces exports, or another system needs to retrieve files for processing. Whatever the use case, the basic requirement is often the same:
Application → Upload File → Cloud Storage → Download File
You do not necessarily need to build a storage platform around that requirement.
With ftpGrid, applications can upload, list, download, move and delete files through a REST API while ftpGrid provides the managed cloud file storage behind it. In this article, we'll keep it practical: authenticate, upload a file and download it again.
View larger infographic (AI generated image)
The architecture is deliberately simple
For an application using ftpGrid as file storage, the primary architecture can be as simple as:
┌──────────────────────┐
│ Your Application │
└──────────┬───────────┘
│
│ HTTPS / REST API
▼
┌──────────────────────┐
│ ftpGrid │
│ Cloud File Storage │
└──────────────────────┘Your application owns the business logic. ftpGrid handles the file storage.
That makes the model useful for:
Customer documents
Generated PDFs
Reports
Images
Application exports
Integration files
Data extracts
Backup files
Files exchanged with external systems
Let's put a file into storage.
Step 1: Authenticate your application
The ftpGrid Storage API uses bearer tokens for authentication. Your API credentials consist of an Association Key, Access Key and Secret Key. Your backend uses these credentials to obtain a temporary JWT access token.
The authentication payload looks like this:
{
"AssociationKey": "YOUR_ASSOCIATION_KEY",
"AccessKey": "YOUR_ACCESS_KEY",
"SecretKey": "YOUR_SECRET_KEY"
}After successful authentication, the response contains a token:
{
"token": "eyJhbGc..."
}Subsequent Storage API requests include the token in the standard HTTP authorization header:
Authorization: Bearer YOUR_TOKENKeep the long-lived API credentials on your backend. They should not be embedded in frontend JavaScript, mobile applications or other software distributed to end users.
The resulting flow is:
API credentials → JWT token → Storage API
Step 2: Upload a file with curl
Files are uploaded using multipart/form-data.
A simple upload can be performed with curl:
curl -X POST "https://webN.ftpgrid.com/api/upload" \
-H "Authorization: Bearer YOUR_TOKEN" \
-F "file=@./invoice.pdf"Replace webN.ftpgrid.com with the storage endpoint assigned to your ftpGrid account.
The important part is the file itself:
file=@./invoice.pdfYour application sends the file over HTTPS and ftpGrid stores it in the managed file environment.
Conceptually:
invoice.pdf
│
▼
REST API
│
▼
ftpGrid StorageThere is no mounted filesystem or storage server for your application to operate.
Step 3: Organize application files
Real applications rarely put every file in one directory.
A SaaS application might organize files by customer:
/customers/1842/
/customers/1842/invoices/
/customers/1842/reports/
/customers/3921/invoices/An integration platform might instead use:
/incoming/
/processing/
/processed/
/exports/The important design decision is to choose a directory structure based on your application's domain rather than the underlying storage technology.
For example:
/customers/1842/invoices/invoice-2026-1042.pdfYour application knows that customer 1842 owns the invoice. ftpGrid simply stores the file. This separation keeps storage infrastructure out of your application logic.
Step 4: List files before downloading
Applications often need to discover what is currently stored.
The Storage API can list files within a directory.
For example:
curl -X POST "https://webN.ftpgrid.com/api/list/files" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"Params":"/customers/1842/invoices/"}'A response can contain information such as:
[
{
"lastModified": 1778904174199,
"name": "invoice-2026-1042.pdf",
"size": 184642,
"type": "file"
}
]Your application can use file listings to:
Display available documents
Discover incoming integration files
Verify generated exports
Build administrative file views
Check whether processing output exists
Synchronize application state
The REST API provides the storage operations. Your application determines what the files mean.
Step 5: Download the file
A stored file can be downloaded through the API using its path.
For example:
curl -X POST \
"https://webN.ftpgrid.com/api/download/single?path=/customers/1842/invoices/invoice-2026-1042.pdf" \
-H "Authorization: Bearer YOUR_TOKEN" \
--output invoice-2026-1042.pdfThe response is written directly to:
invoice-2026-1042.pdfThe complete workflow is now:
Application
│
│ Upload
▼
ftpGrid Storage
│
│ Download
▼
ApplicationFor many business applications, that is the fundamental storage requirement.
Upload and download files from Go
The same operations can naturally be performed from application code.
Here is a compact Go example for downloading a file once your application has obtained a JWT token:
func downloadFile(token, filePath, outputPath string) error {
url := "https://webN.ftpgrid.com/api/download/single?path=" + url.QueryEscape(filePath)
req, err := http.NewRequest(http.MethodPost, url, nil)
if err != nil {
return err
}
req.Header.Set("Authorization", "Bearer "+token)
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("download failed: %s", resp.Status)
}
out, err := os.Create(outputPath)
if err != nil {
return err
}
defer out.Close()
_, err = io.Copy(out, resp.Body)
return err
}The application does not need to know how the underlying storage infrastructure is implemented.
It only needs:
The storage endpoint
An access token
The file path
That is exactly the abstraction we want from application storage.
Upload files from Go
Uploading uses a standard multipart HTTP request.
A simplified implementation looks like this:
func uploadFile(token, filePath string) error {
file, err := os.Open(filePath)
if err != nil {
return err
}
defer file.Close()
var body bytes.Buffer
writer := multipart.NewWriter(&body)
part, err := writer.CreateFormFile("file", filepath.Base(filePath))
if err != nil {
return err
}
if _, err = io.Copy(part, file); err != nil {
return err
}
writer.Close()
req, err := http.NewRequest(http.MethodPost, "https://webN.ftpgrid.com/api/upload", &body)
if err != nil {
return err
}
req.Header.Set("Authorization", "Bearer "+token)
req.Header.Set("Content-Type", writer.FormDataContentType())
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
return fmt.Errorf("upload failed: %s", resp.Status)
}
return nil
}In a production application, you would typically wrap authentication, upload, download and other storage operations in a small storage client rather than spreading HTTP calls throughout the application.
Your business code can then work with operations such as:
storage.Upload(...)
storage.Download(...)
storage.List(...)
storage.Delete(...)The rest of the application does not need to care how those operations are implemented.
Keep authorization in your application
Storage authentication and application authorization are two different things.
Suppose customer 1842 requests:
/customers/1842/invoices/invoice-2026-1042.pdfYour application should first determine whether the logged-in user is actually allowed to access that invoice.
Only then should the backend retrieve the file.
A typical architecture is therefore:
User
│
▼
Your Application
│
├─ Authenticate user
├─ Check business permissions
│
▼
ftpGrid REST API
│
▼
FileDo not expose your ftpGrid API credentials directly to the user simply because the user needs access to a stored file. Your application owns customer authorization. ftpGrid provides the managed storage behind it.
REST API on one side, FTP or SFTP on the other
Application storage becomes particularly useful when files do not exclusively come from your own software.
Imagine your application processes files from a business partner.
Your application prefers REST:
Application → REST API → ftpGridBut the partner already has an established SFTP integration:
Partner → SFTP → ftpGridThose workflows can meet in the same managed file environment:
Application ── REST API ──┐
│
Partner ───── SFTP ───────┼──→ ftpGrid Storage
│
Legacy ERP ── FTP ────────┘There is no business benefit in forcing every external system to implement your preferred API. Modern applications can use REST while existing systems continue using FTP or SFTP.
Let your application know when a file arrives
If another system uploads files, your application needs a way to know when something has changed.
Polling works:
Application → List files → Wait → List files → Wait...But event-driven integration is often cleaner:
Partner
│
│ SFTP
▼
ftpGrid
│
│ Webhook
▼
Your ApplicationA supplier can upload through SFTP, for example, and ftpGrid can trigger a webhook so your application knows that it should begin processing. This combines traditional business file transfer with modern application integration. Learn more about ftpGrid webhooks.
You need file storage — not another infrastructure project
Uploading and downloading files is not a complicated application requirement. The infrastructure surrounding file storage can be.
If your requirement is:
“My application needs somewhere reliable to put files.”
then a focused architecture can be enough:
Application → REST API → Managed Cloud Storage
ftpGrid provides that storage while also supporting the wider file workflows businesses tend to accumulate over time. Your application can use REST. Your ERP can use FTP. Your partners can use SFTP. Webhooks can notify your application when files arrive. You can therefore start with the simplest requirement — upload and download a file — without designing an entire storage platform around it.
For a broader overview of building file workflows with the API, see the REST API tutorial. Store the file. Get it back when you need it. Let the storage platform handle the rest.
ftpGrid menu