Let your users upload images via QR code
Your desktop application needs a photo, but your users' best camera is their phone. When you need an image (or a file you can display a QR code, and we’ll send you the image when your user uploads from their mobile device
Get URL
Show Link / QR code
User scans & uploads
Webhook callback
Get Signed Upload URL
Call our GET upload-url API endpoint from your server. Pass a key only you know that identifies your project and a callbackUrl where image URLs will be delivered once the user uploads. You should
not fetch this client-side or anyone can have your token and upload/spam your app
//Never call this client-side
const res = await fetch('https://uploader.reyes.tech/api/upload-url', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
key: 'some-key-unique-to-my-project',// <- this can be a strong key you make up for your project
callbackUrl: 'https://your-server.com/webhook?param1=value',// <- we'll POST the uploaded data here
}),
});
const { uploadUrl, expiresAt, qr, token } = await res.json();
// you should store the token on your side and not expose it.
// you can display a link to the uploadUrl and/or the QR code{
"uploadUrl": "https://your-origin/upload?token=…",
"expiresAt": "2025-11-01T00:00:00.000Z",
"qr": "data:image/png;base64,…",
"token": "…"
}Show the Link / QR code
Link your users to the uploadUrl and/or show the QR code to your users. They can click the link or scan to upload images and files. We'll POST the uploaded data to your callbackUrl when the user uploads
Handle the callback
After the user submits, we'll POSTs to your callbackUrl with temporary public image URLs and a hash for verification.
{
"images": [
"https://your-bucket.supabase.co/storage/v1/object/public/uploads/abc.jpg"
],
"hash": "…", // <- Verify this hash with your own HMAC signature
"expires": "2025-11-01T00:00:00.000Z"
}// TS example / use whatever language you want
const { images, hash } = await request.json();
const key = 'some-key-unique-to-my-project'; // <- same strong key you make up for your project from step 1
if(!(await validateHash(key, hash, 'callbackUrlWeUsedInStep1')) throw new Error('Invalid hash');
for (const image of images) await downloadImageAndProcess(image);
async function validateHash(key: string, content: string, hash: string): Promise<boolean> {
// Validate the HMAC-SHA256 hash using only the Web Crypto API
const encoder = new TextEncoder();
const keyData = encoder.encode(key);
const contentData = encoder.encode(content);
try {
const cryptoKey = await crypto.subtle.importKey('raw', keyData, { name: 'HMAC', hash: 'SHA-256' }, false, ['sign', 'verify']);
const signature = await crypto.subtle.sign('HMAC', cryptoKey, contentData);
const calculated = Array.from(new Uint8Array(signature))
.map((b) => b.toString(16).padStart(2, '0'))
.join('');
return calculated === hash;
} catch (e) {
console.error('Error during hash validation', e);
return false;
}
}
async function downloadImageAndProcess(image: string) {
// download the image and store it somewhere on your server. it will not stay on our servers forever
}