QR-based mobile uploader

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

01

Get URL

Fetch our endpoint and get a unique URL (and QR code)
02

Show Link / QR code

Show the Code or link to your users
03

User scans & uploads

Mobile user picks images and submits
04

Webhook callback

Image URLs are POSTed to your callback endpoint
Step 1

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

JS server-side Only / Use whatever language you want
//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
response
{
  "uploadUrl": "https://your-origin/upload?token=…",
  "expiresAt": "2025-11-01T00:00:00.000Z",
  "qr":        "data:image/png;base64,…",
  "token":     "…"
}
Step 2

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

Step 4

Handle the callback

After the user submits, we'll POSTs to your callbackUrl with temporary public image URLs and a hash for verification.

JSON - POST to your callbackUrl
{
  "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"
}
Server-side processing
// 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
}