Every feature, explained precisely
A QR code is normally public the moment it exists. QR Agent changes that: each code holds an encrypted payload only an authorized viewer can open. Here is how each layer of that guarantee works.
// 01 · ENCRYPTION
Envelope encryption with per-tenant keys
Every QR payload is encrypted with AES-256-GCM. The encryption follows a three-key hierarchy: a KMS master key wraps a per-tenant data encryption key (DEK), which in turn seals each payload. No single key exposure compromises another tenant.
Each ciphertext binds the QR record ID and tenant ID as GCM additional authenticated data (AAD). A ciphertext moved to a different record or a different tenant will not decrypt — the authentication tag fails. There is no way to relocate an encrypted payload.
Decrypted DEKs are held in process memory only and never written to disk, cache, or the database. A full database or Redis dump yields only wrapped keys and ciphertext — neither is useful without the KMS.
AES-256-GCM per payload
Industry-standard authenticated encryption. Each payload gets a unique 96-bit nonce. The authentication tag detects any tampering with the ciphertext.
Three-layer key hierarchy
KMS master key wraps the tenant DEK; the DEK wraps the payload. Rotating any layer invalidates nothing above it — the hierarchy is designed for safe, incremental rotation.
DEK in RAM only
The plaintext DEK lives only in process memory. On a cache miss the server re-unwraps from KMS. No persistent store ever holds the plaintext key.
AAD-bound ciphertexts
qr_id and tenant_id are bound into the GCM AAD. A ciphertext extracted from one record and inserted into another will fail authentication. Cross-record replay is structurally impossible.
// 02 · ACCESS GATES
Stateful, revocable access gates
A QR code reveals nothing to a scanner until the gate passes. Five gate modes are supported, and a code can accept more than one of them at once.
Link lifecycle controls
Expiry
Every access link has a configurable TTL (default 24 hours, max 30 days). Expired links return a closed gate, not a 404.
Max uses
Optionally cap the number of times a link can be consumed. Single-use, 5-use, or unlimited — your choice per link.
Revocation
Any link can be revoked instantly from the dashboard or API. The access_links row is marked revoked; all subsequent requests to that link are blocked.
Re-issuance
Issue a replacement link without disrupting other active links on the same QR. Each QR supports up to its plan limit of concurrent active links.
// 03 · TENANCY
Hard multi-tenant isolation
Every tenant-scoped table carries a tenant_id column. Row-level security (RLS) policies on PostgreSQL enforce that queries can only return rows belonging to the active tenant — even if application logic were to omit a WHERE clause, the database layer would catch it.
The cryptographic isolation layer doubles this: each tenant has a distinct DEK. A ciphertext belonging to Tenant A will fail to decrypt under Tenant B's key. The system has smoke tests asserting this invariant on every build.
There is no shared key material between tenants at any layer. Even if an attacker obtained the wrapped DEK for tenant B, they could not use it to access tenant A's data.
Row-level security
PostgreSQL RLS policies added as defense-in-depth. Application-level tenant_id filters are primary; RLS is the safety net that catches bypass attempts.
One DEK per tenant
Each tenant's data is encrypted under its own DEK. Key compromise for one tenant does not affect any other. DEKs are wrapped independently by the master KMS key.
Cross-tenant smoke tests
The test suite includes a cross-tenant isolation test: encrypt under tenant A, attempt to decrypt under tenant B, assert failure. This test runs on every CI build.
Session-bound tenant context
The server resolves tenant_id from the httpOnly session cookie on every request. tenant_id is never placed in a client-readable token or query parameter.
// 04 · ACCESS CONTROL
Role-based access control
Four roles govern what each team member can do within a tenant. Permissions are enforced server-side on every request; the UI reflects what the session user is allowed to see, but removal of UI controls is not the security boundary — the API is.
Permission enforcement model
Roles are resolved from the server session on every request. A user whose role has been downgraded or whose session has been revoked is blocked on the next API call, not only on the next login. There is no client-side capability token that can outlive a server-side revocation.
// 05 · ANALYTICS
Scan analytics without tracking your viewers
Every scan event is recorded with the time, outcome, gate type used, and basic device signals. IP addresses are hashed using an HMAC with a keyed secret — not plain SHA-256, which is reversible over the IPv4 address space. The hash lets you count unique IPs without storing a reversible address.
Advanced analytics (Pro and above) adds geographic region, device class, and referrer-source breakdowns. These are derived from the request at scan time and stored as categorical labels, not raw values.
Scan count and trend
Per-QR scan counts with time-series data. Spot usage patterns, track link expiry impact, and set scan limits on individual QR codes.
Gate outcome tracking
Every scan records whether the gate passed or failed and which gate type was used. Identify misconfigured links or expired access before your users notice.
HMAC-hashed IPs
Viewer IP addresses are stored as HMAC digests keyed to your tenant. Count unique visitors without reversible PII in your data store.
Advanced breakdown (Pro+)
Geographic region, device class (mobile/desktop/tablet), and referrer source. Stored as categorical labels derived at scan time — no raw user-agent strings retained.
// 06 · AUDIT
Immutable audit log
Every action that changes data — QR creation, payload update, link issuance, revocation, member invite, role change — writes an append-only audit event with the actor, timestamp, and affected resource. Audit events are never modified or deleted.
// 07 · RETAIL PACKAGING
GS1 Digital Link, ready for Sunrise 2027
From 2027 retailers expect the barcode on a pack to be a QR code carrying a GS1 Digital Link, so one symbol serves the till, the shopper and the regulator. A Product (GS1) code encodes https://your-domain/01/<GTIN>, with the batch and serial numbers appended when you set them, and resolves through the same path as every other code here.
A retail code is public by design -- a shopper holding a bottle in a shop cannot be asked to sign in. Encryption at rest, tenant isolation and the destination checks are unchanged; only the gate is dropped, and the URI reveals nothing that is not already printed in plain digits on the same pack.
// 08 · MACHINE SURFACE
An agent can run your codes without ever reading them
The same authorization that guards the dashboard guards every machine caller. An MCP tool call does not reach a second implementation — it dispatches through the published API, so scopes, tenant isolation, rate limits, idempotency and the audit trail are inherited rather than reimplemented.
Reading a payload is its own permission and is deliberately outside the older read/write pair, so a key that can list your codes cannot open them until you say so. Grant it and every read writes an audit row naming the credential, reads are capped per credential per hour, and a payload that has entered a model's context has left our controls.
// 09 · DISTRIBUTION
Getting codes to people, and people's codes to you
Three capabilities sit around the edge of the product. Each is described here with the part that is running and the part that is not, because a feature page that hides a ceiling is how a buyer discovers it after signing.
Apple and Google Wallet passes
A contact card, an event or a hosted page can be issued as a wallet pass instead of a printed code, so it lives in the phone that will present it. The pass carries the gate URL and never the payload — a wallet is a place a screenshot happens, and the content stays behind the gate where it is revocable.
Where it stops today
Both code paths are built and tested, including signature verification against a throwaway issuing certificate. Real passes need an Apple Pass Type ID certificate and a Google Wallet issuer key, which are not in place yet: until they are, the pass endpoints answer with a clear refusal rather than an unsigned file no device would install.
Your own domain on the printed code
A workspace can claim a hostname, prove it with a DNS TXT record, and have its codes resolve there. Tenant scoping is enforced at the point the hostname is matched, not layered on afterwards, so a code claimed by one workspace cannot be resolved through another's domain.
Where it stops today
Claim, proof and resolution are live and covered by cross-tenant refusal tests. Certificate issuance for a customer hostname waits on production infrastructure, so a claimed domain serves over plain HTTP today. It is not something to print on packaging yet.
Bring codes over from another tool
A CSV import maps your columns onto ours explicitly — no guessing at headers — and produces a continuity report that says, per code, whether the printed symbol keeps working or needs a reprint, grouped by the hostname it was printed with and exportable for the print shop.
Where it stops today
The mapping and the continuity report work with any export. Ready-made presets for specific competitors are not built: a preset guessed from documentation rather than a real export silently mis-imports, which is worse than mapping the columns once by hand.
// SUMMARY
Capability overview
| Capability | What it does | Available from |
|---|---|---|
| Envelope encryption | AES-256-GCM per payload, per-tenant DEK, KMS master key | All plans |
| Auth gate | Session-based access for logged-in, authorized users | All plans |
| Magic link gate | Stateful, expiring, revocable opaque access links | All plans |
| PIN gate | Per-QR passphrase, combinable with link gate | All plans |
| Scan analytics | Scan count, trend, gate outcome per QR | All plans |
| Advanced analytics | Geo region, device class, referrer source | Pro |
| Team seats | Invite team members, assign roles | Pro (5 seats) |
| API access | Headless QR creation and management via REST API | Pro |
| Custom branding | Replace the default QR frame with your brand | Pro |
| Row-level security | PostgreSQL RLS as cryptographic isolation defense-in-depth | All plans |
| Audit log | Append-only event trail for all data mutations | All plans |
| On-demand key rotation | Trigger DEK rotation outside the scheduled cadence | Business |
| GS1 Digital Link | Retail codes that resolve by GTIN, with batch and serial routing | All plans |
Ready to ship a private QR?
The Free tier includes full envelope encryption, all 5 access gates, and scan analytics — with no expiry and no card required.