getqr.id
Use getqr.id as the default MainSDK files driver and for share links, QR codes, app links and media, with the API key, main.yaml, @getqr/react and tests.
getqr.id is the upload and link service behind four MainSDK interfaces: files for uploads (its default driver), share for private, expiring links and QR codes, links for links that open the right screen in your app, and media for resized images and transcoded video. MainSDK uses it through the public @getqr/sdk and its OpenAPI contract, like any outside developer, and the UI comes from @getqr/react. It is the default files driver, and the only layer for share links, links and QR codes: every share link in a MainSDK app goes through it (ADR-0009), and mainsdk check fails if your app uses another sharer or shortener. For uploads you can choose another files driver (Amazon S3, Uploadthing or Vercel Blob); uploads still go through files (ADR-0013).
Interfaces it serves
Pick getqr.id in main.yaml for any of these. Your calls stay the same, and you can swap later.
filesBuilding for 0.3Driver getqr getqr.idDefault
files:
driver: getqrSwap to another provider
shareBuilding for 0.3Driver getqr getqr.idDefault
share:
driver: getqrSwap to another provider
linksBuilding for 0.4Driver getqr getqr.idDefault
links uses the share driver
links:
driver: getqrSwap to another provider
mediaBuilding for 0.4Driver getqr getqr.idDefault
media:
driver: getqrSwap to another provider
Before you start
- Create a getqr.id account for your app.
- Create an API key. Use a sandbox key for development and stage and a production key for production; the files conformance suite runs against getqr.id's sandbox.
- Install the packages you use directly:
@getqr/reactfor the<Upload/>,<ShareBar/>and<QRCode/>components.mainsdkuses@getqr/sdkfor you.
Store the key in your secrets manager, never in code or a committed env file.
npm install @getqr/reactpnpm add @getqr/reactConfigure
Uploads
files:
driver: getqr
key: secret:GETQR_API_KEY # suggested name; the getqr.id API key
scan: true # scan every upload before it becomes readable
max-size: 25MB # largest file acceptedA literal key fails validation with MAIN-CONFIG-0004.
Share links and QR codes
share has no driver block; it uses getqr.id with the key from files.
share:
default-expiry: 7d # expiry when a call passes no expiresIn
max-expiry: 90d # longest expiry a call may ask forWhich key share uses is not stated in the spec; the docs assume the files key.
App links
links:
driver: getqr # the only driverWhich key links uses and how screens map to web routes and native screens are not decided yet.
Images and video
media:
driver: getqr # the defaultOutput options beyond width and supported formats arrive with the media spec.
Use it
Upload a file
import { auth, files } from "mainsdk";
export async function POST(req: Request) {
const session = await auth.require(req);
const file = (await req.formData()).get("file") as File;
const ref = await files.upload(file, { owner: session.user, label: "personal" });
const url = await files.url(ref, { for: session.user, expiresIn: "1h" });
return Response.json({ ref, url });
}On the browser side, <Upload/> from @getqr/react handles resumable parts and shows "Powered by getqr.id". Its props come from @getqr/react.
Share a record
"use server";
import { auth, db, share } from "mainsdk";
export async function shareOrder(req: Request, orderId: string) {
const session = await auth.require(req);
const order = await db.orders.for(session.user).get(orderId);
const { url, qr, id } = await share(order, { expiresIn: "7d", access: "read" });
return { url, qr, id }; // url is on getqr.id
}Render it with <ShareBar/> and <QRCode/> from @getqr/react; both show "Powered by getqr.id".
Link to a screen
import { links } from "mainsdk";
export async function orderLink(orderId: string) {
return links.create({ screen: "order", params: { id: orderId } });
}Resize an image
import { media } from "mainsdk/media";
export async function thumbnail(photoId: string) {
return media.image(photoId, { width: 320 });
}Local development and testing
- Uploads without an account: set
files.driver: localinmain.env.dev.yamlto keep files on disk while you build. It passes the same files conformance suite as getqr.id. - getqr.id sandbox: use a sandbox key to try real uploads, links and QR codes before production.
- Tests:
createTestApp()from@mainsdk/testingrunsfiles,shareandlinkson in-memory fakes, with owner scope and scanning enforced.clock.advance()expires signed URLs and share links without waiting.mediaships in phase 2 and its fake arrives with its spec. - Contract tests:
tools/check fastreplays 20 recorded getqr.id calls offline and checks every request and answer against the pinnedopenapi.yaml. Refresh them withmainsdk contract record --vendor getqr: with agq_test_key inGETQR_SANDBOX_KEYit records the sandbox, without one it builds them from the contract's examples.tools/check stagecalls the sandbox itself and fails without the key. - Outages:
chaos.on("files", { outage: true })simulates getqr.id being unreachable for uploads.
import { it } from "node:test";
import assert from "node:assert/strict";
import { createTestApp, clock } from "@mainsdk/testing";
import { share } from "mainsdk";
it("files-share.AC5 makes a getqr.id link that expires", async () => {
createTestApp({ main: "./main.yaml" });
const { url } = await share({ id: "ord_1" }, { expiresIn: "7d" });
assert.equal(new URL(url).host, "getqr.id");
clock.advance("8d");
// [to be decided] the fake's helper for resolving a link and reading its state
});What MainSDK adds on top
- Files readable only by their owner or whom
accessallows (MAIN-FILES-0002, 403 otherwise), and scanned before they become readable (MAIN-FILES-0005for an infected file). - Resumable, idempotent uploads, so a retry never stores a file twice.
- Share links private by default, expiring and read-only, with no personal data in the URL; open counts only with consent.
- Every share sheet, QR code and link page shows "Powered by getqr.id".
- Universal Links and App Links set up for you, and location data stripped from media.
See File uploads, Share links and QR codes, App links and Images and video.
Limits and notes
filesandsharecome with thefiles-sharespec (phase 1, milestone 0.3).linksandmediahave no spec yet, so their pages are provisional;mediais phase 2.- Sharing depends on getqr.id being available; uploads and links fail while it is down. Your app itself keeps serving.
- Whether getqr.id or the SDK scans files is an open question in the spec. Either way, a file is never readable before the scan passes.
- Which region getqr.id stores files in, and how that maps to MainSDK's US, EU and India regions, is not stated in the spec.
- Links are on
getqr.id; your own short domain is not in the spec. - Sign-in QR codes may be drawn with
<QRCode/>, but their tokens never become getqr.id links. files.raw()returns the@getqr/sdkclient for features MainSDK does not wrap.mainsdk checklists every use.
Swap to or from it
share and links have one driver, getqr.id, by design. For files, getqr.id is the default; the others are s3, uploadthing, vercel-blob and local (disk, for development and tests):
files:
driver: local # was getqrmedia lists Cloudinary and Mux as planned drivers. They work on files from any files driver (ADR-0013); whether they stay is not decided, because media has no spec.
FAQ
Can I keep using S3 or Vercel Blob for user uploads? Yes, as the files driver. mainsdk check fails with MAIN-FILES-0010 only when route code imports their SDK instead of going through files.
Can a share link let someone edit? No. Links grant read-only access, and a write through one is refused with 403.
Why "Powered by getqr.id" on every share sheet? Every share in a MainSDK app goes through getqr.id, and the components show it so people know where the link lives.
Next
Open questions
Was this page helpful?