One call, not three
Direct-to-S3 upload is really create → PUT → complete.
upload() hides all three behind
a single await, with progress.
Everything Qrati Connect's widget does, called directly instead of embedded — you own the UI. Uploads are live today; gallery, curation, and the rest of the platform are shipping the same way. See the roadmap →
import { createQrati } from '@qratilabs/qrati-sdk';
// runs in the browser — real byte-level progress via XHR
const qrati = createQrati(API_KEY, { uid, fname, lname });
const { contentId } = await qrati.upload({
eventId,
file, // from your own drop zone
onProgress: ({ percent }) => setProgress(percent),
});
import { createQrati } from '@qratilabs/qrati-sdk';
// same package, no separate build — runs on your backend too
const qrati = createQrati(process.env.QRATI_API_KEY);
const file = new File([buffer], 'photo.jpg', { type: 'image/jpeg' });
const { contentId } = await qrati.upload({ eventId, file, identity: { uid } });
No shadow DOM, no bundled framework, no styles to override. Just functions that return promises.
Direct-to-S3 upload is really create → PUT → complete.
upload() hides all three behind
a single await, with progress.
Plain async functions, one package — a React effect, a Solid resource, a Svelte store, vanilla JS, or a Node backend job. No separate server build. See Browser & server.
One key per organization, safe to ship in your frontend bundle. Security comes from your domain allowlist — the same model your embedded widget already trusts.
Byte-level progress in the browser via XHR, with a consistent callback whether you're running client-side or on the server.
Every request and response is a typed interface. Your editor tells you what a call needs before you hit the docs.
Want manual control? uploads.create/complete/fail/abort
map 1:1 to the underlying API.
Add the package to your project.
pnpm add @qratilabs/qrati-sdk
Your org's API key, plus the end-user acting through your UI.
const qrati = createQrati(API_KEY, { uid, fname, lname });
Hand it a file from your own drop zone, form, or file picker.
const { contentId } = await qrati.upload({ eventId, file });
Qrati Connect's widget does more than upload. The SDK is working through that same surface — headless, same operations, no widget.
upload()
Getting started, the identity model, API-key security, and a full generated API reference.
Go to docs →