NoCloud uses a two-step upload process:
- Get a signed URL from the Generate Signed URL endpoint
- Upload the file directly to the signed URL using a PUT request
This approach allows for efficient, direct-to-storage uploads without proxying through your backend.
Complete Upload Example
# Step 1: Get signed URL
SIGNED_URL_RESPONSE=$(curl -s -X GET \
"https://api.nonefivem.com/cloud/storage/signed-url?contentType=image/png&size=1048576" \
-H "Authorization: Bearer your-api-key")
# Extract the signed URL
UPLOAD_URL=$(echo $SIGNED_URL_RESPONSE | jq -r '.url')
# Step 2: Upload file to signed URL
curl -X PUT "$UPLOAD_URL" \
-H "Content-Type: image/png" \
--data-binary @./screenshot.png
Attach custom metadata to track file ownership or categorization:
const params = new URLSearchParams({
contentType: "image/png",
size: file.size.toString(),
// Metadata as JSON string
metadata: JSON.stringify({
oderId: "order_123",
visitorId: 456,
isPublic: true
})
});
const response = await fetch(
`https://api.nonefivem.com/cloud/storage/signed-url?${params}`,
{
headers: { Authorization: "Bearer your-api-key" }
}
);
Metadata constraints: - Maximum 10 keys - Key names: alphanumeric,
underscores, hyphens only (max 128 chars) - Values: string (max 512 chars),
number, or boolean - Total metadata size: max 2KB
Upload with Progress Tracking
For larger files, you may want to track upload progress:
async function uploadWithProgress(file, onProgress) {
// Get signed URL first...
const { url, mediaId, mediaUrl } = await getSignedUrl(file);
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.upload.addEventListener("progress", (event) => {
if (event.lengthComputable) {
const percentComplete = (event.loaded / event.total) * 100;
onProgress(percentComplete);
}
});
xhr.addEventListener("load", () => {
if (xhr.status >= 200 && xhr.status < 300) {
resolve({ mediaId, mediaUrl });
} else {
reject(new Error(`Upload failed with status ${xhr.status}`));
}
});
xhr.addEventListener("error", () => reject(new Error("Upload failed")));
xhr.open("PUT", url);
xhr.setRequestHeader("Content-Type", file.type);
xhr.send(file);
});
}
// Usage
await uploadWithProgress(file, (progress) => {
console.log(`Upload progress: ${progress.toFixed(1)}%`);
});
Signed URLs expire after 15 minutes. Generate a new URL if the upload doesn’t
complete in time.