Uploading Files

Upload your files to Luw.ai (by Luvi Technologies) servers.

File uploads use a two-step process:

  1. Call /upload endpoint to get a signed URL

  2. Upload file directly to the signed URL

Luw.ai uses a two-step upload process that enables direct-to-CDN uploads for maximum performance. Instead of routing files through our servers, clients get a signed URL and upload directly to our CDN buckets, significantly improving upload speeds and reducing server load.

Step 1: Get Signed Url and Final Url for Upload

POST /v2/upload

Parameters

Name
Type
Description

filename

file

Required

File name of the file to allocate signed_url and final_url .

pid

integer

Optional

Persona ID to associate with the upload

Curl Example

# 1. Get signed URL
curl -X POST https://api.luw.ai/v2/upload \
  -H "Authorization: Bearer LUW_API_TOKEN" \
  -F "filename=image.jpg" \
  -F "pid=123"

Response Example

{
  "status": true,
  "signed_url": "https://storage.luw.ai/signed-url...",
  "final_url": "https://cdn.luw.ai/luwai/123/image.jpg"
}

The final_url value is the url of the file you've uploaded. After your upload, the url is ready instantly.

Step 2: Use Signed Url to Upload

After you run upload endpoint, you will get signed_url parameter to upload file directly from client to our servers. You can directly make PUT request with signed_url to upload your file. And when your upload finish, you can use the final_url comes from /upload endpoint.

# 2. Upload file
curl -X PUT "<signed_url>" \
  -H "Content-Type: image/jpeg" \
  -H "Cache-Control: max-age=315360000" \
  -H "Expires: Sun, 19 Jul 2030 18:06:32 GMT" \
  --data-binary "@image.jpg"

After successful uploads, you can check response code: 200

Full working HTML - Vanilla JavaScript example (try live demo here):

<!DOCTYPE html>
<html>
<head>
    <title>Luw.ai Upload</title>
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
</head>
<body>
    <input type="text" id="token" placeholder="Your API Token">
    <input type="file" id="file">
    <input type="text" id="pid" placeholder="Persona ID (optional)">
    <button onclick="upload()">Upload</button>
    <div id="progress"></div>
    <div id="result"></div>

    <script>
        async function upload() {
            const fileInput = document.getElementById('file');
            const token = document.getElementById('token').value;
            const pid = document.getElementById('pid').value;
            const progress = document.getElementById('progress');
            const result = document.getElementById('result');

            try {
                // Step 1: Get signed URL by sending filename
                const form = new FormData();
                form.append('filename', fileInput.files[0].name);  // Send filename only
                if (pid) form.append('pid', pid);

                const {data} = await axios.post('https://api.luw.ai/v2/upload', form, {
                    headers: {'Authorization': `Bearer ${token}`}
                });

                progress.textContent = 'Got signed URL, starting upload...';

                // Step 2: Upload actual file to signed URL
                await axios.put(data.signed_url, fileInput.files[0], {
                    headers: {
                        'Content-Type': fileInput.files[0].type,
                        'Cache-Control': 'max-age=315360000'
                    },
                    onUploadProgress: (e) => progress.textContent = `${Math.round(e.loaded/e.total * 100)}%`
                });

                result.innerHTML = `
                    Upload complete!<br>
                    File will be available at: <a href="${data.final_url}">${data.final_url}</a>
                `;
            } catch (err) {
                result.textContent = `Error: ${err.message}`;
            }
        }
    </script>
</body>
</html>

Supported File Types

  • jpg

  • svg

  • mp4

  • tif/tiff

  • png

  • jpeg

  • webp

  • gif

  • glb

  • gltf

  • fbx

Temporary Uploads vs Permanent Uploads

Please use x12tmp- prefix for file names for temporary uploads, for example: x12tmp-filename.jpg. With this prefix, we will keep your files 12 hours on our servers and after it's delete automatically.

If you don't add prefix, we will save it till your persona deleted. If you don't add Persona ID with pid parameter to your upload, we automatically add file to your first persona.

So, for long-time storage operations, please provide pid value, without any prefixes.

Last updated